From c90afbc363b62cd3ef384f01c1be0662945c7ab2 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Mon, 24 Mar 2025 12:07:46 -0500 Subject: [PATCH 01/55] updates --- .../.bicep/azureFilesDomainJoin.bicep | 52 +++++ .../.bicep/managementVm.bicep | 183 ++++++++++++++++++ .../modules/azureNetappFiles/deploy.bicep | 175 +++++++++++++++++ 3 files changed, 410 insertions(+) create mode 100644 workload/bicep/modules/azureNetappFiles/.bicep/azureFilesDomainJoin.bicep create mode 100644 workload/bicep/modules/azureNetappFiles/.bicep/managementVm.bicep create mode 100644 workload/bicep/modules/azureNetappFiles/deploy.bicep diff --git a/workload/bicep/modules/azureNetappFiles/.bicep/azureFilesDomainJoin.bicep b/workload/bicep/modules/azureNetappFiles/.bicep/azureFilesDomainJoin.bicep new file mode 100644 index 000000000..915a8f45b --- /dev/null +++ b/workload/bicep/modules/azureNetappFiles/.bicep/azureFilesDomainJoin.bicep @@ -0,0 +1,52 @@ +metadata name = 'AVD LZA storage' +metadata description = 'Configures domain join settings on storage account via VM custom script extension' +metadata owner = 'Azure/avdaccelerator' + +// ========== // +// Parameters // +// ========== // + +@sys.description('Virtual machine name.') +param virtualMachineName string + +@sys.description('Location where to deploy compute services.') +param location string + +@sys.description('Location for the AVD agent installation package.') +param baseScriptUri string + +param file string + +@sys.description('Arguments for domain join script.') +param scriptArguments string + +@secure() +@sys.description('Domain join user password.') +param adminUserPassword string + +@sys.description('Do not modify, used to set unique value for resource deployment.') +param time string = utcNow() + +// =========== // +// Deployments // +// =========== // + +// Add Azure Files to AD DS domain. +module dscStorageScript '../../../../../avm/1.0.0/res/compute/virtual-machine/extension/main.bicep' = { + name: 'VM-Ext-AVM-${time}' + params: { + name: 'AzureFilesDomainJoin' + virtualMachineName: virtualMachineName + location: location + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + autoUpgradeMinorVersion: true + enableAutomaticUpgrade: false + settings: {} + protectedSettings: { + fileUris: array(baseScriptUri) + commandToExecute: 'powershell -ExecutionPolicy Unrestricted -File ${file} ${scriptArguments} -AdminUserPassword ${adminUserPassword} -verbose' + } + } +} diff --git a/workload/bicep/modules/azureNetappFiles/.bicep/managementVm.bicep b/workload/bicep/modules/azureNetappFiles/.bicep/managementVm.bicep new file mode 100644 index 000000000..82179e075 --- /dev/null +++ b/workload/bicep/modules/azureNetappFiles/.bicep/managementVm.bicep @@ -0,0 +1,183 @@ +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // + +@sys.description('AVD disk encryption set resource ID to enable server side encyption.') +param diskEncryptionSetResourceId string + +@sys.description('AVD workload subscription ID, multiple subscriptions scenario.') +param workloadSubsId string + +@sys.description('Virtual machine time zone.') +param computeTimeZone string + +@sys.description('Required, The service providing domain services for Azure Virtual Desktop.') +param identityServiceProvider string + +@sys.description('Resource Group Name for Azure Files.') +param serviceObjectsRgName string + +@sys.description('AVD subnet ID.') +param subnetId string + +@sys.description('Enable accelerated networking on the session host VMs.') +param enableAcceleratedNetworking bool + +@sys.description('Specifies the securityType of the virtual machine. Must be TrustedLaunch or ConfidentialVM enable UefiSettings.') +param securityType string + +@sys.description('Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings.') +param secureBootEnabled bool + +@sys.description('Specifies whether virtual TPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings.') +param vTpmEnabled bool + +@sys.description('Location where to deploy compute services.') +param location string + +@sys.description('This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs.') +param encryptionAtHost bool + +@sys.description('Session host VM size.') +param mgmtVmSize string + +@sys.description('OS disk type for session host.') +param osDiskType string + +@sys.description('Market Place OS image') +param osImage object + +@sys.description('Storage Managed Identity Resource ID.') +param storageManagedIdentityResourceId string + +@sys.description('Local administrator username.') +param vmLocalUserName string + +@sys.description('Identity domain name.') +param identityDomainName string + +@sys.description('Keyvault name to get credentials from.') +param wrklKvName string + +@sys.description('AVD session host domain join credentials.') +param domainJoinUserName string + +@sys.description('OU path to join AVd VMs.') +param ouPath string + +@sys.description('Application Security Group (ASG) for the session hosts.') +param applicationSecurityGroupResourceId string + +@sys.description('Tags to be applied to resources') +param tags object + +@sys.description('Name for management virtual machine. for tools and to join Azure Files to domain.') +param managementVmName string + +@sys.description('Do not modify, used to set unique value for resource deployment.') +param time string = utcNow() + +// =========== // +// Variable declaration // +// =========== // + +var varManagedDisk = empty(diskEncryptionSetResourceId) ? { + storageAccountType: osDiskType +} : { + diskEncryptionSet: { + id: diskEncryptionSetResourceId + } + storageAccountType: osDiskType +} + +// =========== // +// Deployments // +// =========== // + +// Call on the KV. +resource avdWrklKeyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { + name: wrklKvName + scope: resourceGroup('${workloadSubsId}', '${serviceObjectsRgName}') +} + +// Provision temporary VM and add it to domain. +module managementVm '../../../../../avm/1.0.0/res/compute/virtual-machine/main.bicep' = { + scope: resourceGroup('${workloadSubsId}', '${serviceObjectsRgName}') + name: 'MGMT-VM-${time}' + params: { + name: managementVmName + location: location + timeZone: computeTimeZone + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + storageManagedIdentityResourceId + ] + } + encryptionAtHost: encryptionAtHost + zone: 0 + osType: 'Windows' + vmSize: mgmtVmSize + securityType: securityType + secureBootEnabled: secureBootEnabled + vTpmEnabled: vTpmEnabled + imageReference: osImage + osDisk: { + createOption: 'FromImage' + deleteOption: 'Delete' + caching: 'ReadWrite' + managedDisk: varManagedDisk + } + adminUsername: vmLocalUserName + adminPassword: avdWrklKeyVaultget.getSecret('vmLocalUserPassword') + nicConfigurations: [ + { + name: 'nic-01-${managementVmName}' + deleteOption: 'Delete' + enableAcceleratedNetworking: enableAcceleratedNetworking + ipConfigurations: !empty(applicationSecurityGroupResourceId) ? [ + { + name: 'ipconfig01' + subnetResourceId: subnetId + applicationSecurityGroups: [ + { + id: applicationSecurityGroupResourceId + } + ] + } + ] : [ + { + name: 'ipconfig01' + subnetResourceId: subnetId + } + ] + } + ] + // Join domain + allowExtensionOperations: true + extensionDomainJoinPassword: avdWrklKeyVaultget.getSecret('domainJoinUserPassword') + extensionDomainJoinConfig: { + enabled: (identityServiceProvider == 'EntraID') ? false: true + settings: { + name: identityDomainName + ouPath: !empty(ouPath) ? ouPath : null + user: domainJoinUserName + restart: 'true' + options: '3' + } + } + // Entra ID Join. + extensionAadJoinConfig: { + enabled: (identityServiceProvider == 'EntraID') ? true: false + } + tags: tags + } + dependsOn: [ + ] +} + +// =========== // +// Outputs // +// =========== // diff --git a/workload/bicep/modules/azureNetappFiles/deploy.bicep b/workload/bicep/modules/azureNetappFiles/deploy.bicep new file mode 100644 index 000000000..bb85d48f8 --- /dev/null +++ b/workload/bicep/modules/azureNetappFiles/deploy.bicep @@ -0,0 +1,175 @@ +metadata name = 'AVD LZA storage' +metadata description = 'This module deploys ANF account, capacity pool and volumes' +metadata owner = 'Azure/avdaccelerator' + +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // + +@sys.description('Workload subscription ID') +param subId string + +@sys.description('Resource Group Name where to deploy Azure NetApp Files.') +param storageObjectsRgName string + +// @sys.description('Required, The service providing domain services for Azure Virtual Desktop.') +// param identityServiceProvider string + +@sys.description('ANF account name.') +param anfAccountName string + +@sys.description('Capacity pool volume name.') +param anfCapacityPoolName string + +@sys.description('ANF volume name.') +param anfVolumeName string + +@sys.description('ANF subnet ID.') +param anfSubnetId string + +@sys.description('DNS servers IPs.') +param dnsServers string + +@sys.description('Location where to deploy resources.') +param location string + +@sys.description('Identity domain name.') +param identityDomainName string + +@sys.description('Keyvault resource ID to get credentials from.') +param kvResourceId string + +@sys.description('AVD session host domain join credentials.') +param domainJoinUserName string + +// @sys.description('AVD session host local admin credentials.') +// param vmLocalUserName string + +@sys.description('ANF performance tier.') +param anfPerformance string + +@sys.description('ANF capacity pool size in TiBs.') +param capacityPoolSize int = 4 + +@sys.description('ANF volume quota size in GiBs.') +param volumeSize int + +// @sys.description('Script name for adding storage account to Active Directory.') +// param storageToDomainScript string + +// @sys.description('URI for the script for adding the storage account to Active Directory.') +// param storageToDomainScriptUri string + +@sys.description('Tags to be applied to resources') +param tags object = {} + +// @sys.description('Name for management virtual machine. for tools and to join Azure Files to domain.') +// param managementVmName string + +@sys.description('Do not modify, used to set unique value for resource deployment.') +param time string = utcNow() + +@sys.description('Sets purpose of the storage account.') +param storagePurpose string + +//parameters for domain join +// @sys.description('Sets location of DSC Agent.') +// param dscAgentPackageLocation string + +// @sys.description('Custom OU path for storage.') +// param storageCustomOuPath string + +@sys.description('OU Storage Path') +param ouStgPath string = '' + +// @sys.description('Managed Identity Client ID') +// param managedIdentityClientId string + +// @sys.description('storage account FDQN.') +// param storageAccountFqdn string + +// =========== // +// Variable declaration // +// =========== // +// var varAzureCloudName = environment().name +// var varAdminUserName = (identityServiceProvider == 'EntraID') ? vmLocalUserName : domainJoinUserName +//var varStorageToDomainScriptArgs = '-DscPath ${dscAgentPackageLocation} -StorageAccountName ${storageAccountName} -StorageAccountRG ${storageObjectsRgName} -StoragePurpose ${storagePurpose} -DomainName ${identityDomainName} -IdentityServiceProvider ${identityServiceProvider} -AzureCloudEnvironment ${varAzureCloudName} -SubscriptionId ${workloadSubsId} -AdminUserName ${varAdminUserName} -CustomOuPath ${storageCustomOuPath} -OUName ${ouStgPath} -ShareName ${fileShareName} -ClientId ${managedIdentityClientId} -SecurityPrincipalName "${varSecurityPrincipalName}" -StorageAccountFqdn ${storageAccountFqdn} ' +var varKvSubId = split(kvResourceId, '/')[2] +var varKvRgName = split(kvResourceId, '/')[4] +var varKvName = split(kvResourceId, '/')[8] + + +// =========== // +// Deployments // +// =========== // + +// Call on the KV. +resource keyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { + name: varKvName + scope: resourceGroup('${varKvSubId}', '${varKvRgName}') +} + +// Provision the Azure NetApp Files. +module azureNetAppFiles '../../../../avm/1.1.0/res/net-app/net-app-account/main.bicep' = { + scope: resourceGroup('${subId}', '${storageObjectsRgName}') + name: 'Storage-${storagePurpose}-${time}' + params: { + name: anfAccountName + adName: anfAccountName + domainName: identityDomainName + domainJoinUser: domainJoinUserName + domainJoinPassword: keyVaultget.getSecret('domainJoinUserPassword') + domainJoinOU: ouStgPath + dnsServers: dnsServers + smbServerNamePrefix: anfAccountName + location: location + // aesEncryption: ************* + // customerManagedKey: ************* + capacityPools:[ + { + name: anfCapacityPoolName + serviceLevel: anfPerformance + size: capacityPoolSize * 1099511627776 // Convert TiBs to bytes + encryptionType: 'Single' + volumes: [ + { + name: anfVolumeName + coolAccess: false + encryptionKeySource: 'Microsoft.NetApp' + zones: [] + serviceLevel: anfPerformance + networkFeatures: 'Standard' + usageThreshold: volumeSize * 1073741824 // Convert GiBs to bytes + protocolTypes: [ + 'CIFS' + ] + subnetResourceId: anfSubnetId + creationToken: anfVolumeName + smbContinuouslyAvailable: true + securityStyle: 'ntfs' + } + ] + } + ] + tags: tags + } +} + +// Custom Extension call in on the DSC script to set NTFS permissions. +module addShareToDomainScript './.bicep/azureFilesDomainJoin.bicep' = { + scope: resourceGroup('${workloadSubsId}', '${serviceObjectsRgName}') + name: 'Add-${storagePurpose}-Storage-Setup-${time}' + params: { + location: location + virtualMachineName: managementVmName + file: storageToDomainScript + scriptArguments: varStorageToDomainScriptArgs + adminUserPassword: (identityServiceProvider == 'EntraID') ? avdWrklKeyVaultget.getSecret('vmLocalUserPassword') : + baseScriptUri: storageToDomainScriptUri + } + dependsOn: [ + storageAndFile + ] +} From f05580f445d1d625ad4dd4772be834af71126da5 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Mon, 24 Mar 2025 12:35:24 -0500 Subject: [PATCH 02/55] updates --- .../authorization/policy-assignment/README.md | 1424 ++++ .../policy-assignment/main.bicep | 204 + .../authorization/policy-assignment/main.json | 1492 ++++ ...t-group-additional-rbac-asi-def-loop.bicep | 29 + ...management-group-additional-rbac-asi.bicep | 23 + .../modules/management-group.bicep | 152 + ...e-group-additional-rbac-asi-def-loop.bicep | 29 + .../resource-group-additional-rbac-asi.bicep | 21 + .../modules/resource-group.bicep | 123 + ...ription-additional-rbac-asi-def-loop.bicep | 29 + .../subscription-additional-rbac-asi.bicep | 23 + .../modules/subscription.bicep | 117 + .../tests/e2e/mg.defaults/main.test.bicep | 33 + .../tests/e2e/mg.max/main.test.bicep | 127 + .../tests/e2e/rg.defaults/main.test.bicep | 57 + .../tests/e2e/rg.max/dependencies.bicep | 33 + .../tests/e2e/rg.max/main.test.bicep | 130 + .../tests/e2e/sub.defaults/main.test.bicep | 39 + .../tests/e2e/sub.max/dependencies.bicep | 13 + .../tests/e2e/sub.max/main.test.bicep | 128 + .../policy-assignment/version.json | 7 + .../authorization/policy-exemption/README.md | 933 +++ .../authorization/policy-exemption/main.bicep | 149 + .../authorization/policy-exemption/main.json | 706 ++ .../modules/management-group.bicep | 67 + .../modules/resource-group.bicep | 67 + .../modules/subscription.bicep | 67 + .../tests/e2e/mg.defaults/main.test.bicep | 53 + .../tests/e2e/mg.max/main.test.bicep | 82 + .../tests/e2e/rg.defaults/main.test.bicep | 72 + .../tests/e2e/rg.max/main.test.bicep | 98 + .../tests/e2e/sub.defaults/main.test.bicep | 57 + .../tests/e2e/sub.max/main.test.bicep | 85 + .../policy-exemption/version.json | 7 + .../resource-role-assignment/README.md | 289 + .../resource-role-assignment/main.bicep | 108 + .../resource-role-assignment/main.json | 218 + .../modules/generic-role-assignment.json | 56 + .../tests/e2e/all/dependencies.bicep | 28 + .../tests/e2e/all/main.test.bicep | 61 + .../tests/e2e/defaults/dependencies.bicep | 28 + .../tests/e2e/defaults/main.test.bicep | 59 + .../resource-role-assignment/version.json | 7 + .../authorization/role-assignment/README.md | 673 ++ .../authorization/role-assignment/main.bicep | 144 + .../authorization/role-assignment/main.json | 662 ++ .../modules/management-group.bicep | 87 + .../modules/resource-group.bicep | 85 + .../modules/subscription.bicep | 82 + .../tests/e2e/mg.defaults/dependencies.bicep | 13 + .../tests/e2e/mg.defaults/main.test.bicep | 64 + .../tests/e2e/mg.max/dependencies.bicep | 13 + .../tests/e2e/mg.max/main.test.bicep | 66 + .../tests/e2e/rg.default/dependencies.bicep | 13 + .../tests/e2e/rg.default/main.test.bicep | 65 + .../tests/e2e/rg.max/dependencies.bicep | 13 + .../tests/e2e/rg.max/main.test.bicep | 67 + .../tests/e2e/sub.default/dependencies.bicep | 13 + .../tests/e2e/sub.default/main.test.bicep | 69 + .../tests/e2e/sub.max/dependencies.bicep | 13 + .../tests/e2e/sub.max/main.test.bicep | 66 + .../role-assignment/version.json | 7 + .../authorization/role-definition/README.md | 302 + .../authorization/role-definition/main.bicep | 98 + .../authorization/role-definition/main.json | 150 + .../tests/e2e/mg.default/main.test.bicep | 31 + ...ubscription_owner.alz_role_definition.json | 27 + .../tests/e2e/mg.loadJson/main.test.bicep | 36 + .../role-definition/version.json | 7 + .../ptn/policy-insights/remediation/README.md | 734 ++ .../policy-insights/remediation/main.bicep | 152 + .../ptn/policy-insights/remediation/main.json | 674 ++ .../modules/management-group.bicep | 72 + .../remediation/modules/resource-group.bicep | 80 + .../remediation/modules/subscription.bicep | 80 + .../tests/e2e/mg.defaults/main.test.bicep | 49 + .../tests/e2e/mg.max/main.test.bicep | 53 + .../tests/e2e/rg.defaults/main.test.bicep | 63 + .../tests/e2e/rg.max/main.test.bicep | 68 + .../tests/e2e/sub.defaults/main.test.bicep | 52 + .../tests/e2e/sub.max/main.test.bicep | 57 + .../policy-insights/remediation/version.json | 7 + .../automation/automation-account/README.md | 2721 +++++++ .../automation-account/credential/README.md | 80 + .../automation-account/credential/main.bicep | 41 + .../automation-account/credential/main.json | 88 + .../automation-account/job-schedule/README.md | 96 + .../job-schedule/main.bicep | 50 + .../automation-account/job-schedule/main.json | 94 + .../automation/automation-account/main.bicep | 564 ++ .../automation/automation-account/main.json | 3570 +++++++++ .../automation-account/module/README.md | 91 + .../automation-account/module/main.bicep | 49 + .../automation-account/module/main.json | 106 + .../modules/linked-service.bicep | 40 + .../automation-account/runbook/README.md | 154 + .../automation-account/runbook/main.bicep | 101 + .../automation-account/runbook/main.json | 169 + .../automation-account/schedule/README.md | 144 + .../automation-account/schedule/main.bicep | 72 + .../automation-account/schedule/main.json | 133 + .../software-update-configuration/README.md | 459 ++ .../software-update-configuration/main.bicep | 269 + .../software-update-configuration/main.json | 417 + .../tests/e2e/defaults/main.test.bicep | 48 + .../tests/e2e/encr/dependencies.bicep | 61 + .../tests/e2e/encr/main.test.bicep | 75 + .../tests/e2e/max/dependencies.bicep | 81 + .../tests/e2e/max/main.test.bicep | 314 + .../tests/e2e/waf-aligned/dependencies.bicep | 63 + .../tests/e2e/waf-aligned/main.test.bicep | 260 + .../automation-account/variable/README.md | 82 + .../automation-account/variable/main.bicep | 41 + .../automation-account/variable/main.json | 82 + .../automation-account/version.json | 7 + .../res/compute/availability-set/README.md | 594 ++ .../res/compute/availability-set/main.bicep | 187 + .../res/compute/availability-set/main.json | 306 + .../tests/e2e/defaults/main.test.bicep | 48 + .../tests/e2e/max/dependencies.bicep | 24 + .../tests/e2e/max/main.test.bicep | 90 + .../tests/e2e/waf-aligned/dependencies.bicep | 13 + .../tests/e2e/waf-aligned/main.test.bicep | 67 + .../res/compute/availability-set/version.json | 7 + .../res/compute/disk-encryption-set/README.md | 862 +++ .../compute/disk-encryption-set/main.bicep | 271 + .../res/compute/disk-encryption-set/main.json | 745 ++ .../key-vault.vault.access-policy.bicep | 119 + .../modules/nested_keyVaultPermissions.bicep | 66 + .../e2e/accessPolicies/dependencies.bicep | 51 + .../tests/e2e/accessPolicies/main.test.bicep | 98 + .../tests/e2e/defaults/dependencies.bicep | 37 + .../tests/e2e/defaults/main.test.bicep | 66 + .../tests/e2e/max/dependencies.bicep | 51 + .../tests/e2e/max/main.test.bicep | 103 + .../tests/e2e/waf-aligned/dependencies.bicep | 48 + .../tests/e2e/waf-aligned/main.test.bicep | 77 + .../compute/disk-encryption-set/version.json | 7 + avm/1.1.0/res/compute/disk/README.md | 1118 +++ avm/1.1.0/res/compute/disk/main.bicep | 335 + avm/1.1.0/res/compute/disk/main.json | 519 ++ .../disk/tests/e2e/defaults/main.test.bicep | 50 + .../disk/tests/e2e/image/dependencies.bicep | 13 + .../disk/tests/e2e/image/main.test.bicep | 60 + .../disk/tests/e2e/import/dependencies.bicep | 152 + .../tests/e2e/import/dependencies_rbac.bicep | 19 + .../disk/tests/e2e/import/main.test.bicep | 68 + .../disk/tests/e2e/max/dependencies.bicep | 13 + .../disk/tests/e2e/max/main.test.bicep | 95 + .../tests/e2e/waf-aligned/main.test.bicep | 64 + avm/1.1.0/res/compute/disk/version.json | 7 + avm/1.1.0/res/compute/gallery/README.md | 1830 +++++ .../res/compute/gallery/application/README.md | 454 ++ .../compute/gallery/application/main.bicep | 155 + .../res/compute/gallery/application/main.json | 356 + avm/1.1.0/res/compute/gallery/image/README.md | 521 ++ .../res/compute/gallery/image/main.bicep | 288 + avm/1.1.0/res/compute/gallery/image/main.json | 494 ++ avm/1.1.0/res/compute/gallery/main.bicep | 325 + avm/1.1.0/res/compute/gallery/main.json | 1762 +++++ .../tests/e2e/defaults/main.test.bicep | 48 + .../gallery/tests/e2e/max/dependencies.bicep | 13 + .../gallery/tests/e2e/max/main.test.bicep | 271 + .../tests/e2e/waf-aligned/dependencies.bicep | 13 + .../tests/e2e/waf-aligned/main.test.bicep | 71 + avm/1.1.0/res/compute/gallery/version.json | 7 + avm/1.1.0/res/compute/image/README.md | 739 ++ avm/1.1.0/res/compute/image/main.bicep | 197 + avm/1.1.0/res/compute/image/main.json | 364 + .../tests/e2e/defaults/dependencies.bicep | 154 + .../image/tests/e2e/defaults/main.test.bicep | 69 + .../image/tests/e2e/max/dependencies.bicep | 242 + .../image/tests/e2e/max/main.test.bicep | 103 + .../tests/e2e/waf-aligned/dependencies.bicep | 242 + .../tests/e2e/waf-aligned/main.test.bicep | 80 + avm/1.1.0/res/compute/image/version.json | 7 + .../proximity-placement-group/README.md | 682 ++ .../proximity-placement-group/main.bicep | 173 + .../proximity-placement-group/main.json | 304 + .../tests/e2e/defaults/main.test.bicep | 48 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 104 + .../tests/e2e/waf-aligned/main.test.bicep | 69 + .../proximity-placement-group/version.json | 7 + .../res/compute/ssh-public-key/README.md | 627 ++ .../res/compute/ssh-public-key/main.bicep | 156 + .../res/compute/ssh-public-key/main.json | 276 + .../tests/e2e/defaults/main.test.bicep | 43 + .../tests/e2e/max/dependencies.bicep | 64 + .../tests/e2e/max/main.test.bicep | 89 + .../tests/e2e/waf-aligned/dependencies.bicep | 64 + .../tests/e2e/waf-aligned/main.test.bicep | 88 + .../tests/unit/custom.tests.ps1 | 7 + .../res/compute/ssh-public-key/version.json | 7 + .../virtual-machine-scale-set/README.md | 3452 +++++++++ .../extension/README.md | 132 + .../extension/main.bicep | 65 + .../extension/main.json | 126 + .../virtual-machine-scale-set/main.bicep | 958 +++ .../virtual-machine-scale-set/main.json | 2523 ++++++ .../e2e/linux.defaults/dependencies.bicep | 89 + .../tests/e2e/linux.defaults/main.test.bicep | 106 + .../tests/e2e/linux.max/dependencies.bicep | 199 + .../tests/e2e/linux.max/main.test.bicep | 238 + .../tests/e2e/linux.ssecmk/dependencies.bicep | 154 + .../tests/e2e/linux.ssecmk/main.test.bicep | 131 + .../e2e/windows.defaults/dependencies.bicep | 30 + .../e2e/windows.defaults/main.test.bicep | 96 + .../tests/e2e/windows.max/dependencies.bicep | 161 + .../tests/e2e/windows.max/main.test.bicep | 234 + .../windows.waf-aligned/dependencies.bicep | 161 + .../e2e/windows.waf-aligned/main.test.bicep | 200 + .../virtual-machine-scale-set/version.json | 7 + .../res/compute/virtual-machine/README.md | 6745 +++++++++++++++++ .../virtual-machine/extension/README.md | 150 + .../virtual-machine/extension/main.bicep | 76 + .../virtual-machine/extension/main.json | 156 + .../res/compute/virtual-machine/main.bicep | 1169 +++ .../res/compute/virtual-machine/main.json | 5535 ++++++++++++++ .../modules/nic-configuration.bicep | 186 + .../modules/protected-item.bicep | 54 + .../tests/e2e/atmg/dependencies.bicep | 89 + .../tests/e2e/atmg/main.test.bicep | 113 + .../e2e/linux.defaults/dependencies.bicep | 89 + .../tests/e2e/linux.defaults/main.test.bicep | 107 + .../tests/e2e/linux.max/dependencies.bicep | 457 ++ .../tests/e2e/linux.max/main.test.bicep | 364 + .../tests/e2e/waf-aligned/dependencies.bicep | 469 ++ .../tests/e2e/waf-aligned/main.test.bicep | 354 + .../e2e/windows.SSDv2/dependencies.bicep | 30 + .../tests/e2e/windows.SSDv2/main.test.bicep | 101 + .../e2e/windows.defaults/dependencies.bicep | 30 + .../e2e/windows.defaults/main.test.bicep | 90 + .../dependencies.bicep | 30 + .../main.test.bicep | 123 + .../e2e/windows.hostpool/dependencies.bicep | 94 + .../e2e/windows.hostpool/main.test.bicep | 116 + .../tests/e2e/windows.max/dependencies.bicep | 446 ++ .../tests/e2e/windows.max/main.test.bicep | 393 + .../e2e/windows.nvidia/dependencies.bicep | 30 + .../tests/e2e/windows.nvidia/main.test.bicep | 93 + .../e2e/windows.ssecmk/dependencies.bicep | 95 + .../tests/e2e/windows.ssecmk/main.test.bicep | 109 + .../tests/e2e/windows.vmss/dependencies.bicep | 101 + .../tests/e2e/windows.vmss/main.test.bicep | 94 + .../tests/unit/avm.core.team.tests.ps1 | 35 + .../res/compute/virtual-machine/version.json | 7 + .../application-group/README.md | 870 +++ .../application-group/application/README.md | 134 + .../application-group/application/main.bicep | 65 + .../application-group/application/main.json | 126 + .../application-group/main.bicep | 266 + .../application-group/main.json | 628 ++ .../tests/e2e/defaults/dependencies.bicep | 18 + .../tests/e2e/defaults/main.test.bicep | 59 + .../tests/e2e/max/dependencies.bicep | 29 + .../tests/e2e/max/main.test.bicep | 140 + .../tests/e2e/waf-aligned/dependencies.bicep | 18 + .../tests/e2e/waf-aligned/main.test.bicep | 87 + .../application-group/version.json | 7 + .../host-pool/README.md | 1615 ++++ .../host-pool/main.bicep | 502 ++ .../host-pool/main.json | 1630 ++++ .../tests/e2e/defaults/main.test.bicep | 42 + .../tests/e2e/max/dependencies.bicep | 60 + .../host-pool/tests/e2e/max/main.test.bicep | 179 + .../tests/e2e/waf-aligned/main.test.bicep | 73 + .../host-pool/version.json | 7 + .../scaling-plan/README.md | 1164 +++ .../scaling-plan/main.bicep | 249 + .../scaling-plan/main.json | 475 ++ .../tests/e2e/defaults/main.test.bicep | 45 + .../tests/e2e/max/dependencies.bicep | 52 + .../tests/e2e/max/main.test.bicep | 230 + .../tests/e2e/waf-aligned/main.test.bicep | 75 + .../scaling-plan/version.json | 7 + .../workspace/README.md | 1431 ++++ .../workspace/main.bicep | 385 + .../workspace/main.json | 1438 ++++ .../tests/e2e/defaults/main.test.bicep | 45 + .../tests/e2e/max/dependencies.bicep | 60 + .../workspace/tests/e2e/max/main.test.bicep | 200 + .../tests/e2e/waf-aligned/main.test.bicep | 76 + .../workspace/version.json | 7 + avm/1.1.0/res/insights/action-group/README.md | 660 ++ .../res/insights/action-group/main.bicep | 146 + avm/1.1.0/res/insights/action-group/main.json | 324 + .../tests/e2e/defaults/main.test.bicep | 49 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 104 + .../tests/e2e/waf-aligned/dependencies.bicep | 13 + .../tests/e2e/waf-aligned/main.test.bicep | 63 + .../action-group/tests/unit/custom.tests.ps1 | 7 + .../res/insights/action-group/version.json | 7 + .../res/insights/activity-log-alert/README.md | 880 +++ .../insights/activity-log-alert/main.bicep | 131 + .../res/insights/activity-log-alert/main.json | 282 + .../tests/e2e/defaults/main.test.bicep | 78 + .../tests/e2e/max/dependencies.bicep | 28 + .../tests/e2e/max/main.test.bicep | 125 + .../tests/e2e/waf-aligned/dependencies.bicep | 14 + .../tests/e2e/waf-aligned/main.test.bicep | 101 + .../insights/activity-log-alert/version.json | 7 + avm/1.1.0/res/insights/component/README.md | 981 +++ .../component/linkedStorageAccounts/README.md | 51 + .../linkedStorageAccounts/main.bicep | 29 + .../component/linkedStorageAccounts/main.json | 60 + avm/1.1.0/res/insights/component/main.bicep | 255 + avm/1.1.0/res/insights/component/main.json | 688 ++ .../tests/e2e/defaults/dependencies.bicep | 13 + .../tests/e2e/defaults/main.test.bicep | 55 + .../tests/e2e/max/dependencies.bicep | 35 + .../component/tests/e2e/max/main.test.bicep | 121 + .../tests/e2e/waf-aligned/dependencies.bicep | 13 + .../tests/e2e/waf-aligned/main.test.bicep | 88 + avm/1.1.0/res/insights/component/version.json | 7 + .../data-collection-endpoint/README.md | 605 ++ .../data-collection-endpoint/main.bicep | 152 + .../data-collection-endpoint/main.json | 315 + .../tests/e2e/defaults/main.test.bicep | 47 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 90 + .../tests/e2e/waf-aligned/main.test.bicep | 54 + .../data-collection-endpoint/version.json | 7 + .../insights/data-collection-rule/README.md | 3036 ++++++++ .../insights/data-collection-rule/main.bicep | 263 + .../insights/data-collection-rule/main.json | 771 ++ .../modules/nested_conditionalScope.bicep | 55 + .../tests/e2e/agent-settings/main.test.bicep | 59 + .../tests/e2e/customadv/dependencies.bicep | 68 + .../tests/e2e/customadv/main.test.bicep | 140 + .../tests/e2e/custombasic/dependencies.bicep | 52 + .../tests/e2e/custombasic/main.test.bicep | 121 + .../tests/e2e/customiis/dependencies.bicep | 33 + .../tests/e2e/customiis/main.test.bicep | 100 + .../tests/e2e/defaults/main.test.bicep | 88 + .../tests/e2e/linux/dependencies.bicep | 16 + .../tests/e2e/linux/main.test.bicep | 212 + .../tests/e2e/max/dependencies.bicep | 66 + .../tests/e2e/max/main.test.bicep | 154 + .../tests/e2e/waf-aligned/dependencies.bicep | 16 + .../tests/e2e/waf-aligned/main.test.bicep | 167 + .../tests/e2e/windows/dependencies.bicep | 16 + .../tests/e2e/windows/main.test.bicep | 166 + .../data-collection-rule/version.json | 7 + .../res/insights/diagnostic-setting/README.md | 456 ++ .../insights/diagnostic-setting/main.bicep | 124 + .../res/insights/diagnostic-setting/main.json | 237 + .../tests/e2e/defaults/main.test.bicep | 62 + .../tests/e2e/max/main.test.bicep | 70 + .../tests/e2e/waf-aligned/main.test.bicep | 70 + .../insights/diagnostic-setting/version.json | 7 + avm/1.1.0/res/insights/metric-alert/README.md | 806 ++ .../res/insights/metric-alert/main.bicep | 204 + avm/1.1.0/res/insights/metric-alert/main.json | 415 + .../tests/e2e/defaults/dependencies.bicep | 78 + .../tests/e2e/defaults/main.test.bicep | 75 + .../tests/e2e/max/dependencies.bicep | 29 + .../tests/e2e/max/main.test.bicep | 105 + .../tests/e2e/waf-aligned/dependencies.bicep | 79 + .../tests/e2e/waf-aligned/main.test.bicep | 78 + .../res/insights/metric-alert/version.json | 7 + .../res/insights/private-link-scope/README.md | 1842 +++++ .../insights/private-link-scope/main.bicep | 313 + .../res/insights/private-link-scope/main.json | 1596 ++++ .../scoped-resource/README.md | 59 + .../scoped-resource/main.bicep | 34 + .../scoped-resource/main.json | 68 + .../tests/e2e/defaults/main.test.bicep | 48 + .../tests/e2e/max/dependencies.bicep | 71 + .../tests/e2e/max/main.test.bicep | 225 + .../tests/e2e/waf-aligned/dependencies.bicep | 60 + .../tests/e2e/waf-aligned/main.test.bicep | 179 + .../insights/private-link-scope/version.json | 7 + .../insights/scheduled-query-rule/README.md | 1011 +++ .../insights/scheduled-query-rule/main.bicep | 205 + .../insights/scheduled-query-rule/main.json | 363 + .../tests/e2e/defaults/dependencies.bicep | 13 + .../tests/e2e/defaults/main.test.bicep | 89 + .../tests/e2e/max/dependencies.bicep | 24 + .../tests/e2e/max/main.test.bicep | 126 + .../tests/e2e/waf-aligned/dependencies.bicep | 13 + .../tests/e2e/waf-aligned/main.test.bicep | 98 + .../scheduled-query-rule/version.json | 7 + avm/1.1.0/res/insights/webtest/README.md | 789 ++ avm/1.1.0/res/insights/webtest/main.bicep | 189 + avm/1.1.0/res/insights/webtest/main.json | 404 + .../tests/e2e/defaults/dependencies.bicep | 26 + .../tests/e2e/defaults/main.test.bicep | 64 + .../webtest/tests/e2e/max/dependencies.bicep | 37 + .../webtest/tests/e2e/max/main.test.bicep | 102 + .../tests/e2e/waf-aligned/dependencies.bicep | 26 + .../tests/e2e/waf-aligned/main.test.bicep | 73 + avm/1.1.0/res/insights/webtest/version.json | 7 + avm/1.1.0/res/key-vault/vault/README.md | 3179 ++++++++ .../key-vault/vault/access-policy/README.md | 212 + .../key-vault/vault/access-policy/main.bicep | 120 + .../key-vault/vault/access-policy/main.json | 219 + avm/1.1.0/res/key-vault/vault/key/README.md | 291 + avm/1.1.0/res/key-vault/vault/key/main.bicep | 170 + avm/1.1.0/res/key-vault/vault/key/main.json | 302 + avm/1.1.0/res/key-vault/vault/main.bicep | 651 ++ avm/1.1.0/res/key-vault/vault/main.json | 3115 ++++++++ .../res/key-vault/vault/secret/README.md | 226 + .../res/key-vault/vault/secret/main.bicep | 127 + .../res/key-vault/vault/secret/main.json | 259 + .../vault/tests/e2e/defaults/main.test.bicep | 49 + .../vault/tests/e2e/eckey/main.test.bicep | 83 + .../vault/tests/e2e/max/dependencies.bicep | 65 + .../vault/tests/e2e/max/main.test.bicep | 319 + .../e2e/max/tests/connectivity.tests.ps1 | 39 + .../vault/tests/e2e/rsakey/main.test.bicep | 83 + .../tests/e2e/waf-aligned/dependencies.bicep | 65 + .../tests/e2e/waf-aligned/main.test.bicep | 151 + .../vault/tests/unit/custom.tests.ps1 | 7 + avm/1.1.0/res/key-vault/vault/version.json | 7 + .../user-assigned-identity/README.md | 706 ++ .../federated-identity-credential/README.md | 75 + .../federated-identity-credential/main.bicep | 40 + .../federated-identity-credential/main.json | 80 + .../user-assigned-identity/main.bicep | 196 + .../user-assigned-identity/main.json | 441 ++ .../tests/e2e/defaults/main.test.bicep | 48 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 110 + .../tests/e2e/waf-aligned/dependencies.bicep | 13 + .../tests/e2e/waf-aligned/main.test.bicep | 79 + .../tests/unit/custom.tests.ps1 | 7 + .../user-assigned-identity/version.json | 7 + .../res/net-app/net-app-account/README.md | 2851 +++++++ .../net-app-account/backup-policies/README.md | 109 + .../backup-policies/main.bicep | 49 + .../net-app-account/backup-policies/main.json | 102 + .../net-app-account/backup-vault/README.md | 121 + .../backup-vault/backup/README.md | 97 + .../backup-vault/backup/main.bicep | 58 + .../backup-vault/backup/main.json | 120 + .../net-app-account/backup-vault/main.bicep | 75 + .../net-app-account/backup-vault/main.json | 296 + .../net-app-account/capacity-pool/README.md | 887 +++ .../net-app-account/capacity-pool/main.bicep | 234 + .../net-app-account/capacity-pool/main.json | 1543 ++++ .../capacity-pool/volume/README.md | 696 ++ .../capacity-pool/volume/main.bicep | 380 + .../capacity-pool/volume/main.json | 703 ++ .../res/net-app/net-app-account/main.bicep | 429 ++ .../res/net-app/net-app-account/main.json | 4199 ++++++++++ .../snapshot-policies/README.md | 320 + .../snapshot-policies/main.bicep | 145 + .../snapshot-policies/main.json | 290 + .../tests/e2e/defaults/main.test.bicep | 46 + .../tests/e2e/max/dependencies.bicep | 52 + .../tests/e2e/max/main.test.bicep | 229 + .../tests/e2e/nfs3/dependencies.bicep | 49 + .../tests/e2e/nfs3/main.test.bicep | 168 + .../tests/e2e/waf-aligned/main.test.bicep | 54 + .../res/net-app/net-app-account/version.json | 7 + .../README.md | 495 ++ .../main.bicep | 65 + .../main.json | 127 + .../tests/e2e/defaults/main.test.bicep | 56 + .../tests/e2e/max/main.test.bicep | 75 + .../tests/e2e/waf-aligned/main.test.bicep | 72 + .../version.json | 7 + .../res/network/application-gateway/README.md | 4483 +++++++++++ .../network/application-gateway/main.bicep | 651 ++ .../res/network/application-gateway/main.json | 1794 +++++ .../tests/e2e/defaults/dependencies.bicep | 60 + .../tests/e2e/defaults/main.test.bicep | 137 + .../tests/e2e/max/dependencies.bicep | 154 + .../tests/e2e/max/main.test.bicep | 530 ++ .../tests/e2e/waf-aligned/dependencies.bicep | 175 + .../tests/e2e/waf-aligned/main.test.bicep | 478 ++ .../network/application-gateway/version.json | 7 + .../application-security-group/README.md | 544 ++ .../application-security-group/main.bicep | 152 + .../application-security-group/main.json | 267 + .../tests/e2e/defaults/main.test.bicep | 48 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 88 + .../tests/e2e/waf-aligned/main.test.bicep | 57 + .../application-security-group/version.json | 7 + .../res/network/azure-firewall/README.md | 2949 +++++++ .../res/network/azure-firewall/main.bicep | 639 ++ .../res/network/azure-firewall/main.json | 2407 ++++++ .../tests/e2e/addpip/dependencies.bicep | 70 + .../tests/e2e/addpip/main.test.bicep | 77 + .../tests/e2e/basic/dependencies.bicep | 35 + .../tests/e2e/basic/main.test.bicep | 61 + .../tests/e2e/custompip/dependencies.bicep | 41 + .../tests/e2e/custompip/main.test.bicep | 101 + .../tests/e2e/defaults/dependencies.bicep | 29 + .../tests/e2e/defaults/main.test.bicep | 58 + .../tests/e2e/hubcommon/dependencies.bicep | 46 + .../tests/e2e/hubcommon/main.test.bicep | 66 + .../tests/e2e/hubmin/dependencies.bicep | 32 + .../tests/e2e/hubmin/main.test.bicep | 64 + .../tests/e2e/max/dependencies.bicep | 64 + .../tests/e2e/max/main.test.bicep | 222 + .../e2e/publicipprefix/dependencies.bicep | 56 + .../tests/e2e/publicipprefix/main.test.bicep | 75 + .../tests/e2e/tunneling/dependencies.bicep | 59 + .../tests/e2e/tunneling/main.test.bicep | 70 + .../tests/e2e/waf-aligned/dependencies.bicep | 67 + .../tests/e2e/waf-aligned/main.test.bicep | 180 + .../res/network/azure-firewall/version.json | 7 + avm/1.1.0/res/network/bastion-host/README.md | 1300 ++++ avm/1.1.0/res/network/bastion-host/main.bicep | 282 + avm/1.1.0/res/network/bastion-host/main.json | 1262 +++ .../tests/e2e/custompip/dependencies.bicep | 41 + .../tests/e2e/custompip/main.test.bicep | 111 + .../tests/e2e/defaults/dependencies.bicep | 30 + .../tests/e2e/defaults/main.test.bicep | 58 + .../tests/e2e/developer/dependencies.bicep | 30 + .../tests/e2e/developer/main.test.bicep | 59 + .../tests/e2e/max/dependencies.bicep | 64 + .../tests/e2e/max/main.test.bicep | 127 + .../tests/e2e/private/dependencies.bicep | 30 + .../tests/e2e/private/main.test.bicep | 61 + .../tests/e2e/waf-aligned/dependencies.bicep | 53 + .../tests/e2e/waf-aligned/main.test.bicep | 94 + .../res/network/bastion-host/version.json | 7 + avm/1.1.0/res/network/connection/README.md | 874 +++ avm/1.1.0/res/network/connection/main.bicep | 192 + avm/1.1.0/res/network/connection/main.json | 320 + .../tests/e2e/defaults/dependencies.bicep | 144 + .../tests/e2e/defaults/main.test.bicep | 77 + .../tests/e2e/max/dependencies.bicep | 144 + .../connection/tests/e2e/max/main.test.bicep | 89 + .../tests/e2e/waf-aligned/dependencies.bicep | 144 + .../tests/e2e/waf-aligned/main.test.bicep | 86 + avm/1.1.0/res/network/connection/version.json | 7 + .../network/ddos-protection-plan/README.md | 544 ++ .../network/ddos-protection-plan/main.bicep | 153 + .../network/ddos-protection-plan/main.json | 268 + .../tests/e2e/defaults/main.test.bicep | 49 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 86 + .../tests/e2e/waf-aligned/main.test.bicep | 58 + .../network/ddos-protection-plan/version.json | 7 + .../network/dns-forwarding-ruleset/README.md | 771 ++ .../forwarding-rule/README.md | 88 + .../forwarding-rule/main.bicep | 45 + .../forwarding-rule/main.json | 97 + .../network/dns-forwarding-ruleset/main.bicep | 238 + .../network/dns-forwarding-ruleset/main.json | 633 ++ .../tests/e2e/defaults/dependencies.bicep | 72 + .../tests/e2e/defaults/main.test.bicep | 64 + .../tests/e2e/max/dependencies.bicep | 83 + .../tests/e2e/max/main.test.bicep | 115 + .../tests/e2e/waf-aligned/dependencies.bicep | 83 + .../tests/e2e/waf-aligned/main.test.bicep | 74 + .../dns-forwarding-ruleset/version.json | 7 + .../virtual-network-link/README.md | 72 + .../virtual-network-link/main.bicep | 38 + .../virtual-network-link/main.json | 84 + avm/1.1.0/res/network/dns-resolver/README.md | 777 ++ .../dns-resolver/inbound-endpoint/README.md | 93 + .../dns-resolver/inbound-endpoint/main.bicep | 55 + .../dns-resolver/inbound-endpoint/main.json | 112 + avm/1.1.0/res/network/dns-resolver/main.bicep | 244 + avm/1.1.0/res/network/dns-resolver/main.json | 663 ++ .../dns-resolver/outbound-endpoint/README.md | 76 + .../dns-resolver/outbound-endpoint/main.bicep | 43 + .../dns-resolver/outbound-endpoint/main.json | 92 + .../tests/e2e/defaults/dependencies.bicep | 56 + .../tests/e2e/defaults/main.test.bicep | 59 + .../tests/e2e/max/dependencies.bicep | 56 + .../tests/e2e/max/main.test.bicep | 102 + .../tests/e2e/waf-aligned/dependencies.bicep | 56 + .../tests/e2e/waf-aligned/main.test.bicep | 80 + .../dns-resolver/tests/unit/custom.tests.ps1 | 7 + .../res/network/dns-resolver/version.json | 7 + avm/1.1.0/res/network/dns-zone/README.md | 3268 ++++++++ avm/1.1.0/res/network/dns-zone/a/README.md | 200 + avm/1.1.0/res/network/dns-zone/a/main.bicep | 144 + avm/1.1.0/res/network/dns-zone/a/main.json | 223 + avm/1.1.0/res/network/dns-zone/aaaa/README.md | 200 + .../res/network/dns-zone/aaaa/main.bicep | 145 + avm/1.1.0/res/network/dns-zone/aaaa/main.json | 223 + avm/1.1.0/res/network/dns-zone/caa/README.md | 192 + avm/1.1.0/res/network/dns-zone/caa/main.bicep | 137 + avm/1.1.0/res/network/dns-zone/caa/main.json | 215 + .../res/network/dns-zone/cname/README.md | 200 + .../res/network/dns-zone/cname/main.bicep | 145 + .../res/network/dns-zone/cname/main.json | 223 + avm/1.1.0/res/network/dns-zone/main.bicep | 599 ++ avm/1.1.0/res/network/dns-zone/main.json | 3529 +++++++++ avm/1.1.0/res/network/dns-zone/mx/README.md | 192 + avm/1.1.0/res/network/dns-zone/mx/main.bicep | 137 + avm/1.1.0/res/network/dns-zone/mx/main.json | 215 + avm/1.1.0/res/network/dns-zone/ns/README.md | 192 + avm/1.1.0/res/network/dns-zone/ns/main.bicep | 136 + avm/1.1.0/res/network/dns-zone/ns/main.json | 215 + avm/1.1.0/res/network/dns-zone/ptr/README.md | 192 + avm/1.1.0/res/network/dns-zone/ptr/main.bicep | 137 + avm/1.1.0/res/network/dns-zone/ptr/main.json | 215 + avm/1.1.0/res/network/dns-zone/soa/README.md | 192 + avm/1.1.0/res/network/dns-zone/soa/main.bicep | 137 + avm/1.1.0/res/network/dns-zone/soa/main.json | 215 + avm/1.1.0/res/network/dns-zone/srv/README.md | 192 + avm/1.1.0/res/network/dns-zone/srv/main.bicep | 136 + avm/1.1.0/res/network/dns-zone/srv/main.json | 215 + .../tests/e2e/defaults/main.test.bicep | 48 + .../dns-zone/tests/e2e/max/dependencies.bicep | 37 + .../dns-zone/tests/e2e/max/main.test.bicep | 393 + .../tests/e2e/waf-aligned/dependencies.bicep | 37 + .../tests/e2e/waf-aligned/main.test.bicep | 67 + avm/1.1.0/res/network/dns-zone/txt/README.md | 192 + avm/1.1.0/res/network/dns-zone/txt/main.bicep | 136 + avm/1.1.0/res/network/dns-zone/txt/main.json | 215 + avm/1.1.0/res/network/dns-zone/version.json | 7 + .../network/express-route-circuit/README.md | 1030 +++ .../network/express-route-circuit/main.bicep | 342 + .../network/express-route-circuit/main.json | 606 ++ .../tests/e2e/defaults/main.test.bicep | 51 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 122 + .../tests/e2e/waf-aligned/dependencies.bicep | 13 + .../tests/e2e/waf-aligned/main.test.bicep | 99 + .../express-route-circuit/version.json | 7 + .../network/express-route-gateway/README.md | 618 ++ .../network/express-route-gateway/main.bicep | 183 + .../network/express-route-gateway/main.json | 314 + .../tests/e2e/defaults/dependencies.bicep | 27 + .../tests/e2e/defaults/main.test.bicep | 58 + .../tests/e2e/max/dependencies.bicep | 38 + .../tests/e2e/max/main.test.bicep | 91 + .../tests/e2e/waf-aligned/dependencies.bicep | 27 + .../tests/e2e/waf-aligned/main.test.bicep | 68 + .../express-route-gateway/version.json | 7 + .../res/network/express-route-port/README.md | 725 ++ .../res/network/express-route-port/main.bicep | 180 + .../res/network/express-route-port/main.json | 410 + .../tests/e2e/defaults/main.test.bicep | 49 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 95 + .../tests/e2e/waf-aligned/main.test.bicep | 49 + .../network/express-route-port/version.json | 7 + .../res/network/firewall-policy/README.md | 1036 +++ .../res/network/firewall-policy/main.bicep | 325 + .../res/network/firewall-policy/main.json | 583 ++ .../rule-collection-group/README.md | 72 + .../rule-collection-group/main.bicep | 36 + .../rule-collection-group/main.json | 81 + .../tests/e2e/defaults/main.test.bicep | 48 + .../tests/e2e/max/dependencies.bicep | 16 + .../tests/e2e/max/main.test.bicep | 135 + .../tests/e2e/waf-aligned/main.test.bicep | 94 + .../res/network/firewall-policy/version.json | 7 + .../README.md | 1196 +++ .../main.bicep | 267 + .../main.json | 489 ++ .../tests/e2e/defaults/main.test.bicep | 48 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 151 + .../tests/e2e/waf-aligned/main.test.bicep | 116 + .../version.json | 7 + avm/1.1.0/res/network/front-door/README.md | 1643 ++++ avm/1.1.0/res/network/front-door/main.bicep | 267 + avm/1.1.0/res/network/front-door/main.json | 501 ++ .../tests/e2e/defaults/main.test.bicep | 127 + .../tests/e2e/max/dependencies.bicep | 13 + .../front-door/tests/e2e/max/main.test.bicep | 209 + .../tests/e2e/waf-aligned/main.test.bicep | 163 + avm/1.1.0/res/network/front-door/version.json | 7 + avm/1.1.0/res/network/ip-group/README.md | 568 ++ avm/1.1.0/res/network/ip-group/main.bicep | 158 + avm/1.1.0/res/network/ip-group/main.json | 278 + .../tests/e2e/defaults/main.test.bicep | 48 + .../ip-group/tests/e2e/max/dependencies.bicep | 13 + .../ip-group/tests/e2e/max/main.test.bicep | 92 + .../tests/e2e/waf-aligned/main.test.bicep | 57 + avm/1.1.0/res/network/ip-group/version.json | 7 + avm/1.1.0/res/network/load-balancer/README.md | 2167 ++++++ .../backend-address-pool/README.md | 100 + .../backend-address-pool/main.bicep | 49 + .../backend-address-pool/main.json | 96 + .../load-balancer/inbound-nat-rule/README.md | 178 + .../load-balancer/inbound-nat-rule/main.bicep | 87 + .../load-balancer/inbound-nat-rule/main.json | 159 + .../res/network/load-balancer/main.bicep | 456 ++ avm/1.1.0/res/network/load-balancer/main.json | 930 +++ .../tests/e2e/defaults/dependencies.bicep | 25 + .../tests/e2e/defaults/main.test.bicep | 77 + .../tests/e2e/external/dependencies.bicep | 36 + .../tests/e2e/external/main.test.bicep | 196 + .../tests/e2e/internal/dependencies.bicep | 41 + .../tests/e2e/internal/main.test.bicep | 138 + .../tests/e2e/max/dependencies.bicep | 36 + .../tests/e2e/max/main.test.bicep | 202 + .../tests/e2e/waf-aligned/dependencies.bicep | 41 + .../tests/e2e/waf-aligned/main.test.bicep | 155 + .../res/network/load-balancer/version.json | 7 + .../network/local-network-gateway/README.md | 665 ++ .../network/local-network-gateway/main.bicep | 191 + .../network/local-network-gateway/main.json | 321 + .../tests/e2e/defaults/main.test.bicep | 52 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 94 + .../tests/e2e/waf-aligned/main.test.bicep | 63 + .../local-network-gateway/version.json | 7 + avm/1.1.0/res/network/nat-gateway/README.md | 1012 +++ avm/1.1.0/res/network/nat-gateway/main.bicep | 248 + avm/1.1.0/res/network/nat-gateway/main.json | 1485 ++++ .../modules/formatResourceId.bicep | 6 + .../tests/e2e/defaults/main.test.bicep | 52 + .../tests/e2e/existingPip/dependencies.bicep | 25 + .../tests/e2e/existingPip/main.test.bicep | 61 + .../tests/e2e/max/dependencies.bicep | 13 + .../nat-gateway/tests/e2e/max/main.test.bicep | 144 + .../tests/e2e/prefixCombined/main.test.bicep | 58 + .../tests/e2e/waf-aligned/main.test.bicep | 93 + .../tests/unit/avm.core.team.tests.ps1 | 39 + .../res/network/nat-gateway/version.json | 7 + .../res/network/network-interface/README.md | 996 +++ .../res/network/network-interface/main.bicep | 333 + .../res/network/network-interface/main.json | 528 ++ .../tests/e2e/defaults/dependencies.bicep | 30 + .../tests/e2e/defaults/main.test.bicep | 66 + .../tests/e2e/max/dependencies.bicep | 113 + .../tests/e2e/max/main.test.bicep | 142 + .../tests/e2e/waf-aligned/dependencies.bicep | 102 + .../tests/e2e/waf-aligned/main.test.bicep | 115 + .../network/network-interface/version.json | 7 + .../res/network/network-manager/README.md | 2307 ++++++ .../connectivity-configuration/README.md | 191 + .../connectivity-configuration/main.bicep | 92 + .../connectivity-configuration/main.json | 187 + .../res/network/network-manager/main.bicep | 323 + .../res/network/network-manager/main.json | 3487 +++++++++ .../network-manager/network-group/README.md | 112 + .../network-manager/network-group/main.bicep | 71 + .../network-manager/network-group/main.json | 224 + .../network-group/static-member/README.md | 68 + .../network-group/static-member/main.bicep | 40 + .../network-group/static-member/main.json | 72 + .../routing-configuration/README.md | 245 + .../routing-configuration/main.bicep | 76 + .../routing-configuration/main.json | 714 ++ .../rule-collection/README.md | 219 + .../rule-collection/main.bicep | 96 + .../rule-collection/main.json | 430 ++ .../rule-collection/rule/README.md | 162 + .../rule-collection/rule/main.bicep | 79 + .../rule-collection/rule/main.json | 168 + .../scope-connection/README.md | 82 + .../scope-connection/main.bicep | 43 + .../scope-connection/main.json | 83 + .../security-admin-configuration/README.md | 357 + .../security-admin-configuration/main.bicep | 87 + .../security-admin-configuration/main.json | 1012 +++ .../rule-collection/README.md | 298 + .../rule-collection/main.bicep | 118 + .../rule-collection/main.json | 621 ++ .../rule-collection/rule/README.md | 256 + .../rule-collection/rule/main.bicep | 129 + .../rule-collection/rule/main.json | 262 + .../tests/e2e/defaults/main.test.bicep | 53 + .../tests/e2e/max/dependencies.bicep | 129 + .../tests/e2e/max/main.test.bicep | 372 + .../tests/e2e/waf-aligned/main.test.bicep | 61 + .../res/network/network-manager/version.json | 7 + .../network/network-security-group/README.md | 1218 +++ .../network/network-security-group/main.bicep | 311 + .../network/network-security-group/main.json | 602 ++ .../tests/e2e/defaults/main.test.bicep | 48 + .../tests/e2e/max/dependencies.bicep | 24 + .../tests/e2e/max/main.test.bicep | 205 + .../tests/e2e/waf-aligned/main.test.bicep | 71 + .../network-security-group/version.json | 7 + .../res/network/network-watcher/README.md | 932 +++ .../connection-monitor/README.md | 106 + .../connection-monitor/main.bicep | 64 + .../connection-monitor/main.json | 122 + .../network-watcher/flow-log/README.md | 155 + .../network-watcher/flow-log/main.bicep | 96 + .../network-watcher/flow-log/main.json | 163 + .../res/network/network-watcher/main.bicep | 194 + .../res/network/network-watcher/main.json | 666 ++ .../tests/e2e/defaults/main.test.bicep | 50 + .../tests/e2e/max/dependencies.bicep | 144 + .../tests/e2e/max/main.test.bicep | 176 + .../tests/e2e/waf-aligned/dependencies.bicep | 144 + .../tests/e2e/waf-aligned/main.test.bicep | 155 + .../res/network/network-watcher/version.json | 7 + .../res/network/p2s-vpn-gateway/README.md | 679 ++ .../res/network/p2s-vpn-gateway/main.bicep | 204 + .../res/network/p2s-vpn-gateway/main.json | 362 + .../tests/e2e/defaults/dependencies.bicep | 57 + .../tests/e2e/defaults/main.test.bicep | 65 + .../tests/e2e/max/dependencies.bicep | 156 + .../tests/e2e/max/main.test.bicep | 79 + .../tests/e2e/waf-aligned/dependencies.bicep | 82 + .../tests/e2e/waf-aligned/main.test.bicep | 72 + .../res/network/p2s-vpn-gateway/version.json | 7 + .../res/network/private-dns-zone/README.md | 2740 +++++++ .../res/network/private-dns-zone/a/README.md | 188 + .../res/network/private-dns-zone/a/main.bicep | 122 + .../res/network/private-dns-zone/a/main.json | 211 + .../network/private-dns-zone/aaaa/README.md | 188 + .../network/private-dns-zone/aaaa/main.bicep | 122 + .../network/private-dns-zone/aaaa/main.json | 211 + .../network/private-dns-zone/cname/README.md | 188 + .../network/private-dns-zone/cname/main.bicep | 122 + .../network/private-dns-zone/cname/main.json | 211 + .../res/network/private-dns-zone/main.bicep | 517 ++ .../res/network/private-dns-zone/main.json | 3006 ++++++++ .../res/network/private-dns-zone/mx/README.md | 188 + .../network/private-dns-zone/mx/main.bicep | 122 + .../res/network/private-dns-zone/mx/main.json | 211 + .../network/private-dns-zone/ptr/README.md | 188 + .../network/private-dns-zone/ptr/main.bicep | 122 + .../network/private-dns-zone/ptr/main.json | 211 + .../network/private-dns-zone/soa/README.md | 188 + .../network/private-dns-zone/soa/main.bicep | 122 + .../network/private-dns-zone/soa/main.json | 211 + .../network/private-dns-zone/srv/README.md | 188 + .../network/private-dns-zone/srv/main.bicep | 122 + .../network/private-dns-zone/srv/main.json | 211 + .../tests/e2e/defaults/main.test.bicep | 48 + .../tests/e2e/max/dependencies.bicep | 41 + .../tests/e2e/max/main.test.bicep | 332 + .../tests/e2e/waf-aligned/dependencies.bicep | 41 + .../tests/e2e/waf-aligned/main.test.bicep | 67 + .../network/private-dns-zone/txt/README.md | 188 + .../network/private-dns-zone/txt/main.bicep | 122 + .../network/private-dns-zone/txt/main.json | 211 + .../res/network/private-dns-zone/version.json | 7 + .../virtual-network-link/README.md | 100 + .../virtual-network-link/main.bicep | 53 + .../virtual-network-link/main.json | 115 + .../res/network/private-endpoint/README.md | 1268 ++++ .../res/network/private-endpoint/main.bicep | 248 + .../res/network/private-endpoint/main.json | 697 ++ .../private-dns-zone-group/README.md | 91 + .../private-dns-zone-group/main.bicep | 56 + .../private-dns-zone-group/main.json | 116 + .../tests/e2e/defaults/dependencies.bicep | 54 + .../tests/e2e/defaults/main.test.bicep | 69 + .../tests/e2e/max/dependencies.bicep | 95 + .../tests/e2e/max/main.test.bicep | 135 + .../tests/e2e/private-link/dependencies.bicep | 147 + .../tests/e2e/private-link/main.test.bicep | 78 + .../tests/e2e/waf-aligned/dependencies.bicep | 95 + .../tests/e2e/waf-aligned/main.test.bicep | 97 + .../tests/unit/custom.tests.ps1 | 7 + .../res/network/private-endpoint/version.json | 7 + .../network/private-link-service/README.md | 858 +++ .../network/private-link-service/main.bicep | 189 + .../network/private-link-service/main.json | 324 + .../tests/e2e/defaults/dependencies.bicep | 57 + .../tests/e2e/defaults/main.test.bicep | 73 + .../tests/e2e/max/dependencies.bicep | 68 + .../tests/e2e/max/main.test.bicep | 122 + .../tests/e2e/waf-aligned/dependencies.bicep | 57 + .../tests/e2e/waf-aligned/main.test.bicep | 95 + .../network/private-link-service/version.json | 7 + .../res/network/public-ip-address/README.md | 1188 +++ .../res/network/public-ip-address/main.bicep | 279 + .../res/network/public-ip-address/main.json | 671 ++ .../tests/e2e/defaults/main.test.bicep | 47 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 128 + .../tests/e2e/waf-aligned/dependencies.bicep | 13 + .../tests/e2e/waf-aligned/main.test.bicep | 120 + .../tests/unit/custom.tests.ps1 | 7 + .../network/public-ip-address/version.json | 7 + .../res/network/public-ip-prefix/README.md | 812 ++ .../res/network/public-ip-prefix/main.bicep | 177 + .../res/network/public-ip-prefix/main.json | 377 + .../tests/e2e/defaults/main.test.bicep | 48 + .../tests/e2e/ipv6/main.test.bicep | 50 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 99 + .../tests/e2e/waf-aligned/dependencies.bicep | 13 + .../tests/e2e/waf-aligned/main.test.bicep | 54 + .../res/network/public-ip-prefix/version.json | 7 + avm/1.1.0/res/network/route-table/README.md | 699 ++ avm/1.1.0/res/network/route-table/main.bicep | 184 + avm/1.1.0/res/network/route-table/main.json | 341 + .../tests/e2e/defaults/main.test.bicep | 45 + .../tests/e2e/max/dependencies.bicep | 13 + .../route-table/tests/e2e/max/main.test.bicep | 95 + .../tests/e2e/waf-aligned/main.test.bicep | 64 + .../res/network/route-table/version.json | 7 + .../network/service-endpoint-policy/README.md | 555 ++ .../service-endpoint-policy/main.bicep | 179 + .../network/service-endpoint-policy/main.json | 295 + .../tests/e2e/defaults/main.test.bicep | 47 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 87 + .../tests/e2e/waf-aligned/main.test.bicep | 52 + .../service-endpoint-policy/version.json | 7 + .../network/trafficmanagerprofile/README.md | 979 +++ .../network/trafficmanagerprofile/main.bicep | 289 + .../network/trafficmanagerprofile/main.json | 517 ++ .../tests/e2e/defaults/main.test.bicep | 47 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 116 + .../tests/e2e/waf-aligned/dependencies.bicep | 81 + .../tests/e2e/waf-aligned/main.test.bicep | 131 + .../trafficmanagerprofile/version.json | 7 + avm/1.1.0/res/network/virtual-hub/README.md | 934 +++ .../virtual-hub/hub-route-table/README.md | 74 + .../virtual-hub/hub-route-table/main.bicep | 36 + .../virtual-hub/hub-route-table/main.json | 75 + .../virtual-hub/hub-routing-intent/README.md | 73 + .../virtual-hub/hub-routing-intent/main.bicep | 72 + .../virtual-hub/hub-routing-intent/main.json | 72 + .../hub-virtual-network-connection/README.md | 82 + .../hub-virtual-network-connection/main.bicep | 42 + .../hub-virtual-network-connection/main.json | 84 + avm/1.1.0/res/network/virtual-hub/main.bicep | 243 + avm/1.1.0/res/network/virtual-hub/main.json | 643 ++ .../tests/e2e/defaults/dependencies.bicep | 13 + .../tests/e2e/defaults/main.test.bicep | 59 + .../tests/e2e/max/dependencies.bicep | 41 + .../virtual-hub/tests/e2e/max/main.test.bicep | 95 + .../e2e/routing-intent/dependencies.bicep | 81 + .../tests/e2e/routing-intent/main.test.bicep | 84 + .../tests/e2e/waf-aligned/dependencies.bicep | 41 + .../tests/e2e/waf-aligned/main.test.bicep | 95 + .../res/network/virtual-hub/version.json | 7 + .../network/virtual-network-gateway/README.md | 3197 ++++++++ .../virtual-network-gateway/main.bicep | 617 ++ .../network/virtual-network-gateway/main.json | 1630 ++++ .../nat-rule/README.md | 117 + .../nat-rule/main.bicep | 58 + .../nat-rule/main.json | 109 + .../e2e/activeActiveBGP/dependencies.bicep | 49 + .../tests/e2e/activeActiveBGP/main.test.bicep | 83 + .../activeActiveBgpAPIPA/dependencies.bicep | 49 + .../e2e/activeActiveBgpAPIPA/main.test.bicep | 85 + .../dependencies.bicep | 96 + .../activeActiveExistingPip/main.test.bicep | 88 + .../e2e/activeActiveNoBGP/dependencies.bicep | 49 + .../e2e/activeActiveNoBGP/main.test.bicep | 83 + .../e2e/activePassiveBGP/dependencies.bicep | 49 + .../e2e/activePassiveBGP/main.test.bicep | 85 + .../dependencies.bicep | 74 + .../activePassiveExistingPip/main.test.bicep | 87 + .../e2e/activePassiveNoBGP/dependencies.bicep | 49 + .../e2e/activePassiveNoBGP/main.test.bicep | 83 + .../tests/e2e/defaults/dependencies.bicep | 49 + .../tests/e2e/defaults/main.test.bicep | 73 + .../tests/e2e/expressRoute/dependencies.bicep | 30 + .../tests/e2e/expressRoute/main.test.bicep | 75 + .../tests/e2e/max/dependencies.bicep | 60 + .../tests/e2e/max/main.test.bicep | 180 + .../tests/e2e/vpn-no-az/dependencies.bicep | 49 + .../tests/e2e/vpn-no-az/main.test.bicep | 69 + .../tests/e2e/vpn/dependencies.bicep | 49 + .../tests/e2e/vpn/main.test.bicep | 82 + .../tests/e2e/waf-aligned/dependencies.bicep | 49 + .../tests/e2e/waf-aligned/main.test.bicep | 156 + .../virtual-network-gateway/version.json | 7 + .../res/network/virtual-network/ORPHANED.md | 4 + .../res/network/virtual-network/README.md | 2015 +++++ .../res/network/virtual-network/main.bicep | 392 + .../res/network/virtual-network/main.json | 1526 ++++ .../network/virtual-network/subnet/README.md | 308 + .../network/virtual-network/subnet/main.bicep | 170 + .../network/virtual-network/subnet/main.json | 338 + .../tests/e2e/defaults/main.test.bicep | 51 + .../tests/e2e/ipv6/main.test.bicep | 61 + .../tests/e2e/max/dependencies.bicep | 163 + .../tests/e2e/max/main.test.bicep | 193 + .../tests/e2e/vnetPeering/dependencies.bicep | 158 + .../tests/e2e/vnetPeering/main.test.bicep | 94 + .../tests/e2e/waf-aligned/dependencies.bicep | 163 + .../tests/e2e/waf-aligned/main.test.bicep | 147 + .../res/network/virtual-network/version.json | 7 + .../virtual-network-peering/README.md | 110 + .../virtual-network-peering/main.bicep | 54 + .../virtual-network-peering/main.json | 109 + avm/1.1.0/res/network/virtual-wan/README.md | 607 ++ avm/1.1.0/res/network/virtual-wan/main.bicep | 137 + avm/1.1.0/res/network/virtual-wan/main.json | 317 + .../tests/e2e/defaults/main.test.bicep | 47 + .../tests/e2e/max/dependencies.bicep | 13 + .../virtual-wan/tests/e2e/max/main.test.bicep | 92 + .../tests/e2e/waf-aligned/dependencies.bicep | 13 + .../tests/e2e/waf-aligned/main.test.bicep | 56 + .../res/network/virtual-wan/version.json | 7 + avm/1.1.0/res/network/vpn-gateway/README.md | 748 ++ avm/1.1.0/res/network/vpn-gateway/main.bicep | 163 + avm/1.1.0/res/network/vpn-gateway/main.json | 635 ++ .../network/vpn-gateway/nat-rule/README.md | 112 + .../network/vpn-gateway/nat-rule/main.bicep | 56 + .../network/vpn-gateway/nat-rule/main.json | 114 + .../tests/e2e/defaults/dependencies.bicep | 27 + .../tests/e2e/defaults/main.test.bicep | 58 + .../tests/e2e/max/dependencies.bicep | 49 + .../vpn-gateway/tests/e2e/max/main.test.bicep | 103 + .../tests/e2e/waf-aligned/dependencies.bicep | 49 + .../tests/e2e/waf-aligned/main.test.bicep | 99 + .../res/network/vpn-gateway/version.json | 7 + .../vpn-gateway/vpn-connection/README.md | 249 + .../vpn-gateway/vpn-connection/main.bicep | 93 + .../vpn-gateway/vpn-connection/main.json | 175 + .../vpn-server-configuration/README.md | 1021 +++ .../vpn-server-configuration/main.bicep | 216 + .../vpn-server-configuration/main.json | 409 + .../tests/e2e/defaults/dependencies.bicep | 13 + .../tests/e2e/defaults/main.test.bicep | 79 + .../tests/e2e/max/dependencies.bicep | 13 + .../tests/e2e/max/main.test.bicep | 162 + .../tests/e2e/waf-aligned/dependencies.bicep | 13 + .../tests/e2e/waf-aligned/main.test.bicep | 81 + .../vpn-server-configuration/version.json | 7 + avm/1.1.0/res/network/vpn-site/README.md | 931 +++ avm/1.1.0/res/network/vpn-site/main.bicep | 158 + avm/1.1.0/res/network/vpn-site/main.json | 346 + .../tests/e2e/defaults/dependencies.bicep | 13 + .../tests/e2e/defaults/main.test.bicep | 61 + .../vpn-site/tests/e2e/max/dependencies.bicep | 24 + .../vpn-site/tests/e2e/max/main.test.bicep | 130 + .../tests/e2e/waf-aligned/dependencies.bicep | 24 + .../tests/e2e/waf-aligned/main.test.bicep | 104 + avm/1.1.0/res/network/vpn-site/version.json | 7 + .../operational-insights/workspace/README.md | 4216 +++++++++++ .../workspace/data-export/README.md | 120 + .../workspace/data-export/main.bicep | 71 + .../workspace/data-export/main.json | 128 + .../workspace/data-source/README.md | 179 + .../workspace/data-source/main.bicep | 100 + .../workspace/data-source/main.json | 180 + .../workspace/linked-service/README.md | 80 + .../workspace/linked-service/main.bicep | 40 + .../workspace/linked-service/main.json | 90 + .../linked-storage-account/README.md | 68 + .../linked-storage-account/main.bicep | 39 + .../linked-storage-account/main.json | 83 + .../operational-insights/workspace/main.bicep | 669 ++ .../operational-insights/workspace/main.json | 2996 ++++++++ .../workspace/saved-search/README.md | 123 + .../workspace/saved-search/main.bicep | 62 + .../workspace/saved-search/main.json | 127 + .../storage-insight-config/README.md | 89 + .../storage-insight-config/main.bicep | 51 + .../storage-insight-config/main.json | 113 + .../workspace/table/README.md | 479 ++ .../workspace/table/main.bicep | 191 + .../workspace/table/main.json | 420 + .../tests/e2e/adv/dependencies.bicep | 85 + .../workspace/tests/e2e/adv/main.test.bicep | 367 + .../tests/e2e/defaults/main.test.bicep | 48 + .../tests/e2e/max/dependencies.bicep | 47 + .../workspace/tests/e2e/max/main.test.bicep | 379 + .../tests/e2e/waf-aligned/dependencies.bicep | 33 + .../tests/e2e/waf-aligned/main.test.bicep | 217 + .../workspace/version.json | 7 + .../operations-management/solution/README.md | 547 ++ .../operations-management/solution/main.bicep | 92 + .../operations-management/solution/main.json | 151 + .../tests/e2e/defaults/dependencies.bicep | 13 + .../tests/e2e/defaults/main.test.bicep | 58 + .../solution/tests/e2e/ms/dependencies.bicep | 13 + .../solution/tests/e2e/ms/main.test.bicep | 58 + .../tests/e2e/nonms/dependencies.bicep | 13 + .../solution/tests/e2e/nonms/main.test.bicep | 60 + .../tests/e2e/sql-auditing/dependencies.bicep | 13 + .../tests/e2e/sql-auditing/main.test.bicep | 59 + .../tests/e2e/waf-aligned/dependencies.bicep | 13 + .../tests/e2e/waf-aligned/main.test.bicep | 63 + .../solution/version.json | 7 + .../res/resources/deployment-script/README.md | 1450 ++++ .../resources/deployment-script/main.bicep | 271 + .../res/resources/deployment-script/main.json | 523 ++ .../tests/e2e/cli/dependencies.bicep | 31 + .../tests/e2e/cli/main.test.bicep | 74 + .../tests/e2e/defaults/dependencies.bicep | 13 + .../tests/e2e/defaults/main.test.bicep | 65 + .../tests/e2e/max/dependencies.bicep | 33 + .../tests/e2e/max/main.test.bicep | 113 + .../e2e/private-endpoint/dependencies.bicep | 154 + .../e2e/private-endpoint/main.test.bicep | 73 + .../e2e/private-network/dependencies.bicep | 103 + .../tests/e2e/private-network/main.test.bicep | 75 + .../tests/e2e/ps/dependencies.bicep | 31 + .../tests/e2e/ps/main.test.bicep | 69 + .../tests/e2e/waf-aligned/dependencies.bicep | 38 + .../tests/e2e/waf-aligned/main.test.bicep | 79 + .../resources/deployment-script/version.json | 7 + .../res/resources/resource-group/README.md | 516 ++ .../res/resources/resource-group/main.bicep | 78 + .../res/resources/resource-group/main.json | 467 ++ .../resource-group/modules/nested_lock.bicep | 25 + .../modules/nested_roleAssignments.bicep | 88 + .../tests/e2e/defaults/main.test.bicep | 31 + .../tests/e2e/max/dependencies.bicep | 17 + .../tests/e2e/max/main.test.bicep | 84 + .../tests/e2e/waf-aligned/main.test.bicep | 33 + .../res/resources/resource-group/version.json | 7 + .../res/storage/storage-account/README.md | 4897 ++++++++++++ .../storage-account/blob-service/README.md | 471 ++ .../blob-service/container/README.md | 275 + .../container/immutability-policy/README.md | 78 + .../container/immutability-policy/main.bicep | 49 + .../container/immutability-policy/main.json | 84 + .../blob-service/container/main.bicep | 167 + .../blob-service/container/main.json | 404 + .../storage-account/blob-service/main.bicep | 199 + .../storage-account/blob-service/main.json | 901 +++ .../storage-account/file-service/README.md | 311 + .../storage-account/file-service/main.bicep | 125 + .../storage-account/file-service/main.json | 760 ++ .../file-service/share/README.md | 246 + .../file-service/share/main.bicep | 142 + .../file-service/share/main.json | 375 + .../modules/nested_inner_roleAssignment.json | 93 + .../storage-account/local-user/README.md | 161 + .../storage-account/local-user/main.bicep | 78 + .../storage-account/local-user/main.json | 167 + .../res/storage/storage-account/main.bicep | 833 ++ .../res/storage/storage-account/main.json | 5657 ++++++++++++++ .../management-policy/README.md | 51 + .../management-policy/main.bicep | 33 + .../management-policy/main.json | 63 + .../modules/keyVaultExport.bicep | 42 + .../storage-account/queue-service/README.md | 278 + .../storage-account/queue-service/main.bicep | 108 + .../storage-account/queue-service/main.json | 560 ++ .../queue-service/queue/README.md | 187 + .../queue-service/queue/main.bicep | 114 + .../queue-service/queue/main.json | 214 + .../storage-account/table-service/README.md | 279 + .../storage-account/table-service/main.bicep | 107 + .../storage-account/table-service/main.json | 545 ++ .../table-service/table/README.md | 176 + .../table-service/table/main.bicep | 100 + .../table-service/table/main.json | 202 + .../tests/e2e/blob/main.test.bicep | 50 + .../tests/e2e/block/main.test.bicep | 50 + .../tests/e2e/changefeed/main.test.bicep | 52 + .../tests/e2e/defaults/main.test.bicep | 53 + .../tests/e2e/kvSecrets/dependencies.bicep | 21 + .../tests/e2e/kvSecrets/main.test.bicep | 58 + .../tests/e2e/max/dependencies.bicep | 99 + .../tests/e2e/max/main.test.bicep | 599 ++ .../tests/e2e/nfs/main.test.bicep | 58 + .../dependencies.bicep | 124 + .../main.test.bicep | 94 + .../dependencies.bicep | 116 + .../main.test.bicep | 101 + .../tests/e2e/v1/main.test.bicep | 49 + .../tests/e2e/waf-aligned/dependencies.bicep | 68 + .../tests/e2e/waf-aligned/main.test.bicep | 311 + .../res/storage/storage-account/version.json | 7 + .../image-template/README.md | 1454 ++++ .../image-template/main.bicep | 387 + .../image-template/main.json | 750 ++ .../tests/e2e/defaults/dependencies.bicep | 25 + .../tests/e2e/defaults/main.test.bicep | 73 + .../tests/e2e/max/dependencies.bicep | 324 + .../tests/e2e/max/main.test.bicep | 177 + .../e2e/max/src/Initialize-LinuxSoftware.ps1 | 93 + .../e2e/max/src/Install-LinuxPowerShell.sh | 43 + .../tests/e2e/waf-aligned/dependencies.bicep | 121 + .../tests/e2e/waf-aligned/main.test.bicep | 87 + .../image-template/version.json | 7 + avm/carmlVersionTracking.md | 1 + .../modules/azureNetappFiles/deploy.bicep | 44 +- .../DSCStorageScripts/1.0.3/Configuration.ps1 | 20 +- .../1.0.3/Script-DomainJoinStorage.ps1 | 22 +- .../scripts/Manual-DSC-Storage-Scripts.ps1 | 13 +- 1167 files changed, 313303 insertions(+), 41 deletions(-) create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/README.md create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/main.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/main.json create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi-def-loop.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/modules/management-group.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/modules/resource-group-additional-rbac-asi-def-loop.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/modules/resource-group-additional-rbac-asi.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/modules/resource-group.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/modules/subscription-additional-rbac-asi-def-loop.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/modules/subscription-additional-rbac-asi.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/modules/subscription.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/mg.defaults/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/mg.max/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/rg.defaults/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/rg.max/dependencies.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/rg.max/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/sub.defaults/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/sub.max/dependencies.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/sub.max/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-assignment/version.json create mode 100644 avm/1.1.0/ptn/authorization/policy-exemption/README.md create mode 100644 avm/1.1.0/ptn/authorization/policy-exemption/main.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-exemption/main.json create mode 100644 avm/1.1.0/ptn/authorization/policy-exemption/modules/management-group.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-exemption/modules/resource-group.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-exemption/modules/subscription.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/mg.defaults/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/mg.max/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/rg.defaults/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/rg.max/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/sub.defaults/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/sub.max/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/policy-exemption/version.json create mode 100644 avm/1.1.0/ptn/authorization/resource-role-assignment/README.md create mode 100644 avm/1.1.0/ptn/authorization/resource-role-assignment/main.bicep create mode 100644 avm/1.1.0/ptn/authorization/resource-role-assignment/main.json create mode 100644 avm/1.1.0/ptn/authorization/resource-role-assignment/modules/generic-role-assignment.json create mode 100644 avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/all/dependencies.bicep create mode 100644 avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/all/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/resource-role-assignment/version.json create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/README.md create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/main.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/main.json create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/modules/management-group.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/modules/resource-group.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/modules/subscription.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.defaults/dependencies.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.defaults/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.max/dependencies.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.max/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.default/dependencies.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.default/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.max/dependencies.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.max/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.default/dependencies.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.default/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.max/dependencies.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.max/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-assignment/version.json create mode 100644 avm/1.1.0/ptn/authorization/role-definition/README.md create mode 100644 avm/1.1.0/ptn/authorization/role-definition/main.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-definition/main.json create mode 100644 avm/1.1.0/ptn/authorization/role-definition/tests/e2e/mg.default/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-definition/tests/e2e/mg.loadJson/lib/subscription_owner.alz_role_definition.json create mode 100644 avm/1.1.0/ptn/authorization/role-definition/tests/e2e/mg.loadJson/main.test.bicep create mode 100644 avm/1.1.0/ptn/authorization/role-definition/version.json create mode 100644 avm/1.1.0/ptn/policy-insights/remediation/README.md create mode 100644 avm/1.1.0/ptn/policy-insights/remediation/main.bicep create mode 100644 avm/1.1.0/ptn/policy-insights/remediation/main.json create mode 100644 avm/1.1.0/ptn/policy-insights/remediation/modules/management-group.bicep create mode 100644 avm/1.1.0/ptn/policy-insights/remediation/modules/resource-group.bicep create mode 100644 avm/1.1.0/ptn/policy-insights/remediation/modules/subscription.bicep create mode 100644 avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/mg.defaults/main.test.bicep create mode 100644 avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/mg.max/main.test.bicep create mode 100644 avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/rg.defaults/main.test.bicep create mode 100644 avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/rg.max/main.test.bicep create mode 100644 avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/sub.defaults/main.test.bicep create mode 100644 avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/sub.max/main.test.bicep create mode 100644 avm/1.1.0/ptn/policy-insights/remediation/version.json create mode 100644 avm/1.1.0/res/automation/automation-account/README.md create mode 100644 avm/1.1.0/res/automation/automation-account/credential/README.md create mode 100644 avm/1.1.0/res/automation/automation-account/credential/main.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/credential/main.json create mode 100644 avm/1.1.0/res/automation/automation-account/job-schedule/README.md create mode 100644 avm/1.1.0/res/automation/automation-account/job-schedule/main.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/job-schedule/main.json create mode 100644 avm/1.1.0/res/automation/automation-account/main.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/main.json create mode 100644 avm/1.1.0/res/automation/automation-account/module/README.md create mode 100644 avm/1.1.0/res/automation/automation-account/module/main.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/module/main.json create mode 100644 avm/1.1.0/res/automation/automation-account/modules/linked-service.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/runbook/README.md create mode 100644 avm/1.1.0/res/automation/automation-account/runbook/main.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/runbook/main.json create mode 100644 avm/1.1.0/res/automation/automation-account/schedule/README.md create mode 100644 avm/1.1.0/res/automation/automation-account/schedule/main.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/schedule/main.json create mode 100644 avm/1.1.0/res/automation/automation-account/software-update-configuration/README.md create mode 100644 avm/1.1.0/res/automation/automation-account/software-update-configuration/main.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/software-update-configuration/main.json create mode 100644 avm/1.1.0/res/automation/automation-account/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/tests/e2e/encr/dependencies.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/tests/e2e/encr/main.test.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/variable/README.md create mode 100644 avm/1.1.0/res/automation/automation-account/variable/main.bicep create mode 100644 avm/1.1.0/res/automation/automation-account/variable/main.json create mode 100644 avm/1.1.0/res/automation/automation-account/version.json create mode 100644 avm/1.1.0/res/compute/availability-set/README.md create mode 100644 avm/1.1.0/res/compute/availability-set/main.bicep create mode 100644 avm/1.1.0/res/compute/availability-set/main.json create mode 100644 avm/1.1.0/res/compute/availability-set/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/compute/availability-set/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/availability-set/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/compute/availability-set/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/availability-set/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/compute/availability-set/version.json create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/README.md create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/main.bicep create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/main.json create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/modules/key-vault.vault.access-policy.bicep create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/modules/nested_keyVaultPermissions.bicep create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/accessPolicies/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/accessPolicies/main.test.bicep create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/compute/disk-encryption-set/version.json create mode 100644 avm/1.1.0/res/compute/disk/README.md create mode 100644 avm/1.1.0/res/compute/disk/main.bicep create mode 100644 avm/1.1.0/res/compute/disk/main.json create mode 100644 avm/1.1.0/res/compute/disk/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/compute/disk/tests/e2e/image/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/disk/tests/e2e/image/main.test.bicep create mode 100644 avm/1.1.0/res/compute/disk/tests/e2e/import/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/disk/tests/e2e/import/dependencies_rbac.bicep create mode 100644 avm/1.1.0/res/compute/disk/tests/e2e/import/main.test.bicep create mode 100644 avm/1.1.0/res/compute/disk/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/disk/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/compute/disk/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/compute/disk/version.json create mode 100644 avm/1.1.0/res/compute/gallery/README.md create mode 100644 avm/1.1.0/res/compute/gallery/application/README.md create mode 100644 avm/1.1.0/res/compute/gallery/application/main.bicep create mode 100644 avm/1.1.0/res/compute/gallery/application/main.json create mode 100644 avm/1.1.0/res/compute/gallery/image/README.md create mode 100644 avm/1.1.0/res/compute/gallery/image/main.bicep create mode 100644 avm/1.1.0/res/compute/gallery/image/main.json create mode 100644 avm/1.1.0/res/compute/gallery/main.bicep create mode 100644 avm/1.1.0/res/compute/gallery/main.json create mode 100644 avm/1.1.0/res/compute/gallery/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/compute/gallery/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/gallery/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/compute/gallery/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/gallery/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/compute/gallery/version.json create mode 100644 avm/1.1.0/res/compute/image/README.md create mode 100644 avm/1.1.0/res/compute/image/main.bicep create mode 100644 avm/1.1.0/res/compute/image/main.json create mode 100644 avm/1.1.0/res/compute/image/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/image/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/compute/image/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/image/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/compute/image/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/image/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/compute/image/version.json create mode 100644 avm/1.1.0/res/compute/proximity-placement-group/README.md create mode 100644 avm/1.1.0/res/compute/proximity-placement-group/main.bicep create mode 100644 avm/1.1.0/res/compute/proximity-placement-group/main.json create mode 100644 avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/compute/proximity-placement-group/version.json create mode 100644 avm/1.1.0/res/compute/ssh-public-key/README.md create mode 100644 avm/1.1.0/res/compute/ssh-public-key/main.bicep create mode 100644 avm/1.1.0/res/compute/ssh-public-key/main.json create mode 100644 avm/1.1.0/res/compute/ssh-public-key/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/compute/ssh-public-key/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/ssh-public-key/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/compute/ssh-public-key/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/ssh-public-key/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/compute/ssh-public-key/tests/unit/custom.tests.ps1 create mode 100644 avm/1.1.0/res/compute/ssh-public-key/version.json create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/README.md create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/extension/README.md create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/extension/main.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/extension/main.json create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/main.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/main.json create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.defaults/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.max/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.max/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.defaults/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine-scale-set/version.json create mode 100644 avm/1.1.0/res/compute/virtual-machine/README.md create mode 100644 avm/1.1.0/res/compute/virtual-machine/extension/README.md create mode 100644 avm/1.1.0/res/compute/virtual-machine/extension/main.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/extension/main.json create mode 100644 avm/1.1.0/res/compute/virtual-machine/main.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/main.json create mode 100644 avm/1.1.0/res/compute/virtual-machine/modules/nic-configuration.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/modules/protected-item.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/atmg/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/atmg/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.defaults/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.max/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.max/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.SSDv2/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.SSDv2/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.defaults/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.hostpool/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.hostpool/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.max/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.max/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.nvidia/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.ssecmk/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.ssecmk/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.vmss/dependencies.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep create mode 100644 avm/1.1.0/res/compute/virtual-machine/tests/unit/avm.core.team.tests.ps1 create mode 100644 avm/1.1.0/res/compute/virtual-machine/version.json create mode 100644 avm/1.1.0/res/desktop-virtualization/application-group/README.md create mode 100644 avm/1.1.0/res/desktop-virtualization/application-group/application/README.md create mode 100644 avm/1.1.0/res/desktop-virtualization/application-group/application/main.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/application-group/application/main.json create mode 100644 avm/1.1.0/res/desktop-virtualization/application-group/main.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/application-group/main.json create mode 100644 avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/application-group/version.json create mode 100644 avm/1.1.0/res/desktop-virtualization/host-pool/README.md create mode 100644 avm/1.1.0/res/desktop-virtualization/host-pool/main.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/host-pool/main.json create mode 100644 avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/host-pool/version.json create mode 100644 avm/1.1.0/res/desktop-virtualization/scaling-plan/README.md create mode 100644 avm/1.1.0/res/desktop-virtualization/scaling-plan/main.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/scaling-plan/main.json create mode 100644 avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/scaling-plan/version.json create mode 100644 avm/1.1.0/res/desktop-virtualization/workspace/README.md create mode 100644 avm/1.1.0/res/desktop-virtualization/workspace/main.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/workspace/main.json create mode 100644 avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/desktop-virtualization/workspace/version.json create mode 100644 avm/1.1.0/res/insights/action-group/README.md create mode 100644 avm/1.1.0/res/insights/action-group/main.bicep create mode 100644 avm/1.1.0/res/insights/action-group/main.json create mode 100644 avm/1.1.0/res/insights/action-group/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/insights/action-group/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/action-group/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/insights/action-group/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/action-group/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/insights/action-group/tests/unit/custom.tests.ps1 create mode 100644 avm/1.1.0/res/insights/action-group/version.json create mode 100644 avm/1.1.0/res/insights/activity-log-alert/README.md create mode 100644 avm/1.1.0/res/insights/activity-log-alert/main.bicep create mode 100644 avm/1.1.0/res/insights/activity-log-alert/main.json create mode 100644 avm/1.1.0/res/insights/activity-log-alert/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/insights/activity-log-alert/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/activity-log-alert/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/insights/activity-log-alert/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/activity-log-alert/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/insights/activity-log-alert/version.json create mode 100644 avm/1.1.0/res/insights/component/README.md create mode 100644 avm/1.1.0/res/insights/component/linkedStorageAccounts/README.md create mode 100644 avm/1.1.0/res/insights/component/linkedStorageAccounts/main.bicep create mode 100644 avm/1.1.0/res/insights/component/linkedStorageAccounts/main.json create mode 100644 avm/1.1.0/res/insights/component/main.bicep create mode 100644 avm/1.1.0/res/insights/component/main.json create mode 100644 avm/1.1.0/res/insights/component/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/component/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/insights/component/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/component/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/insights/component/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/component/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/insights/component/version.json create mode 100644 avm/1.1.0/res/insights/data-collection-endpoint/README.md create mode 100644 avm/1.1.0/res/insights/data-collection-endpoint/main.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-endpoint/main.json create mode 100644 avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-endpoint/version.json create mode 100644 avm/1.1.0/res/insights/data-collection-rule/README.md create mode 100644 avm/1.1.0/res/insights/data-collection-rule/main.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/main.json create mode 100644 avm/1.1.0/res/insights/data-collection-rule/modules/nested_conditionalScope.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/agent-settings/main.test.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customadv/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customadv/main.test.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/custombasic/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/custombasic/main.test.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customiis/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customiis/main.test.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/linux/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/linux/main.test.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/windows/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/tests/e2e/windows/main.test.bicep create mode 100644 avm/1.1.0/res/insights/data-collection-rule/version.json create mode 100644 avm/1.1.0/res/insights/diagnostic-setting/README.md create mode 100644 avm/1.1.0/res/insights/diagnostic-setting/main.bicep create mode 100644 avm/1.1.0/res/insights/diagnostic-setting/main.json create mode 100644 avm/1.1.0/res/insights/diagnostic-setting/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/insights/diagnostic-setting/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/insights/diagnostic-setting/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/insights/diagnostic-setting/version.json create mode 100644 avm/1.1.0/res/insights/metric-alert/README.md create mode 100644 avm/1.1.0/res/insights/metric-alert/main.bicep create mode 100644 avm/1.1.0/res/insights/metric-alert/main.json create mode 100644 avm/1.1.0/res/insights/metric-alert/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/metric-alert/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/insights/metric-alert/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/metric-alert/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/insights/metric-alert/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/metric-alert/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/insights/metric-alert/version.json create mode 100644 avm/1.1.0/res/insights/private-link-scope/README.md create mode 100644 avm/1.1.0/res/insights/private-link-scope/main.bicep create mode 100644 avm/1.1.0/res/insights/private-link-scope/main.json create mode 100644 avm/1.1.0/res/insights/private-link-scope/scoped-resource/README.md create mode 100644 avm/1.1.0/res/insights/private-link-scope/scoped-resource/main.bicep create mode 100644 avm/1.1.0/res/insights/private-link-scope/scoped-resource/main.json create mode 100644 avm/1.1.0/res/insights/private-link-scope/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/insights/private-link-scope/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/private-link-scope/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/insights/private-link-scope/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/private-link-scope/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/insights/private-link-scope/version.json create mode 100644 avm/1.1.0/res/insights/scheduled-query-rule/README.md create mode 100644 avm/1.1.0/res/insights/scheduled-query-rule/main.bicep create mode 100644 avm/1.1.0/res/insights/scheduled-query-rule/main.json create mode 100644 avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/insights/scheduled-query-rule/version.json create mode 100644 avm/1.1.0/res/insights/webtest/README.md create mode 100644 avm/1.1.0/res/insights/webtest/main.bicep create mode 100644 avm/1.1.0/res/insights/webtest/main.json create mode 100644 avm/1.1.0/res/insights/webtest/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/webtest/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/insights/webtest/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/webtest/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/insights/webtest/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/insights/webtest/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/insights/webtest/version.json create mode 100644 avm/1.1.0/res/key-vault/vault/README.md create mode 100644 avm/1.1.0/res/key-vault/vault/access-policy/README.md create mode 100644 avm/1.1.0/res/key-vault/vault/access-policy/main.bicep create mode 100644 avm/1.1.0/res/key-vault/vault/access-policy/main.json create mode 100644 avm/1.1.0/res/key-vault/vault/key/README.md create mode 100644 avm/1.1.0/res/key-vault/vault/key/main.bicep create mode 100644 avm/1.1.0/res/key-vault/vault/key/main.json create mode 100644 avm/1.1.0/res/key-vault/vault/main.bicep create mode 100644 avm/1.1.0/res/key-vault/vault/main.json create mode 100644 avm/1.1.0/res/key-vault/vault/secret/README.md create mode 100644 avm/1.1.0/res/key-vault/vault/secret/main.bicep create mode 100644 avm/1.1.0/res/key-vault/vault/secret/main.json create mode 100644 avm/1.1.0/res/key-vault/vault/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/key-vault/vault/tests/e2e/eckey/main.test.bicep create mode 100644 avm/1.1.0/res/key-vault/vault/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/key-vault/vault/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/key-vault/vault/tests/e2e/max/tests/connectivity.tests.ps1 create mode 100644 avm/1.1.0/res/key-vault/vault/tests/e2e/rsakey/main.test.bicep create mode 100644 avm/1.1.0/res/key-vault/vault/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/key-vault/vault/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/key-vault/vault/tests/unit/custom.tests.ps1 create mode 100644 avm/1.1.0/res/key-vault/vault/version.json create mode 100644 avm/1.1.0/res/managed-identity/user-assigned-identity/README.md create mode 100644 avm/1.1.0/res/managed-identity/user-assigned-identity/federated-identity-credential/README.md create mode 100644 avm/1.1.0/res/managed-identity/user-assigned-identity/federated-identity-credential/main.bicep create mode 100644 avm/1.1.0/res/managed-identity/user-assigned-identity/federated-identity-credential/main.json create mode 100644 avm/1.1.0/res/managed-identity/user-assigned-identity/main.bicep create mode 100644 avm/1.1.0/res/managed-identity/user-assigned-identity/main.json create mode 100644 avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/managed-identity/user-assigned-identity/tests/unit/custom.tests.ps1 create mode 100644 avm/1.1.0/res/managed-identity/user-assigned-identity/version.json create mode 100644 avm/1.1.0/res/net-app/net-app-account/README.md create mode 100644 avm/1.1.0/res/net-app/net-app-account/backup-policies/README.md create mode 100644 avm/1.1.0/res/net-app/net-app-account/backup-policies/main.bicep create mode 100644 avm/1.1.0/res/net-app/net-app-account/backup-policies/main.json create mode 100644 avm/1.1.0/res/net-app/net-app-account/backup-vault/README.md create mode 100644 avm/1.1.0/res/net-app/net-app-account/backup-vault/backup/README.md create mode 100644 avm/1.1.0/res/net-app/net-app-account/backup-vault/backup/main.bicep create mode 100644 avm/1.1.0/res/net-app/net-app-account/backup-vault/backup/main.json create mode 100644 avm/1.1.0/res/net-app/net-app-account/backup-vault/main.bicep create mode 100644 avm/1.1.0/res/net-app/net-app-account/backup-vault/main.json create mode 100644 avm/1.1.0/res/net-app/net-app-account/capacity-pool/README.md create mode 100644 avm/1.1.0/res/net-app/net-app-account/capacity-pool/main.bicep create mode 100644 avm/1.1.0/res/net-app/net-app-account/capacity-pool/main.json create mode 100644 avm/1.1.0/res/net-app/net-app-account/capacity-pool/volume/README.md create mode 100644 avm/1.1.0/res/net-app/net-app-account/capacity-pool/volume/main.bicep create mode 100644 avm/1.1.0/res/net-app/net-app-account/capacity-pool/volume/main.json create mode 100644 avm/1.1.0/res/net-app/net-app-account/main.bicep create mode 100644 avm/1.1.0/res/net-app/net-app-account/main.json create mode 100644 avm/1.1.0/res/net-app/net-app-account/snapshot-policies/README.md create mode 100644 avm/1.1.0/res/net-app/net-app-account/snapshot-policies/main.bicep create mode 100644 avm/1.1.0/res/net-app/net-app-account/snapshot-policies/main.json create mode 100644 avm/1.1.0/res/net-app/net-app-account/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/net-app/net-app-account/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/net-app/net-app-account/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/net-app/net-app-account/tests/e2e/nfs3/dependencies.bicep create mode 100644 avm/1.1.0/res/net-app/net-app-account/tests/e2e/nfs3/main.test.bicep create mode 100644 avm/1.1.0/res/net-app/net-app-account/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/net-app/net-app-account/version.json create mode 100644 avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/README.md create mode 100644 avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/main.bicep create mode 100644 avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/main.json create mode 100644 avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/version.json create mode 100644 avm/1.1.0/res/network/application-gateway/README.md create mode 100644 avm/1.1.0/res/network/application-gateway/main.bicep create mode 100644 avm/1.1.0/res/network/application-gateway/main.json create mode 100644 avm/1.1.0/res/network/application-gateway/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/application-gateway/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/application-gateway/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/application-gateway/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/application-gateway/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/application-gateway/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/application-gateway/version.json create mode 100644 avm/1.1.0/res/network/application-security-group/README.md create mode 100644 avm/1.1.0/res/network/application-security-group/main.bicep create mode 100644 avm/1.1.0/res/network/application-security-group/main.json create mode 100644 avm/1.1.0/res/network/application-security-group/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/application-security-group/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/application-security-group/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/application-security-group/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/application-security-group/version.json create mode 100644 avm/1.1.0/res/network/azure-firewall/README.md create mode 100644 avm/1.1.0/res/network/azure-firewall/main.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/main.json create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/addpip/dependencies.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/addpip/main.test.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/basic/dependencies.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/basic/main.test.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/custompip/dependencies.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/custompip/main.test.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/hubcommon/dependencies.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/hubcommon/main.test.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/hubmin/dependencies.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/hubmin/main.test.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/publicipprefix/dependencies.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/publicipprefix/main.test.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/azure-firewall/version.json create mode 100644 avm/1.1.0/res/network/bastion-host/README.md create mode 100644 avm/1.1.0/res/network/bastion-host/main.bicep create mode 100644 avm/1.1.0/res/network/bastion-host/main.json create mode 100644 avm/1.1.0/res/network/bastion-host/tests/e2e/custompip/dependencies.bicep create mode 100644 avm/1.1.0/res/network/bastion-host/tests/e2e/custompip/main.test.bicep create mode 100644 avm/1.1.0/res/network/bastion-host/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/bastion-host/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/bastion-host/tests/e2e/developer/dependencies.bicep create mode 100644 avm/1.1.0/res/network/bastion-host/tests/e2e/developer/main.test.bicep create mode 100644 avm/1.1.0/res/network/bastion-host/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/bastion-host/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/bastion-host/tests/e2e/private/dependencies.bicep create mode 100644 avm/1.1.0/res/network/bastion-host/tests/e2e/private/main.test.bicep create mode 100644 avm/1.1.0/res/network/bastion-host/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/bastion-host/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/bastion-host/version.json create mode 100644 avm/1.1.0/res/network/connection/README.md create mode 100644 avm/1.1.0/res/network/connection/main.bicep create mode 100644 avm/1.1.0/res/network/connection/main.json create mode 100644 avm/1.1.0/res/network/connection/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/connection/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/connection/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/connection/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/connection/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/connection/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/connection/version.json create mode 100644 avm/1.1.0/res/network/ddos-protection-plan/README.md create mode 100644 avm/1.1.0/res/network/ddos-protection-plan/main.bicep create mode 100644 avm/1.1.0/res/network/ddos-protection-plan/main.json create mode 100644 avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/ddos-protection-plan/version.json create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/README.md create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/forwarding-rule/README.md create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/forwarding-rule/main.bicep create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/forwarding-rule/main.json create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/main.bicep create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/main.json create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/version.json create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/virtual-network-link/README.md create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/virtual-network-link/main.bicep create mode 100644 avm/1.1.0/res/network/dns-forwarding-ruleset/virtual-network-link/main.json create mode 100644 avm/1.1.0/res/network/dns-resolver/README.md create mode 100644 avm/1.1.0/res/network/dns-resolver/inbound-endpoint/README.md create mode 100644 avm/1.1.0/res/network/dns-resolver/inbound-endpoint/main.bicep create mode 100644 avm/1.1.0/res/network/dns-resolver/inbound-endpoint/main.json create mode 100644 avm/1.1.0/res/network/dns-resolver/main.bicep create mode 100644 avm/1.1.0/res/network/dns-resolver/main.json create mode 100644 avm/1.1.0/res/network/dns-resolver/outbound-endpoint/README.md create mode 100644 avm/1.1.0/res/network/dns-resolver/outbound-endpoint/main.bicep create mode 100644 avm/1.1.0/res/network/dns-resolver/outbound-endpoint/main.json create mode 100644 avm/1.1.0/res/network/dns-resolver/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/dns-resolver/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/dns-resolver/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/dns-resolver/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/dns-resolver/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/dns-resolver/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/dns-resolver/tests/unit/custom.tests.ps1 create mode 100644 avm/1.1.0/res/network/dns-resolver/version.json create mode 100644 avm/1.1.0/res/network/dns-zone/README.md create mode 100644 avm/1.1.0/res/network/dns-zone/a/README.md create mode 100644 avm/1.1.0/res/network/dns-zone/a/main.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/a/main.json create mode 100644 avm/1.1.0/res/network/dns-zone/aaaa/README.md create mode 100644 avm/1.1.0/res/network/dns-zone/aaaa/main.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/aaaa/main.json create mode 100644 avm/1.1.0/res/network/dns-zone/caa/README.md create mode 100644 avm/1.1.0/res/network/dns-zone/caa/main.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/caa/main.json create mode 100644 avm/1.1.0/res/network/dns-zone/cname/README.md create mode 100644 avm/1.1.0/res/network/dns-zone/cname/main.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/cname/main.json create mode 100644 avm/1.1.0/res/network/dns-zone/main.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/main.json create mode 100644 avm/1.1.0/res/network/dns-zone/mx/README.md create mode 100644 avm/1.1.0/res/network/dns-zone/mx/main.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/mx/main.json create mode 100644 avm/1.1.0/res/network/dns-zone/ns/README.md create mode 100644 avm/1.1.0/res/network/dns-zone/ns/main.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/ns/main.json create mode 100644 avm/1.1.0/res/network/dns-zone/ptr/README.md create mode 100644 avm/1.1.0/res/network/dns-zone/ptr/main.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/ptr/main.json create mode 100644 avm/1.1.0/res/network/dns-zone/soa/README.md create mode 100644 avm/1.1.0/res/network/dns-zone/soa/main.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/soa/main.json create mode 100644 avm/1.1.0/res/network/dns-zone/srv/README.md create mode 100644 avm/1.1.0/res/network/dns-zone/srv/main.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/srv/main.json create mode 100644 avm/1.1.0/res/network/dns-zone/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/txt/README.md create mode 100644 avm/1.1.0/res/network/dns-zone/txt/main.bicep create mode 100644 avm/1.1.0/res/network/dns-zone/txt/main.json create mode 100644 avm/1.1.0/res/network/dns-zone/version.json create mode 100644 avm/1.1.0/res/network/express-route-circuit/README.md create mode 100644 avm/1.1.0/res/network/express-route-circuit/main.bicep create mode 100644 avm/1.1.0/res/network/express-route-circuit/main.json create mode 100644 avm/1.1.0/res/network/express-route-circuit/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/express-route-circuit/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/express-route-circuit/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/express-route-circuit/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/express-route-circuit/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/express-route-circuit/version.json create mode 100644 avm/1.1.0/res/network/express-route-gateway/README.md create mode 100644 avm/1.1.0/res/network/express-route-gateway/main.bicep create mode 100644 avm/1.1.0/res/network/express-route-gateway/main.json create mode 100644 avm/1.1.0/res/network/express-route-gateway/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/express-route-gateway/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/express-route-gateway/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/express-route-gateway/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/express-route-gateway/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/express-route-gateway/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/express-route-gateway/version.json create mode 100644 avm/1.1.0/res/network/express-route-port/README.md create mode 100644 avm/1.1.0/res/network/express-route-port/main.bicep create mode 100644 avm/1.1.0/res/network/express-route-port/main.json create mode 100644 avm/1.1.0/res/network/express-route-port/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/express-route-port/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/express-route-port/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/express-route-port/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/express-route-port/version.json create mode 100644 avm/1.1.0/res/network/firewall-policy/README.md create mode 100644 avm/1.1.0/res/network/firewall-policy/main.bicep create mode 100644 avm/1.1.0/res/network/firewall-policy/main.json create mode 100644 avm/1.1.0/res/network/firewall-policy/rule-collection-group/README.md create mode 100644 avm/1.1.0/res/network/firewall-policy/rule-collection-group/main.bicep create mode 100644 avm/1.1.0/res/network/firewall-policy/rule-collection-group/main.json create mode 100644 avm/1.1.0/res/network/firewall-policy/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/firewall-policy/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/firewall-policy/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/firewall-policy/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/firewall-policy/version.json create mode 100644 avm/1.1.0/res/network/front-door-web-application-firewall-policy/README.md create mode 100644 avm/1.1.0/res/network/front-door-web-application-firewall-policy/main.bicep create mode 100644 avm/1.1.0/res/network/front-door-web-application-firewall-policy/main.json create mode 100644 avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/front-door-web-application-firewall-policy/version.json create mode 100644 avm/1.1.0/res/network/front-door/README.md create mode 100644 avm/1.1.0/res/network/front-door/main.bicep create mode 100644 avm/1.1.0/res/network/front-door/main.json create mode 100644 avm/1.1.0/res/network/front-door/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/front-door/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/front-door/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/front-door/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/front-door/version.json create mode 100644 avm/1.1.0/res/network/ip-group/README.md create mode 100644 avm/1.1.0/res/network/ip-group/main.bicep create mode 100644 avm/1.1.0/res/network/ip-group/main.json create mode 100644 avm/1.1.0/res/network/ip-group/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/ip-group/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/ip-group/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/ip-group/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/ip-group/version.json create mode 100644 avm/1.1.0/res/network/load-balancer/README.md create mode 100644 avm/1.1.0/res/network/load-balancer/backend-address-pool/README.md create mode 100644 avm/1.1.0/res/network/load-balancer/backend-address-pool/main.bicep create mode 100644 avm/1.1.0/res/network/load-balancer/backend-address-pool/main.json create mode 100644 avm/1.1.0/res/network/load-balancer/inbound-nat-rule/README.md create mode 100644 avm/1.1.0/res/network/load-balancer/inbound-nat-rule/main.bicep create mode 100644 avm/1.1.0/res/network/load-balancer/inbound-nat-rule/main.json create mode 100644 avm/1.1.0/res/network/load-balancer/main.bicep create mode 100644 avm/1.1.0/res/network/load-balancer/main.json create mode 100644 avm/1.1.0/res/network/load-balancer/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/load-balancer/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/load-balancer/tests/e2e/external/dependencies.bicep create mode 100644 avm/1.1.0/res/network/load-balancer/tests/e2e/external/main.test.bicep create mode 100644 avm/1.1.0/res/network/load-balancer/tests/e2e/internal/dependencies.bicep create mode 100644 avm/1.1.0/res/network/load-balancer/tests/e2e/internal/main.test.bicep create mode 100644 avm/1.1.0/res/network/load-balancer/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/load-balancer/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/load-balancer/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/load-balancer/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/load-balancer/version.json create mode 100644 avm/1.1.0/res/network/local-network-gateway/README.md create mode 100644 avm/1.1.0/res/network/local-network-gateway/main.bicep create mode 100644 avm/1.1.0/res/network/local-network-gateway/main.json create mode 100644 avm/1.1.0/res/network/local-network-gateway/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/local-network-gateway/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/local-network-gateway/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/local-network-gateway/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/local-network-gateway/version.json create mode 100644 avm/1.1.0/res/network/nat-gateway/README.md create mode 100644 avm/1.1.0/res/network/nat-gateway/main.bicep create mode 100644 avm/1.1.0/res/network/nat-gateway/main.json create mode 100644 avm/1.1.0/res/network/nat-gateway/modules/formatResourceId.bicep create mode 100644 avm/1.1.0/res/network/nat-gateway/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/nat-gateway/tests/e2e/existingPip/dependencies.bicep create mode 100644 avm/1.1.0/res/network/nat-gateway/tests/e2e/existingPip/main.test.bicep create mode 100644 avm/1.1.0/res/network/nat-gateway/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/nat-gateway/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/nat-gateway/tests/e2e/prefixCombined/main.test.bicep create mode 100644 avm/1.1.0/res/network/nat-gateway/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/nat-gateway/tests/unit/avm.core.team.tests.ps1 create mode 100644 avm/1.1.0/res/network/nat-gateway/version.json create mode 100644 avm/1.1.0/res/network/network-interface/README.md create mode 100644 avm/1.1.0/res/network/network-interface/main.bicep create mode 100644 avm/1.1.0/res/network/network-interface/main.json create mode 100644 avm/1.1.0/res/network/network-interface/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/network-interface/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/network-interface/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/network-interface/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/network-interface/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/network-interface/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/network-interface/version.json create mode 100644 avm/1.1.0/res/network/network-manager/README.md create mode 100644 avm/1.1.0/res/network/network-manager/connectivity-configuration/README.md create mode 100644 avm/1.1.0/res/network/network-manager/connectivity-configuration/main.bicep create mode 100644 avm/1.1.0/res/network/network-manager/connectivity-configuration/main.json create mode 100644 avm/1.1.0/res/network/network-manager/main.bicep create mode 100644 avm/1.1.0/res/network/network-manager/main.json create mode 100644 avm/1.1.0/res/network/network-manager/network-group/README.md create mode 100644 avm/1.1.0/res/network/network-manager/network-group/main.bicep create mode 100644 avm/1.1.0/res/network/network-manager/network-group/main.json create mode 100644 avm/1.1.0/res/network/network-manager/network-group/static-member/README.md create mode 100644 avm/1.1.0/res/network/network-manager/network-group/static-member/main.bicep create mode 100644 avm/1.1.0/res/network/network-manager/network-group/static-member/main.json create mode 100644 avm/1.1.0/res/network/network-manager/routing-configuration/README.md create mode 100644 avm/1.1.0/res/network/network-manager/routing-configuration/main.bicep create mode 100644 avm/1.1.0/res/network/network-manager/routing-configuration/main.json create mode 100644 avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/README.md create mode 100644 avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/main.bicep create mode 100644 avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/main.json create mode 100644 avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/rule/README.md create mode 100644 avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/rule/main.bicep create mode 100644 avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/rule/main.json create mode 100644 avm/1.1.0/res/network/network-manager/scope-connection/README.md create mode 100644 avm/1.1.0/res/network/network-manager/scope-connection/main.bicep create mode 100644 avm/1.1.0/res/network/network-manager/scope-connection/main.json create mode 100644 avm/1.1.0/res/network/network-manager/security-admin-configuration/README.md create mode 100644 avm/1.1.0/res/network/network-manager/security-admin-configuration/main.bicep create mode 100644 avm/1.1.0/res/network/network-manager/security-admin-configuration/main.json create mode 100644 avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/README.md create mode 100644 avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/main.bicep create mode 100644 avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/main.json create mode 100644 avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/rule/README.md create mode 100644 avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/rule/main.bicep create mode 100644 avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/rule/main.json create mode 100644 avm/1.1.0/res/network/network-manager/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/network-manager/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/network-manager/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/network-manager/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/network-manager/version.json create mode 100644 avm/1.1.0/res/network/network-security-group/README.md create mode 100644 avm/1.1.0/res/network/network-security-group/main.bicep create mode 100644 avm/1.1.0/res/network/network-security-group/main.json create mode 100644 avm/1.1.0/res/network/network-security-group/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/network-security-group/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/network-security-group/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/network-security-group/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/network-security-group/version.json create mode 100644 avm/1.1.0/res/network/network-watcher/README.md create mode 100644 avm/1.1.0/res/network/network-watcher/connection-monitor/README.md create mode 100644 avm/1.1.0/res/network/network-watcher/connection-monitor/main.bicep create mode 100644 avm/1.1.0/res/network/network-watcher/connection-monitor/main.json create mode 100644 avm/1.1.0/res/network/network-watcher/flow-log/README.md create mode 100644 avm/1.1.0/res/network/network-watcher/flow-log/main.bicep create mode 100644 avm/1.1.0/res/network/network-watcher/flow-log/main.json create mode 100644 avm/1.1.0/res/network/network-watcher/main.bicep create mode 100644 avm/1.1.0/res/network/network-watcher/main.json create mode 100644 avm/1.1.0/res/network/network-watcher/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/network-watcher/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/network-watcher/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/network-watcher/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/network-watcher/version.json create mode 100644 avm/1.1.0/res/network/p2s-vpn-gateway/README.md create mode 100644 avm/1.1.0/res/network/p2s-vpn-gateway/main.bicep create mode 100644 avm/1.1.0/res/network/p2s-vpn-gateway/main.json create mode 100644 avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/p2s-vpn-gateway/version.json create mode 100644 avm/1.1.0/res/network/private-dns-zone/README.md create mode 100644 avm/1.1.0/res/network/private-dns-zone/a/README.md create mode 100644 avm/1.1.0/res/network/private-dns-zone/a/main.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/a/main.json create mode 100644 avm/1.1.0/res/network/private-dns-zone/aaaa/README.md create mode 100644 avm/1.1.0/res/network/private-dns-zone/aaaa/main.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/aaaa/main.json create mode 100644 avm/1.1.0/res/network/private-dns-zone/cname/README.md create mode 100644 avm/1.1.0/res/network/private-dns-zone/cname/main.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/cname/main.json create mode 100644 avm/1.1.0/res/network/private-dns-zone/main.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/main.json create mode 100644 avm/1.1.0/res/network/private-dns-zone/mx/README.md create mode 100644 avm/1.1.0/res/network/private-dns-zone/mx/main.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/mx/main.json create mode 100644 avm/1.1.0/res/network/private-dns-zone/ptr/README.md create mode 100644 avm/1.1.0/res/network/private-dns-zone/ptr/main.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/ptr/main.json create mode 100644 avm/1.1.0/res/network/private-dns-zone/soa/README.md create mode 100644 avm/1.1.0/res/network/private-dns-zone/soa/main.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/soa/main.json create mode 100644 avm/1.1.0/res/network/private-dns-zone/srv/README.md create mode 100644 avm/1.1.0/res/network/private-dns-zone/srv/main.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/srv/main.json create mode 100644 avm/1.1.0/res/network/private-dns-zone/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/txt/README.md create mode 100644 avm/1.1.0/res/network/private-dns-zone/txt/main.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/txt/main.json create mode 100644 avm/1.1.0/res/network/private-dns-zone/version.json create mode 100644 avm/1.1.0/res/network/private-dns-zone/virtual-network-link/README.md create mode 100644 avm/1.1.0/res/network/private-dns-zone/virtual-network-link/main.bicep create mode 100644 avm/1.1.0/res/network/private-dns-zone/virtual-network-link/main.json create mode 100644 avm/1.1.0/res/network/private-endpoint/README.md create mode 100644 avm/1.1.0/res/network/private-endpoint/main.bicep create mode 100644 avm/1.1.0/res/network/private-endpoint/main.json create mode 100644 avm/1.1.0/res/network/private-endpoint/private-dns-zone-group/README.md create mode 100644 avm/1.1.0/res/network/private-endpoint/private-dns-zone-group/main.bicep create mode 100644 avm/1.1.0/res/network/private-endpoint/private-dns-zone-group/main.json create mode 100644 avm/1.1.0/res/network/private-endpoint/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/private-endpoint/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/private-endpoint/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/private-endpoint/tests/e2e/private-link/dependencies.bicep create mode 100644 avm/1.1.0/res/network/private-endpoint/tests/e2e/private-link/main.test.bicep create mode 100644 avm/1.1.0/res/network/private-endpoint/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/private-endpoint/tests/unit/custom.tests.ps1 create mode 100644 avm/1.1.0/res/network/private-endpoint/version.json create mode 100644 avm/1.1.0/res/network/private-link-service/README.md create mode 100644 avm/1.1.0/res/network/private-link-service/main.bicep create mode 100644 avm/1.1.0/res/network/private-link-service/main.json create mode 100644 avm/1.1.0/res/network/private-link-service/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/private-link-service/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/private-link-service/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/private-link-service/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/private-link-service/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/private-link-service/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/private-link-service/version.json create mode 100644 avm/1.1.0/res/network/public-ip-address/README.md create mode 100644 avm/1.1.0/res/network/public-ip-address/main.bicep create mode 100644 avm/1.1.0/res/network/public-ip-address/main.json create mode 100644 avm/1.1.0/res/network/public-ip-address/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/public-ip-address/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/public-ip-address/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/public-ip-address/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/public-ip-address/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/public-ip-address/tests/unit/custom.tests.ps1 create mode 100644 avm/1.1.0/res/network/public-ip-address/version.json create mode 100644 avm/1.1.0/res/network/public-ip-prefix/README.md create mode 100644 avm/1.1.0/res/network/public-ip-prefix/main.bicep create mode 100644 avm/1.1.0/res/network/public-ip-prefix/main.json create mode 100644 avm/1.1.0/res/network/public-ip-prefix/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/public-ip-prefix/tests/e2e/ipv6/main.test.bicep create mode 100644 avm/1.1.0/res/network/public-ip-prefix/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/public-ip-prefix/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/public-ip-prefix/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/public-ip-prefix/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/public-ip-prefix/version.json create mode 100644 avm/1.1.0/res/network/route-table/README.md create mode 100644 avm/1.1.0/res/network/route-table/main.bicep create mode 100644 avm/1.1.0/res/network/route-table/main.json create mode 100644 avm/1.1.0/res/network/route-table/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/route-table/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/route-table/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/route-table/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/route-table/version.json create mode 100644 avm/1.1.0/res/network/service-endpoint-policy/README.md create mode 100644 avm/1.1.0/res/network/service-endpoint-policy/main.bicep create mode 100644 avm/1.1.0/res/network/service-endpoint-policy/main.json create mode 100644 avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/service-endpoint-policy/version.json create mode 100644 avm/1.1.0/res/network/trafficmanagerprofile/README.md create mode 100644 avm/1.1.0/res/network/trafficmanagerprofile/main.bicep create mode 100644 avm/1.1.0/res/network/trafficmanagerprofile/main.json create mode 100644 avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/trafficmanagerprofile/version.json create mode 100644 avm/1.1.0/res/network/virtual-hub/README.md create mode 100644 avm/1.1.0/res/network/virtual-hub/hub-route-table/README.md create mode 100644 avm/1.1.0/res/network/virtual-hub/hub-route-table/main.bicep create mode 100644 avm/1.1.0/res/network/virtual-hub/hub-route-table/main.json create mode 100644 avm/1.1.0/res/network/virtual-hub/hub-routing-intent/README.md create mode 100644 avm/1.1.0/res/network/virtual-hub/hub-routing-intent/main.bicep create mode 100644 avm/1.1.0/res/network/virtual-hub/hub-routing-intent/main.json create mode 100644 avm/1.1.0/res/network/virtual-hub/hub-virtual-network-connection/README.md create mode 100644 avm/1.1.0/res/network/virtual-hub/hub-virtual-network-connection/main.bicep create mode 100644 avm/1.1.0/res/network/virtual-hub/hub-virtual-network-connection/main.json create mode 100644 avm/1.1.0/res/network/virtual-hub/main.bicep create mode 100644 avm/1.1.0/res/network/virtual-hub/main.json create mode 100644 avm/1.1.0/res/network/virtual-hub/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-hub/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-hub/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-hub/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-hub/tests/e2e/routing-intent/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-hub/tests/e2e/routing-intent/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-hub/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-hub/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-hub/version.json create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/README.md create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/main.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/main.json create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/nat-rule/README.md create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/nat-rule/main.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/nat-rule/main.json create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/expressRoute/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network-gateway/version.json create mode 100644 avm/1.1.0/res/network/virtual-network/ORPHANED.md create mode 100644 avm/1.1.0/res/network/virtual-network/README.md create mode 100644 avm/1.1.0/res/network/virtual-network/main.bicep create mode 100644 avm/1.1.0/res/network/virtual-network/main.json create mode 100644 avm/1.1.0/res/network/virtual-network/subnet/README.md create mode 100644 avm/1.1.0/res/network/virtual-network/subnet/main.bicep create mode 100644 avm/1.1.0/res/network/virtual-network/subnet/main.json create mode 100644 avm/1.1.0/res/network/virtual-network/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network/tests/e2e/ipv6/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network/tests/e2e/vnetPeering/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network/tests/e2e/vnetPeering/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-network/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-network/version.json create mode 100644 avm/1.1.0/res/network/virtual-network/virtual-network-peering/README.md create mode 100644 avm/1.1.0/res/network/virtual-network/virtual-network-peering/main.bicep create mode 100644 avm/1.1.0/res/network/virtual-network/virtual-network-peering/main.json create mode 100644 avm/1.1.0/res/network/virtual-wan/README.md create mode 100644 avm/1.1.0/res/network/virtual-wan/main.bicep create mode 100644 avm/1.1.0/res/network/virtual-wan/main.json create mode 100644 avm/1.1.0/res/network/virtual-wan/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-wan/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-wan/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-wan/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/virtual-wan/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/virtual-wan/version.json create mode 100644 avm/1.1.0/res/network/vpn-gateway/README.md create mode 100644 avm/1.1.0/res/network/vpn-gateway/main.bicep create mode 100644 avm/1.1.0/res/network/vpn-gateway/main.json create mode 100644 avm/1.1.0/res/network/vpn-gateway/nat-rule/README.md create mode 100644 avm/1.1.0/res/network/vpn-gateway/nat-rule/main.bicep create mode 100644 avm/1.1.0/res/network/vpn-gateway/nat-rule/main.json create mode 100644 avm/1.1.0/res/network/vpn-gateway/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/vpn-gateway/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/vpn-gateway/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/vpn-gateway/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/vpn-gateway/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/vpn-gateway/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/vpn-gateway/version.json create mode 100644 avm/1.1.0/res/network/vpn-gateway/vpn-connection/README.md create mode 100644 avm/1.1.0/res/network/vpn-gateway/vpn-connection/main.bicep create mode 100644 avm/1.1.0/res/network/vpn-gateway/vpn-connection/main.json create mode 100644 avm/1.1.0/res/network/vpn-server-configuration/README.md create mode 100644 avm/1.1.0/res/network/vpn-server-configuration/main.bicep create mode 100644 avm/1.1.0/res/network/vpn-server-configuration/main.json create mode 100644 avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/vpn-server-configuration/version.json create mode 100644 avm/1.1.0/res/network/vpn-site/README.md create mode 100644 avm/1.1.0/res/network/vpn-site/main.bicep create mode 100644 avm/1.1.0/res/network/vpn-site/main.json create mode 100644 avm/1.1.0/res/network/vpn-site/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/network/vpn-site/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/network/vpn-site/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/network/vpn-site/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/network/vpn-site/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/network/vpn-site/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/network/vpn-site/version.json create mode 100644 avm/1.1.0/res/operational-insights/workspace/README.md create mode 100644 avm/1.1.0/res/operational-insights/workspace/data-export/README.md create mode 100644 avm/1.1.0/res/operational-insights/workspace/data-export/main.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/data-export/main.json create mode 100644 avm/1.1.0/res/operational-insights/workspace/data-source/README.md create mode 100644 avm/1.1.0/res/operational-insights/workspace/data-source/main.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/data-source/main.json create mode 100644 avm/1.1.0/res/operational-insights/workspace/linked-service/README.md create mode 100644 avm/1.1.0/res/operational-insights/workspace/linked-service/main.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/linked-service/main.json create mode 100644 avm/1.1.0/res/operational-insights/workspace/linked-storage-account/README.md create mode 100644 avm/1.1.0/res/operational-insights/workspace/linked-storage-account/main.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/linked-storage-account/main.json create mode 100644 avm/1.1.0/res/operational-insights/workspace/main.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/main.json create mode 100644 avm/1.1.0/res/operational-insights/workspace/saved-search/README.md create mode 100644 avm/1.1.0/res/operational-insights/workspace/saved-search/main.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/saved-search/main.json create mode 100644 avm/1.1.0/res/operational-insights/workspace/storage-insight-config/README.md create mode 100644 avm/1.1.0/res/operational-insights/workspace/storage-insight-config/main.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/storage-insight-config/main.json create mode 100644 avm/1.1.0/res/operational-insights/workspace/table/README.md create mode 100644 avm/1.1.0/res/operational-insights/workspace/table/main.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/table/main.json create mode 100644 avm/1.1.0/res/operational-insights/workspace/tests/e2e/adv/dependencies.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/tests/e2e/adv/main.test.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/operational-insights/workspace/version.json create mode 100644 avm/1.1.0/res/operations-management/solution/README.md create mode 100644 avm/1.1.0/res/operations-management/solution/main.bicep create mode 100644 avm/1.1.0/res/operations-management/solution/main.json create mode 100644 avm/1.1.0/res/operations-management/solution/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/operations-management/solution/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/operations-management/solution/tests/e2e/ms/dependencies.bicep create mode 100644 avm/1.1.0/res/operations-management/solution/tests/e2e/ms/main.test.bicep create mode 100644 avm/1.1.0/res/operations-management/solution/tests/e2e/nonms/dependencies.bicep create mode 100644 avm/1.1.0/res/operations-management/solution/tests/e2e/nonms/main.test.bicep create mode 100644 avm/1.1.0/res/operations-management/solution/tests/e2e/sql-auditing/dependencies.bicep create mode 100644 avm/1.1.0/res/operations-management/solution/tests/e2e/sql-auditing/main.test.bicep create mode 100644 avm/1.1.0/res/operations-management/solution/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/operations-management/solution/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/operations-management/solution/version.json create mode 100644 avm/1.1.0/res/resources/deployment-script/README.md create mode 100644 avm/1.1.0/res/resources/deployment-script/main.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/main.json create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/cli/dependencies.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/cli/main.test.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/private-endpoint/dependencies.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/private-endpoint/main.test.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/private-network/dependencies.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/private-network/main.test.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/ps/dependencies.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/ps/main.test.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/resources/deployment-script/version.json create mode 100644 avm/1.1.0/res/resources/resource-group/README.md create mode 100644 avm/1.1.0/res/resources/resource-group/main.bicep create mode 100644 avm/1.1.0/res/resources/resource-group/main.json create mode 100644 avm/1.1.0/res/resources/resource-group/modules/nested_lock.bicep create mode 100644 avm/1.1.0/res/resources/resource-group/modules/nested_roleAssignments.bicep create mode 100644 avm/1.1.0/res/resources/resource-group/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/resources/resource-group/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/resources/resource-group/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/resources/resource-group/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/resources/resource-group/version.json create mode 100644 avm/1.1.0/res/storage/storage-account/README.md create mode 100644 avm/1.1.0/res/storage/storage-account/blob-service/README.md create mode 100644 avm/1.1.0/res/storage/storage-account/blob-service/container/README.md create mode 100644 avm/1.1.0/res/storage/storage-account/blob-service/container/immutability-policy/README.md create mode 100644 avm/1.1.0/res/storage/storage-account/blob-service/container/immutability-policy/main.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/blob-service/container/immutability-policy/main.json create mode 100644 avm/1.1.0/res/storage/storage-account/blob-service/container/main.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/blob-service/container/main.json create mode 100644 avm/1.1.0/res/storage/storage-account/blob-service/main.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/blob-service/main.json create mode 100644 avm/1.1.0/res/storage/storage-account/file-service/README.md create mode 100644 avm/1.1.0/res/storage/storage-account/file-service/main.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/file-service/main.json create mode 100644 avm/1.1.0/res/storage/storage-account/file-service/share/README.md create mode 100644 avm/1.1.0/res/storage/storage-account/file-service/share/main.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/file-service/share/main.json create mode 100644 avm/1.1.0/res/storage/storage-account/file-service/share/modules/nested_inner_roleAssignment.json create mode 100644 avm/1.1.0/res/storage/storage-account/local-user/README.md create mode 100644 avm/1.1.0/res/storage/storage-account/local-user/main.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/local-user/main.json create mode 100644 avm/1.1.0/res/storage/storage-account/main.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/main.json create mode 100644 avm/1.1.0/res/storage/storage-account/management-policy/README.md create mode 100644 avm/1.1.0/res/storage/storage-account/management-policy/main.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/management-policy/main.json create mode 100644 avm/1.1.0/res/storage/storage-account/modules/keyVaultExport.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/queue-service/README.md create mode 100644 avm/1.1.0/res/storage/storage-account/queue-service/main.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/queue-service/main.json create mode 100644 avm/1.1.0/res/storage/storage-account/queue-service/queue/README.md create mode 100644 avm/1.1.0/res/storage/storage-account/queue-service/queue/main.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/queue-service/queue/main.json create mode 100644 avm/1.1.0/res/storage/storage-account/table-service/README.md create mode 100644 avm/1.1.0/res/storage/storage-account/table-service/main.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/table-service/main.json create mode 100644 avm/1.1.0/res/storage/storage-account/table-service/table/README.md create mode 100644 avm/1.1.0/res/storage/storage-account/table-service/table/main.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/table-service/table/main.json create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/blob/main.test.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/block/main.test.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/changefeed/main.test.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/kvSecrets/dependencies.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/kvSecrets/main.test.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/nfs/main.test.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/system-assigned-cmk-encryption/dependencies.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/system-assigned-cmk-encryption/main.test.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/user-assigned-cmk-encryption/main.test.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/v1/main.test.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/storage/storage-account/version.json create mode 100644 avm/1.1.0/res/virtual-machine-images/image-template/README.md create mode 100644 avm/1.1.0/res/virtual-machine-images/image-template/main.bicep create mode 100644 avm/1.1.0/res/virtual-machine-images/image-template/main.json create mode 100644 avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/defaults/main.test.bicep create mode 100644 avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/dependencies.bicep create mode 100644 avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/main.test.bicep create mode 100644 avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/src/Initialize-LinuxSoftware.ps1 create mode 100644 avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/src/Install-LinuxPowerShell.sh create mode 100644 avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/1.1.0/res/virtual-machine-images/image-template/version.json diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/README.md b/avm/1.1.0/ptn/authorization/policy-assignment/README.md new file mode 100644 index 000000000..72120281c --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/README.md @@ -0,0 +1,1424 @@ +# Policy Assignments (All scopes) `[Authorization/PolicyAssignment]` + +This module deploys a Policy Assignment at a Management Group, Subscription or Resource Group scope. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/policyAssignments` | [2022-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-06-01/policyAssignments) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/authorization/policy-assignment:`. + +- [Policy Assignments (Management Group scope)](#example-1-policy-assignments-management-group-scope) +- [Policy Assignments (Management Group scope)](#example-2-policy-assignments-management-group-scope) +- [Policy Assignments (Resource Group)](#example-3-policy-assignments-resource-group) +- [Policy Assignments (Resource Group)](#example-4-policy-assignments-resource-group) +- [Policy Assignments (Subscription)](#example-5-policy-assignments-subscription) +- [Policy Assignments (Subscription)](#example-6-policy-assignments-subscription) + +### Example 1: _Policy Assignments (Management Group scope)_ + +This module deploys a Policy Assignment at a Management Group scope using minimal parameters. + + +
+ +via Bicep module + +```bicep +module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:' = { + name: 'policyAssignmentDeployment' + params: { + // Required parameters + name: 'apamgmin001' + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + // Non-required parameters + location: '' + metadata: { + assignedBy: 'Bicep' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "apamgmin001" + }, + "policyDefinitionId": { + "value": "/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d" + }, + // Non-required parameters + "location": { + "value": "" + }, + "metadata": { + "value": { + "assignedBy": "Bicep" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-assignment:' + +// Required parameters +param name = 'apamgmin001' +param policyDefinitionId = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' +// Non-required parameters +param location = '' +param metadata = { + assignedBy: 'Bicep' +} +``` + +
+

+ +### Example 2: _Policy Assignments (Management Group scope)_ + +This module deploys a Policy Assignment at a Management Group scope using common parameters. + + +

+ +via Bicep module + +```bicep +module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:' = { + name: 'policyAssignmentDeployment' + params: { + // Required parameters + name: 'apamgmax001' + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' + // Non-required parameters + additionalManagementGroupsIDsToAssignRbacTo: [ + '' + ] + additionalResourceGroupResourceIDsToAssignRbacTo: [ + '' + ] + additionalSubscriptionIDsToAssignRbacTo: [ + '' + ] + description: '[Description] Policy Assignment at the management group scope' + displayName: '[Display Name] Policy Assignment at the management group scope' + enforcementMode: 'DoNotEnforce' + identity: 'SystemAssigned' + location: '' + managementGroupId: '' + metadata: { + assignedBy: 'Bicep' + category: 'Security' + version: '1.0' + } + nonComplianceMessages: [ + { + message: 'Violated Policy Assignment - This is a Non Compliance Message' + } + ] + notScopes: [ + '' + ] + overrides: [ + { + kind: 'policyEffect' + selectors: [ + { + in: [ + 'ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent' + 'ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent' + ] + kind: 'policyDefinitionReferenceId' + } + ] + value: 'Disabled' + } + ] + parameters: { + effect: { + value: 'Disabled' + } + enableCollectionOfSqlQueriesForSecurityResearch: { + value: false + } + } + resourceSelectors: [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } + ] + roleDefinitionIds: [ + '/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "apamgmax001" + }, + "policyDefinitionId": { + "value": "/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611" + }, + // Non-required parameters + "additionalManagementGroupsIDsToAssignRbacTo": { + "value": [ + "" + ] + }, + "additionalResourceGroupResourceIDsToAssignRbacTo": { + "value": [ + "" + ] + }, + "additionalSubscriptionIDsToAssignRbacTo": { + "value": [ + "" + ] + }, + "description": { + "value": "[Description] Policy Assignment at the management group scope" + }, + "displayName": { + "value": "[Display Name] Policy Assignment at the management group scope" + }, + "enforcementMode": { + "value": "DoNotEnforce" + }, + "identity": { + "value": "SystemAssigned" + }, + "location": { + "value": "" + }, + "managementGroupId": { + "value": "" + }, + "metadata": { + "value": { + "assignedBy": "Bicep", + "category": "Security", + "version": "1.0" + } + }, + "nonComplianceMessages": { + "value": [ + { + "message": "Violated Policy Assignment - This is a Non Compliance Message" + } + ] + }, + "notScopes": { + "value": [ + "" + ] + }, + "overrides": { + "value": [ + { + "kind": "policyEffect", + "selectors": [ + { + "in": [ + "ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent", + "ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent" + ], + "kind": "policyDefinitionReferenceId" + } + ], + "value": "Disabled" + } + ] + }, + "parameters": { + "value": { + "effect": { + "value": "Disabled" + }, + "enableCollectionOfSqlQueriesForSecurityResearch": { + "value": false + } + } + }, + "resourceSelectors": { + "value": [ + { + "name": "resourceSelector-test", + "selectors": [ + { + "in": [ + "Microsoft.Compute/virtualMachines" + ], + "kind": "resourceType" + }, + { + "in": [ + "westeurope" + ], + "kind": "resourceLocation" + } + ] + } + ] + }, + "roleDefinitionIds": { + "value": [ + "/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c" + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-assignment:' + +// Required parameters +param name = 'apamgmax001' +param policyDefinitionId = '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' +// Non-required parameters +param additionalManagementGroupsIDsToAssignRbacTo = [ + '' +] +param additionalResourceGroupResourceIDsToAssignRbacTo = [ + '' +] +param additionalSubscriptionIDsToAssignRbacTo = [ + '' +] +param description = '[Description] Policy Assignment at the management group scope' +param displayName = '[Display Name] Policy Assignment at the management group scope' +param enforcementMode = 'DoNotEnforce' +param identity = 'SystemAssigned' +param location = '' +param managementGroupId = '' +param metadata = { + assignedBy: 'Bicep' + category: 'Security' + version: '1.0' +} +param nonComplianceMessages = [ + { + message: 'Violated Policy Assignment - This is a Non Compliance Message' + } +] +param notScopes = [ + '' +] +param overrides = [ + { + kind: 'policyEffect' + selectors: [ + { + in: [ + 'ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent' + 'ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent' + ] + kind: 'policyDefinitionReferenceId' + } + ] + value: 'Disabled' + } +] +param parameters = { + effect: { + value: 'Disabled' + } + enableCollectionOfSqlQueriesForSecurityResearch: { + value: false + } +} +param resourceSelectors = [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } +] +param roleDefinitionIds = [ + '/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' +] +``` + +
+

+ +### Example 3: _Policy Assignments (Resource Group)_ + +This module deploys a Policy Assignment at a Resource Group scope using minimal parameters. + + +

+ +via Bicep module + +```bicep +module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:' = { + name: 'policyAssignmentDeployment' + params: { + // Required parameters + name: 'apargmin001' + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + // Non-required parameters + location: '' + metadata: { + assignedBy: 'Bicep' + } + resourceGroupName: '' + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "apargmin001" + }, + "policyDefinitionId": { + "value": "/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d" + }, + // Non-required parameters + "location": { + "value": "" + }, + "metadata": { + "value": { + "assignedBy": "Bicep" + } + }, + "resourceGroupName": { + "value": "" + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-assignment:' + +// Required parameters +param name = 'apargmin001' +param policyDefinitionId = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' +// Non-required parameters +param location = '' +param metadata = { + assignedBy: 'Bicep' +} +param resourceGroupName = '' +param subscriptionId = '' +``` + +
+

+ +### Example 4: _Policy Assignments (Resource Group)_ + +This module deploys a Policy Assignment at a Resource Group scope using common parameters. + + +

+ +via Bicep module + +```bicep +module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:' = { + name: 'policyAssignmentDeployment' + params: { + // Required parameters + name: 'apargmax001' + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' + // Non-required parameters + description: '[Description] Policy Assignment at the resource group scope' + displayName: '[Display Name] Policy Assignment at the resource group scope' + enforcementMode: 'DoNotEnforce' + identity: 'UserAssigned' + location: '' + metadata: { + assignedBy: 'Bicep' + category: 'Security' + version: '1.0' + } + nonComplianceMessages: [ + { + message: 'Violated Policy Assignment - This is a Non Compliance Message' + } + ] + notScopes: [ + '' + ] + overrides: [ + { + kind: 'policyEffect' + selectors: [ + { + in: [ + 'ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent' + 'ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent' + ] + kind: 'policyDefinitionReferenceId' + } + ] + value: 'Disabled' + } + ] + parameters: { + effect: { + value: 'Disabled' + } + enableCollectionOfSqlQueriesForSecurityResearch: { + value: false + } + } + resourceGroupName: '' + resourceSelectors: [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } + ] + roleDefinitionIds: [ + '/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + ] + subscriptionId: '' + userAssignedIdentityId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "apargmax001" + }, + "policyDefinitionId": { + "value": "/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611" + }, + // Non-required parameters + "description": { + "value": "[Description] Policy Assignment at the resource group scope" + }, + "displayName": { + "value": "[Display Name] Policy Assignment at the resource group scope" + }, + "enforcementMode": { + "value": "DoNotEnforce" + }, + "identity": { + "value": "UserAssigned" + }, + "location": { + "value": "" + }, + "metadata": { + "value": { + "assignedBy": "Bicep", + "category": "Security", + "version": "1.0" + } + }, + "nonComplianceMessages": { + "value": [ + { + "message": "Violated Policy Assignment - This is a Non Compliance Message" + } + ] + }, + "notScopes": { + "value": [ + "" + ] + }, + "overrides": { + "value": [ + { + "kind": "policyEffect", + "selectors": [ + { + "in": [ + "ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent", + "ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent" + ], + "kind": "policyDefinitionReferenceId" + } + ], + "value": "Disabled" + } + ] + }, + "parameters": { + "value": { + "effect": { + "value": "Disabled" + }, + "enableCollectionOfSqlQueriesForSecurityResearch": { + "value": false + } + } + }, + "resourceGroupName": { + "value": "" + }, + "resourceSelectors": { + "value": [ + { + "name": "resourceSelector-test", + "selectors": [ + { + "in": [ + "Microsoft.Compute/virtualMachines" + ], + "kind": "resourceType" + }, + { + "in": [ + "westeurope" + ], + "kind": "resourceLocation" + } + ] + } + ] + }, + "roleDefinitionIds": { + "value": [ + "/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c" + ] + }, + "subscriptionId": { + "value": "" + }, + "userAssignedIdentityId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-assignment:' + +// Required parameters +param name = 'apargmax001' +param policyDefinitionId = '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' +// Non-required parameters +param description = '[Description] Policy Assignment at the resource group scope' +param displayName = '[Display Name] Policy Assignment at the resource group scope' +param enforcementMode = 'DoNotEnforce' +param identity = 'UserAssigned' +param location = '' +param metadata = { + assignedBy: 'Bicep' + category: 'Security' + version: '1.0' +} +param nonComplianceMessages = [ + { + message: 'Violated Policy Assignment - This is a Non Compliance Message' + } +] +param notScopes = [ + '' +] +param overrides = [ + { + kind: 'policyEffect' + selectors: [ + { + in: [ + 'ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent' + 'ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent' + ] + kind: 'policyDefinitionReferenceId' + } + ] + value: 'Disabled' + } +] +param parameters = { + effect: { + value: 'Disabled' + } + enableCollectionOfSqlQueriesForSecurityResearch: { + value: false + } +} +param resourceGroupName = '' +param resourceSelectors = [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } +] +param roleDefinitionIds = [ + '/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' +] +param subscriptionId = '' +param userAssignedIdentityId = '' +``` + +
+

+ +### Example 5: _Policy Assignments (Subscription)_ + +This module deploys a Policy Assignment at a Subscription scope using common parameters. + + +

+ +via Bicep module + +```bicep +module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:' = { + name: 'policyAssignmentDeployment' + params: { + // Required parameters + name: 'apasubmin001' + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + // Non-required parameters + location: '' + metadata: { + assignedBy: 'Bicep' + category: 'Security' + version: '1.0' + } + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "apasubmin001" + }, + "policyDefinitionId": { + "value": "/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d" + }, + // Non-required parameters + "location": { + "value": "" + }, + "metadata": { + "value": { + "assignedBy": "Bicep", + "category": "Security", + "version": "1.0" + } + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-assignment:' + +// Required parameters +param name = 'apasubmin001' +param policyDefinitionId = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' +// Non-required parameters +param location = '' +param metadata = { + assignedBy: 'Bicep' + category: 'Security' + version: '1.0' +} +param subscriptionId = '' +``` + +
+

+ +### Example 6: _Policy Assignments (Subscription)_ + +This module deploys a Policy Assignment at a Subscription scope using common parameters. + + +

+ +via Bicep module + +```bicep +module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:' = { + name: 'policyAssignmentDeployment' + params: { + // Required parameters + name: 'apasubmax001' + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' + // Non-required parameters + description: '[Description] Policy Assignment at the subscription scope' + displayName: '[Display Name] Policy Assignment at the subscription scope' + enforcementMode: 'DoNotEnforce' + identity: 'UserAssigned' + location: '' + metadata: { + assignedBy: 'Bicep' + category: 'Security' + version: '1.0' + } + nonComplianceMessages: [ + { + message: 'Violated Policy Assignment - This is a Non Compliance Message' + } + ] + notScopes: [ + '/subscriptions//resourceGroups/validation-rg' + ] + overrides: [ + { + kind: 'policyEffect' + selectors: [ + { + in: [ + 'ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent' + 'ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent' + ] + kind: 'policyDefinitionReferenceId' + } + ] + value: 'Disabled' + } + ] + parameters: { + effect: { + value: 'Disabled' + } + enableCollectionOfSqlQueriesForSecurityResearch: { + value: false + } + } + resourceSelectors: [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } + ] + roleDefinitionIds: [ + '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + ] + subscriptionId: '' + userAssignedIdentityId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "apasubmax001" + }, + "policyDefinitionId": { + "value": "/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611" + }, + // Non-required parameters + "description": { + "value": "[Description] Policy Assignment at the subscription scope" + }, + "displayName": { + "value": "[Display Name] Policy Assignment at the subscription scope" + }, + "enforcementMode": { + "value": "DoNotEnforce" + }, + "identity": { + "value": "UserAssigned" + }, + "location": { + "value": "" + }, + "metadata": { + "value": { + "assignedBy": "Bicep", + "category": "Security", + "version": "1.0" + } + }, + "nonComplianceMessages": { + "value": [ + { + "message": "Violated Policy Assignment - This is a Non Compliance Message" + } + ] + }, + "notScopes": { + "value": [ + "/subscriptions//resourceGroups/validation-rg" + ] + }, + "overrides": { + "value": [ + { + "kind": "policyEffect", + "selectors": [ + { + "in": [ + "ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent", + "ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent" + ], + "kind": "policyDefinitionReferenceId" + } + ], + "value": "Disabled" + } + ] + }, + "parameters": { + "value": { + "effect": { + "value": "Disabled" + }, + "enableCollectionOfSqlQueriesForSecurityResearch": { + "value": false + } + } + }, + "resourceSelectors": { + "value": [ + { + "name": "resourceSelector-test", + "selectors": [ + { + "in": [ + "Microsoft.Compute/virtualMachines" + ], + "kind": "resourceType" + }, + { + "in": [ + "westeurope" + ], + "kind": "resourceLocation" + } + ] + } + ] + }, + "roleDefinitionIds": { + "value": [ + "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c" + ] + }, + "subscriptionId": { + "value": "" + }, + "userAssignedIdentityId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-assignment:' + +// Required parameters +param name = 'apasubmax001' +param policyDefinitionId = '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' +// Non-required parameters +param description = '[Description] Policy Assignment at the subscription scope' +param displayName = '[Display Name] Policy Assignment at the subscription scope' +param enforcementMode = 'DoNotEnforce' +param identity = 'UserAssigned' +param location = '' +param metadata = { + assignedBy: 'Bicep' + category: 'Security' + version: '1.0' +} +param nonComplianceMessages = [ + { + message: 'Violated Policy Assignment - This is a Non Compliance Message' + } +] +param notScopes = [ + '/subscriptions//resourceGroups/validation-rg' +] +param overrides = [ + { + kind: 'policyEffect' + selectors: [ + { + in: [ + 'ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent' + 'ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent' + ] + kind: 'policyDefinitionReferenceId' + } + ] + value: 'Disabled' + } +] +param parameters = { + effect: { + value: 'Disabled' + } + enableCollectionOfSqlQueriesForSecurityResearch: { + value: false + } +} +param resourceSelectors = [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } +] +param roleDefinitionIds = [ + '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' +] +param subscriptionId = '' +param userAssignedIdentityId = '' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope, 64 characters for subscription and resource group scopes. | +| [`policyDefinitionId`](#parameter-policydefinitionid) | string | Specifies the ID of the policy definition or policy set definition being assigned. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`additionalManagementGroupsIDsToAssignRbacTo`](#parameter-additionalmanagementgroupsidstoassignrbacto) | array | An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity. | +| [`additionalResourceGroupResourceIDsToAssignRbacTo`](#parameter-additionalresourcegroupresourceidstoassignrbacto) | array | An array of additional Resource Group Resource IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments. | +| [`additionalSubscriptionIDsToAssignRbacTo`](#parameter-additionalsubscriptionidstoassignrbacto) | array | An array of additional Subscription IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments. | +| [`description`](#parameter-description) | string | This message will be part of response in case of policy violation. | +| [`displayName`](#parameter-displayname) | string | The display name of the policy assignment. Maximum length is 128 characters. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`enforcementMode`](#parameter-enforcementmode) | string | The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce. | +| [`identity`](#parameter-identity) | string | The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`managementGroupId`](#parameter-managementgroupid) | string | The Target Scope for the Policy. The name of the management group for the policy assignment. If not provided, will use the current scope for deployment. | +| [`metadata`](#parameter-metadata) | object | The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs. | +| [`nonComplianceMessages`](#parameter-noncompliancemessages) | array | The messages that describe why a resource is non-compliant with the policy. | +| [`notScopes`](#parameter-notscopes) | array | The policy excluded scopes. | +| [`overrides`](#parameter-overrides) | array | The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition. | +| [`parameters`](#parameter-parameters) | object | Parameters for the policy assignment if needed. | +| [`resourceGroupName`](#parameter-resourcegroupname) | string | The Target Scope for the Policy. The name of the resource group for the policy assignment. | +| [`resourceSelectors`](#parameter-resourceselectors) | array | The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location. | +| [`roleDefinitionIds`](#parameter-roledefinitionids) | array | The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition. | +| [`subscriptionId`](#parameter-subscriptionid) | string | The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. | +| [`userAssignedIdentityId`](#parameter-userassignedidentityid) | string | The Resource ID for the user assigned identity to assign to the policy assignment. | + +### Parameter: `name` + +Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope, 64 characters for subscription and resource group scopes. + +- Required: Yes +- Type: string + +### Parameter: `policyDefinitionId` + +Specifies the ID of the policy definition or policy set definition being assigned. + +- Required: Yes +- Type: string + +### Parameter: `additionalManagementGroupsIDsToAssignRbacTo` + +An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `additionalResourceGroupResourceIDsToAssignRbacTo` + +An array of additional Resource Group Resource IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `additionalSubscriptionIDsToAssignRbacTo` + +An array of additional Subscription IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `description` + +This message will be part of response in case of policy violation. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `displayName` + +The display name of the policy assignment. Maximum length is 128 characters. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enforcementMode` + +The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce. + +- Required: No +- Type: string +- Default: `'Default'` +- Allowed: + ```Bicep + [ + 'Default' + 'DoNotEnforce' + ] + ``` + +### Parameter: `identity` + +The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions. + +- Required: No +- Type: string +- Default: `'SystemAssigned'` +- Allowed: + ```Bicep + [ + 'None' + 'SystemAssigned' + 'UserAssigned' + ] + ``` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[deployment().location]` + +### Parameter: `managementGroupId` + +The Target Scope for the Policy. The name of the management group for the policy assignment. If not provided, will use the current scope for deployment. + +- Required: No +- Type: string +- Default: `[managementGroup().name]` + +### Parameter: `metadata` + +The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `nonComplianceMessages` + +The messages that describe why a resource is non-compliant with the policy. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `notScopes` + +The policy excluded scopes. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `overrides` + +The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `parameters` + +Parameters for the policy assignment if needed. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `resourceGroupName` + +The Target Scope for the Policy. The name of the resource group for the policy assignment. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `resourceSelectors` + +The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `roleDefinitionIds` + +The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `subscriptionId` + +The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `userAssignedIdentityId` + +The Resource ID for the user assigned identity to assign to the policy assignment. + +- Required: No +- Type: string +- Default: `''` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | Policy Assignment Name. | +| `principalId` | string | Policy Assignment principal ID. | +| `resourceId` | string | Policy Assignment resource ID. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/main.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/main.bicep new file mode 100644 index 000000000..82cf2ddd5 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/main.bicep @@ -0,0 +1,204 @@ +metadata name = 'Policy Assignments (All scopes)' +metadata description = 'This module deploys a Policy Assignment at a Management Group, Subscription or Resource Group scope.' + +targetScope = 'managementGroup' + +@sys.description('Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope, 64 characters for subscription and resource group scopes.') +param name string + +@sys.description('Optional. This message will be part of response in case of policy violation.') +param description string = '' + +@sys.description('Optional. The display name of the policy assignment. Maximum length is 128 characters.') +@maxLength(128) +param displayName string = '' + +@sys.description('Required. Specifies the ID of the policy definition or policy set definition being assigned.') +param policyDefinitionId string + +@sys.description('Optional. Parameters for the policy assignment if needed.') +param parameters object = {} + +@sys.description('Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning \'Modify\' policy definitions.') +@allowed([ + 'SystemAssigned' + 'UserAssigned' + 'None' +]) +param identity string = 'SystemAssigned' + +@sys.description('Optional. The Resource ID for the user assigned identity to assign to the policy assignment.') +param userAssignedIdentityId string = '' + +@sys.description('Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') +param roleDefinitionIds array = [] + +@sys.description('Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs.') +param metadata object = {} + +@sys.description('Optional. The messages that describe why a resource is non-compliant with the policy.') +param nonComplianceMessages array = [] + +@sys.description('Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce.') +@allowed([ + 'Default' + 'DoNotEnforce' +]) +param enforcementMode string = 'Default' + +@sys.description('Optional. The Target Scope for the Policy. The name of the management group for the policy assignment. If not provided, will use the current scope for deployment.') +param managementGroupId string = managementGroup().name + +@sys.description('Optional. An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity.') +param additionalManagementGroupsIDsToAssignRbacTo array = [] + +@sys.description('Optional. An array of additional Subscription IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments.') +param additionalSubscriptionIDsToAssignRbacTo array = [] + +@sys.description('Optional. An array of additional Resource Group Resource IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments.') +param additionalResourceGroupResourceIDsToAssignRbacTo array = [] + +@sys.description('Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment.') +param subscriptionId string = '' + +@sys.description('Optional. The Target Scope for the Policy. The name of the resource group for the policy assignment.') +param resourceGroupName string = '' + +@sys.description('Optional. The policy excluded scopes.') +param notScopes array = [] + +@sys.description('Optional. Location for all resources.') +param location string = deployment().location + +@sys.description('Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition.') +param overrides array = [] + +@sys.description('Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location.') +param resourceSelectors array = [] + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.ptn.authorization-policyassignment.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + location: location + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +module policyAssignment_mg 'modules/management-group.bicep' = if (empty(subscriptionId) && empty(resourceGroupName)) { + name: '${uniqueString(deployment().name, location)}-PolicyAssignment-MG-Module' + scope: managementGroup(managementGroupId) + params: { + name: name + policyDefinitionId: policyDefinitionId + displayName: !empty(displayName) ? displayName : '' + description: !empty(description) ? description : '' + parameters: !empty(parameters) ? parameters : {} + identity: identity + userAssignedIdentityId: userAssignedIdentityId + roleDefinitionIds: !empty(roleDefinitionIds) ? roleDefinitionIds : [] + metadata: !empty(metadata) ? metadata : {} + nonComplianceMessages: !empty(nonComplianceMessages) ? nonComplianceMessages : [] + enforcementMode: enforcementMode + notScopes: !empty(notScopes) ? notScopes : [] + location: location + overrides: !empty(overrides) ? overrides : [] + resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : [] + additionalManagementGroupsIDsToAssignRbacTo: additionalManagementGroupsIDsToAssignRbacTo + additionalSubscriptionIDsToAssignRbacTo: additionalSubscriptionIDsToAssignRbacTo + additionalResourceGroupResourceIDsToAssignRbacTo: additionalResourceGroupResourceIDsToAssignRbacTo + } +} + +// Create additional role assignments at different management group scopes if needed + +module policyAssignment_sub 'modules/subscription.bicep' = if (!empty(subscriptionId) && empty(resourceGroupName)) { + name: '${uniqueString(deployment().name, location)}-PolicyAssignment-Sub-Module' + scope: subscription(subscriptionId) + params: { + name: name + policyDefinitionId: policyDefinitionId + displayName: !empty(displayName) ? displayName : '' + description: !empty(description) ? description : '' + parameters: !empty(parameters) ? parameters : {} + identity: identity + userAssignedIdentityId: userAssignedIdentityId + roleDefinitionIds: !empty(roleDefinitionIds) ? roleDefinitionIds : [] + metadata: !empty(metadata) ? metadata : {} + nonComplianceMessages: !empty(nonComplianceMessages) ? nonComplianceMessages : [] + enforcementMode: enforcementMode + notScopes: !empty(notScopes) ? notScopes : [] + subscriptionId: subscriptionId + location: location + overrides: !empty(overrides) ? overrides : [] + resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : [] + } +} + +module policyAssignment_rg 'modules/resource-group.bicep' = if (!empty(resourceGroupName) && !empty(subscriptionId)) { + name: '${uniqueString(deployment().name, location)}-PolicyAssignment-RG-Module' + scope: resourceGroup(subscriptionId, resourceGroupName) + params: { + name: name + policyDefinitionId: policyDefinitionId + displayName: !empty(displayName) ? displayName : '' + description: !empty(description) ? description : '' + parameters: !empty(parameters) ? parameters : {} + identity: identity + userAssignedIdentityId: userAssignedIdentityId + roleDefinitionIds: !empty(roleDefinitionIds) ? roleDefinitionIds : [] + metadata: !empty(metadata) ? metadata : {} + nonComplianceMessages: !empty(nonComplianceMessages) ? nonComplianceMessages : [] + enforcementMode: enforcementMode + notScopes: !empty(notScopes) ? notScopes : [] + subscriptionId: subscriptionId + location: location + overrides: !empty(overrides) ? overrides : [] + resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : [] + } +} + +@sys.description('Policy Assignment Name.') +output name string = empty(subscriptionId) && empty(resourceGroupName) + ? policyAssignment_mg.outputs.name + : (!empty(subscriptionId) && empty(resourceGroupName) + ? policyAssignment_sub.outputs.name + : policyAssignment_rg.outputs.name) + +@sys.description('Policy Assignment principal ID.') +output principalId string = empty(subscriptionId) && empty(resourceGroupName) + ? policyAssignment_mg.outputs.principalId + : (!empty(subscriptionId) && empty(resourceGroupName) + ? policyAssignment_sub.outputs.principalId + : policyAssignment_rg.outputs.principalId) + +@sys.description('Policy Assignment resource ID.') +output resourceId string = empty(subscriptionId) && empty(resourceGroupName) + ? policyAssignment_mg.outputs.resourceId + : (!empty(subscriptionId) && empty(resourceGroupName) + ? policyAssignment_sub.outputs.resourceId + : policyAssignment_rg.outputs.resourceId) + +@sys.description('The location the resource was deployed into.') +output location string = empty(subscriptionId) && empty(resourceGroupName) + ? policyAssignment_mg.outputs.location + : (!empty(subscriptionId) && empty(resourceGroupName) + ? policyAssignment_sub.outputs.location + : policyAssignment_rg.outputs.location) diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/main.json b/avm/1.1.0/ptn/authorization/policy-assignment/main.json new file mode 100644 index 000000000..eec410fdf --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/main.json @@ -0,0 +1,1492 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "18206582420908895315" + }, + "name": "Policy Assignments (All scopes)", + "description": "This module deploys a Policy Assignment at a Management Group, Subscription or Resource Group scope." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope, 64 characters for subscription and resource group scopes." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. This message will be part of response in case of policy violation." + } + }, + "displayName": { + "type": "string", + "defaultValue": "", + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy assignment. Maximum length is 128 characters." + } + }, + "policyDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the ID of the policy definition or policy set definition being assigned." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Parameters for the policy assignment if needed." + } + }, + "identity": { + "type": "string", + "defaultValue": "SystemAssigned", + "allowedValues": [ + "SystemAssigned", + "UserAssigned", + "None" + ], + "metadata": { + "description": "Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions." + } + }, + "userAssignedIdentityId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource ID for the user assigned identity to assign to the policy assignment." + } + }, + "roleDefinitionIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "nonComplianceMessages": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The messages that describe why a resource is non-compliant with the policy." + } + }, + "enforcementMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "DoNotEnforce" + ], + "metadata": { + "description": "Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce." + } + }, + "managementGroupId": { + "type": "string", + "defaultValue": "[managementGroup().name]", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The name of the management group for the policy assignment. If not provided, will use the current scope for deployment." + } + }, + "additionalManagementGroupsIDsToAssignRbacTo": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity." + } + }, + "additionalSubscriptionIDsToAssignRbacTo": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of additional Subscription IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments." + } + }, + "additionalResourceGroupResourceIDsToAssignRbacTo": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of additional Resource Group Resource IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The name of the resource group for the policy assignment." + } + }, + "notScopes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy excluded scopes." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "overrides": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition." + } + }, + "resourceSelectors": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.ptn.authorization-policyassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "location": "[parameters('location')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "condition": "[and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyAssignment-MG-Module', uniqueString(deployment().name, parameters('location')))]", + "scope": "[format('Microsoft.Management/managementGroups/{0}', parameters('managementGroupId'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "policyDefinitionId": { + "value": "[parameters('policyDefinitionId')]" + }, + "displayName": "[if(not(empty(parameters('displayName'))), createObject('value', parameters('displayName')), createObject('value', ''))]", + "description": "[if(not(empty(parameters('description'))), createObject('value', parameters('description')), createObject('value', ''))]", + "parameters": "[if(not(empty(parameters('parameters'))), createObject('value', parameters('parameters')), createObject('value', createObject()))]", + "identity": { + "value": "[parameters('identity')]" + }, + "userAssignedIdentityId": { + "value": "[parameters('userAssignedIdentityId')]" + }, + "roleDefinitionIds": "[if(not(empty(parameters('roleDefinitionIds'))), createObject('value', parameters('roleDefinitionIds')), createObject('value', createArray()))]", + "metadata": "[if(not(empty(parameters('metadata'))), createObject('value', parameters('metadata')), createObject('value', createObject()))]", + "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), createObject('value', parameters('nonComplianceMessages')), createObject('value', createArray()))]", + "enforcementMode": { + "value": "[parameters('enforcementMode')]" + }, + "notScopes": "[if(not(empty(parameters('notScopes'))), createObject('value', parameters('notScopes')), createObject('value', createArray()))]", + "location": { + "value": "[parameters('location')]" + }, + "overrides": "[if(not(empty(parameters('overrides'))), createObject('value', parameters('overrides')), createObject('value', createArray()))]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), createObject('value', parameters('resourceSelectors')), createObject('value', createArray()))]", + "additionalManagementGroupsIDsToAssignRbacTo": { + "value": "[parameters('additionalManagementGroupsIDsToAssignRbacTo')]" + }, + "additionalSubscriptionIDsToAssignRbacTo": { + "value": "[parameters('additionalSubscriptionIDsToAssignRbacTo')]" + }, + "additionalResourceGroupResourceIDsToAssignRbacTo": { + "value": "[parameters('additionalResourceGroupResourceIDsToAssignRbacTo')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10678509985815740940" + }, + "name": "Policy Assignments (Management Group scope)", + "description": "This module deploys a Policy Assignment at a Management Group scope." + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. This message will be part of response in case of policy violation." + } + }, + "displayName": { + "type": "string", + "defaultValue": "", + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy assignment. Maximum length is 128 characters." + } + }, + "policyDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the ID of the policy definition or policy set definition being assigned." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Parameters for the policy assignment if needed." + } + }, + "identity": { + "type": "string", + "defaultValue": "SystemAssigned", + "allowedValues": [ + "SystemAssigned", + "UserAssigned", + "None" + ], + "metadata": { + "description": "Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions." + } + }, + "userAssignedIdentityId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource ID for the user assigned identity to assign to the policy assignment." + } + }, + "roleDefinitionIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "additionalManagementGroupsIDsToAssignRbacTo": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity." + } + }, + "additionalSubscriptionIDsToAssignRbacTo": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of additional Subscription IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments." + } + }, + "additionalResourceGroupResourceIDsToAssignRbacTo": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of additional Resource Group Resource IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "nonComplianceMessages": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The messages that describe why a resource is non-compliant with the policy." + } + }, + "enforcementMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "DoNotEnforce" + ], + "metadata": { + "description": "Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce." + } + }, + "notScopes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy excluded scopes." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "overrides": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition." + } + }, + "resourceSelectors": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location." + } + } + }, + "variables": { + "identityVar": "[if(equals(parameters('identity'), 'SystemAssigned'), createObject('type', parameters('identity')), if(equals(parameters('identity'), 'UserAssigned'), createObject('type', parameters('identity'), 'userAssignedIdentities', createObject(format('{0}', parameters('userAssignedIdentityId')), createObject())), null()))]", + "finalArrayOfManagementGroupsToAssignRbacTo": "[if(equals(parameters('identity'), 'SystemAssigned'), union(parameters('additionalManagementGroupsIDsToAssignRbacTo'), createArray(managementGroup().name)), createArray())]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2022-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "policyDefinitionId": "[parameters('policyDefinitionId')]", + "parameters": "[parameters('parameters')]", + "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), parameters('nonComplianceMessages'), createArray())]", + "enforcementMode": "[parameters('enforcementMode')]", + "notScopes": "[if(not(empty(parameters('notScopes'))), parameters('notScopes'), createArray())]", + "overrides": "[if(not(empty(parameters('overrides'))), parameters('overrides'), createArray())]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), createArray())]" + }, + "identity": "[variables('identityVar')]" + }, + { + "copy": { + "name": "managementGroupRoleAssignments", + "count": "[length(parameters('roleDefinitionIds'))]" + }, + "condition": "[and(and(not(empty(parameters('roleDefinitionIds'))), not(empty(parameters('additionalManagementGroupsIDsToAssignRbacTo')))), equals(parameters('identity'), 'SystemAssigned'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyAssignment-MG-Module-Additional-RBAC', uniqueString(deployment().name, parameters('location'), parameters('roleDefinitionIds')[copyIndex()], parameters('name')))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "policyAssignmentIdentityId": { + "value": "[reference(extensionResourceId(managementGroup().id, 'Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]" + }, + "roleDefinitionId": { + "value": "[parameters('roleDefinitionIds')[copyIndex()]]" + }, + "managementGroupsIDsToAssignRbacTo": { + "value": "[variables('finalArrayOfManagementGroupsToAssignRbacTo')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9631038445585845349" + } + }, + "parameters": { + "managementGroupsIDsToAssignRbacTo": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope." + } + }, + "policyAssignmentIdentityId": { + "type": "string", + "metadata": { + "description": "Required. The managed identity principal ID associated with the policy assignment." + } + } + }, + "resources": [ + { + "copy": { + "name": "additionalManagementGroupRoleAssignmentsPerMG", + "count": "[length(parameters('managementGroupsIDsToAssignRbacTo'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyAssignment-MG-Module-Additional-RBAC', uniqueString(deployment().name, parameters('location'), parameters('roleDefinitionId'), parameters('name')))]", + "scope": "[format('Microsoft.Management/managementGroups/{0}', parameters('managementGroupsIDsToAssignRbacTo')[copyIndex()])]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "policyAssignmentIdentityId": { + "value": "[parameters('policyAssignmentIdentityId')]" + }, + "roleDefinitionId": { + "value": "[parameters('roleDefinitionId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9140403539470176881" + } + }, + "parameters": { + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope." + } + }, + "policyAssignmentIdentityId": { + "type": "string", + "metadata": { + "description": "Required. The managed identity principal ID associated with the policy assignment." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(managementGroup().id, parameters('roleDefinitionId'), parameters('location'), parameters('name'))]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('policyAssignmentIdentityId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(managementGroup().id, 'Microsoft.Authorization/policyAssignments', parameters('name'))]" + ] + }, + { + "copy": { + "name": "additionalSubscriptionRoleAssignments", + "count": "[length(parameters('roleDefinitionIds'))]" + }, + "condition": "[and(and(not(empty(parameters('roleDefinitionIds'))), not(empty(parameters('additionalSubscriptionIDsToAssignRbacTo')))), equals(parameters('identity'), 'SystemAssigned'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyAssignment-MG-Module-Additional-RBAC-Subs', uniqueString(deployment().name, parameters('location'), parameters('roleDefinitionIds')[copyIndex()], parameters('name')))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "policyAssignmentIdentityId": { + "value": "[reference(extensionResourceId(managementGroup().id, 'Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]" + }, + "roleDefinitionId": { + "value": "[parameters('roleDefinitionIds')[copyIndex()]]" + }, + "subscriptionIDsToAssignRbacTo": { + "value": "[parameters('additionalSubscriptionIDsToAssignRbacTo')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "5868976721767457523" + } + }, + "parameters": { + "subscriptionIDsToAssignRbacTo": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of additional Subscription IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope." + } + }, + "policyAssignmentIdentityId": { + "type": "string", + "metadata": { + "description": "Required. The managed identity principal ID associated with the policy assignment." + } + } + }, + "resources": [ + { + "copy": { + "name": "additionalSubscriptionRoleAssignmentsPerSub", + "count": "[length(parameters('subscriptionIDsToAssignRbacTo'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyAssignment-MG-Module-RBAC-Sub-{1}', uniqueString(deployment().name, parameters('location'), parameters('roleDefinitionId'), parameters('name')), substring(parameters('subscriptionIDsToAssignRbacTo')[copyIndex()], 0, 8))]", + "subscriptionId": "[parameters('subscriptionIDsToAssignRbacTo')[copyIndex()]]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "policyAssignmentIdentityId": { + "value": "[parameters('policyAssignmentIdentityId')]" + }, + "roleDefinitionId": { + "value": "[parameters('roleDefinitionId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "1856107527131838082" + } + }, + "parameters": { + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope." + } + }, + "policyAssignmentIdentityId": { + "type": "string", + "metadata": { + "description": "Required. The managed identity principal ID associated with the policy assignment." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(subscription().id, parameters('roleDefinitionId'), parameters('location'), parameters('name'))]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('policyAssignmentIdentityId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(managementGroup().id, 'Microsoft.Authorization/policyAssignments', parameters('name'))]" + ] + }, + { + "copy": { + "name": "additionalResourceGroupRoleAssignments", + "count": "[length(parameters('roleDefinitionIds'))]" + }, + "condition": "[and(and(not(empty(parameters('roleDefinitionIds'))), not(empty(parameters('additionalResourceGroupResourceIDsToAssignRbacTo')))), equals(parameters('identity'), 'SystemAssigned'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyAssignment-MG-Module-Additional-RBAC-RGs', uniqueString(deployment().name, parameters('location'), parameters('roleDefinitionIds')[copyIndex()], parameters('name')))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "policyAssignmentIdentityId": { + "value": "[reference(extensionResourceId(managementGroup().id, 'Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]" + }, + "roleDefinitionId": { + "value": "[parameters('roleDefinitionIds')[copyIndex()]]" + }, + "resourceGroupResourceIDsToAssignRbacTo": { + "value": "[parameters('additionalResourceGroupResourceIDsToAssignRbacTo')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12514251766635911763" + } + }, + "parameters": { + "resourceGroupResourceIDsToAssignRbacTo": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of additional Resource Group Resource IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope." + } + }, + "policyAssignmentIdentityId": { + "type": "string", + "metadata": { + "description": "Required. The managed identity principal ID associated with the policy assignment." + } + } + }, + "resources": [ + { + "copy": { + "name": "additionalResourceGroupResourceIDsRoleAssignmentsPerSub", + "count": "[length(parameters('resourceGroupResourceIDsToAssignRbacTo'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyAssignment-MG-Module-RBAC-RG-Sub-{1}', uniqueString(deployment().name, parameters('location'), parameters('roleDefinitionId'), parameters('name'), parameters('resourceGroupResourceIDsToAssignRbacTo')[copyIndex()]), substring(split(parameters('resourceGroupResourceIDsToAssignRbacTo')[copyIndex()], '/')[2], 0, 8))]", + "subscriptionId": "[split(parameters('resourceGroupResourceIDsToAssignRbacTo')[copyIndex()], '/')[2]]", + "resourceGroup": "[split(parameters('resourceGroupResourceIDsToAssignRbacTo')[copyIndex()], '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "policyAssignmentIdentityId": { + "value": "[parameters('policyAssignmentIdentityId')]" + }, + "roleDefinitionId": { + "value": "[parameters('roleDefinitionId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "11358116386111113340" + } + }, + "parameters": { + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope." + } + }, + "policyAssignmentIdentityId": { + "type": "string", + "metadata": { + "description": "Required. The managed identity principal ID associated with the policy assignment." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(resourceGroup().id, parameters('roleDefinitionId'), parameters('location'), parameters('name'))]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('policyAssignmentIdentityId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(managementGroup().id, 'Microsoft.Authorization/policyAssignments', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy Assignment Name." + }, + "value": "[parameters('name')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Policy Assignment principal ID." + }, + "value": "[coalesce(tryGet(tryGet(reference(extensionResourceId(managementGroup().id, 'Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Assignment resource ID." + }, + "value": "[extensionResourceId(managementGroup().id, 'Microsoft.Authorization/policyAssignments', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(extensionResourceId(managementGroup().id, 'Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyAssignment-Sub-Module', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[parameters('subscriptionId')]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "policyDefinitionId": { + "value": "[parameters('policyDefinitionId')]" + }, + "displayName": "[if(not(empty(parameters('displayName'))), createObject('value', parameters('displayName')), createObject('value', ''))]", + "description": "[if(not(empty(parameters('description'))), createObject('value', parameters('description')), createObject('value', ''))]", + "parameters": "[if(not(empty(parameters('parameters'))), createObject('value', parameters('parameters')), createObject('value', createObject()))]", + "identity": { + "value": "[parameters('identity')]" + }, + "userAssignedIdentityId": { + "value": "[parameters('userAssignedIdentityId')]" + }, + "roleDefinitionIds": "[if(not(empty(parameters('roleDefinitionIds'))), createObject('value', parameters('roleDefinitionIds')), createObject('value', createArray()))]", + "metadata": "[if(not(empty(parameters('metadata'))), createObject('value', parameters('metadata')), createObject('value', createObject()))]", + "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), createObject('value', parameters('nonComplianceMessages')), createObject('value', createArray()))]", + "enforcementMode": { + "value": "[parameters('enforcementMode')]" + }, + "notScopes": "[if(not(empty(parameters('notScopes'))), createObject('value', parameters('notScopes')), createObject('value', createArray()))]", + "subscriptionId": { + "value": "[parameters('subscriptionId')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "overrides": "[if(not(empty(parameters('overrides'))), createObject('value', parameters('overrides')), createObject('value', createArray()))]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), createObject('value', parameters('resourceSelectors')), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "2523227409976507857" + }, + "name": "Policy Assignments (Subscription scope)", + "description": "This module deploys a Policy Assignment at a Subscription scope." + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 64 characters for subscription scope." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. This message will be part of response in case of policy violation." + } + }, + "displayName": { + "type": "string", + "defaultValue": "", + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy assignment. Maximum length is 128 characters." + } + }, + "policyDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the ID of the policy definition or policy set definition being assigned." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Parameters for the policy assignment if needed." + } + }, + "identity": { + "type": "string", + "defaultValue": "SystemAssigned", + "allowedValues": [ + "SystemAssigned", + "UserAssigned", + "None" + ], + "metadata": { + "description": "Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions." + } + }, + "userAssignedIdentityId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource ID for the user assigned identity to assign to the policy assignment." + } + }, + "roleDefinitionIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "nonComplianceMessages": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The messages that describe why a resource is non-compliant with the policy." + } + }, + "enforcementMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "DoNotEnforce" + ], + "metadata": { + "description": "Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce." + } + }, + "notScopes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy excluded scopes." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "overrides": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition." + } + }, + "resourceSelectors": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment." + } + } + }, + "variables": { + "identityVar": "[if(equals(parameters('identity'), 'SystemAssigned'), createObject('type', parameters('identity')), if(equals(parameters('identity'), 'UserAssigned'), createObject('type', parameters('identity'), 'userAssignedIdentities', createObject(format('{0}', parameters('userAssignedIdentityId')), createObject())), null()))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2022-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "policyDefinitionId": "[parameters('policyDefinitionId')]", + "parameters": "[parameters('parameters')]", + "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), parameters('nonComplianceMessages'), createArray())]", + "enforcementMode": "[parameters('enforcementMode')]", + "notScopes": "[if(not(empty(parameters('notScopes'))), parameters('notScopes'), createArray())]", + "overrides": "[if(not(empty(parameters('overrides'))), parameters('overrides'), createArray())]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), createArray())]" + }, + "identity": "[variables('identityVar')]" + }, + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('roleDefinitionIds'))]" + }, + "condition": "[and(not(empty(parameters('roleDefinitionIds'))), equals(parameters('identity'), 'SystemAssigned'))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('roleDefinitionIds')[copyIndex()], parameters('location'), parameters('name'))]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionIds')[copyIndex()]]", + "principalId": "[reference(subscriptionResourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy Assignment Name." + }, + "value": "[parameters('name')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Policy Assignment principal ID." + }, + "value": "[coalesce(tryGet(tryGet(reference(subscriptionResourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Assignment resource ID." + }, + "value": "[subscriptionResourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(subscriptionResourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[and(not(empty(parameters('resourceGroupName'))), not(empty(parameters('subscriptionId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyAssignment-RG-Module', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "policyDefinitionId": { + "value": "[parameters('policyDefinitionId')]" + }, + "displayName": "[if(not(empty(parameters('displayName'))), createObject('value', parameters('displayName')), createObject('value', ''))]", + "description": "[if(not(empty(parameters('description'))), createObject('value', parameters('description')), createObject('value', ''))]", + "parameters": "[if(not(empty(parameters('parameters'))), createObject('value', parameters('parameters')), createObject('value', createObject()))]", + "identity": { + "value": "[parameters('identity')]" + }, + "userAssignedIdentityId": { + "value": "[parameters('userAssignedIdentityId')]" + }, + "roleDefinitionIds": "[if(not(empty(parameters('roleDefinitionIds'))), createObject('value', parameters('roleDefinitionIds')), createObject('value', createArray()))]", + "metadata": "[if(not(empty(parameters('metadata'))), createObject('value', parameters('metadata')), createObject('value', createObject()))]", + "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), createObject('value', parameters('nonComplianceMessages')), createObject('value', createArray()))]", + "enforcementMode": { + "value": "[parameters('enforcementMode')]" + }, + "notScopes": "[if(not(empty(parameters('notScopes'))), createObject('value', parameters('notScopes')), createObject('value', createArray()))]", + "subscriptionId": { + "value": "[parameters('subscriptionId')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "overrides": "[if(not(empty(parameters('overrides'))), createObject('value', parameters('overrides')), createObject('value', createArray()))]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), createObject('value', parameters('resourceSelectors')), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3323049503112762784" + }, + "name": "Policy Assignments (Resource Group scope)", + "description": "This module deploys a Policy Assignment at a Resource Group scope." + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 64 characters for resource group scope." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. This message will be part of response in case of policy violation." + } + }, + "displayName": { + "type": "string", + "defaultValue": "", + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy assignment. Maximum length is 128 characters." + } + }, + "policyDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the ID of the policy definition or policy set definition being assigned." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Parameters for the policy assignment if needed." + } + }, + "identity": { + "type": "string", + "defaultValue": "SystemAssigned", + "allowedValues": [ + "SystemAssigned", + "UserAssigned", + "None" + ], + "metadata": { + "description": "Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions." + } + }, + "userAssignedIdentityId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource ID for the user assigned identity to assign to the policy assignment." + } + }, + "roleDefinitionIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "nonComplianceMessages": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The messages that describe why a resource is non-compliant with the policy." + } + }, + "enforcementMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "DoNotEnforce" + ], + "metadata": { + "description": "Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce." + } + }, + "notScopes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy excluded scopes." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "overrides": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition." + } + }, + "resourceSelectors": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The name of the resource group for the policy assignment. If not provided, will use the current scope for deployment." + } + } + }, + "variables": { + "identityVar": "[if(equals(parameters('identity'), 'SystemAssigned'), createObject('type', parameters('identity')), if(equals(parameters('identity'), 'UserAssigned'), createObject('type', parameters('identity'), 'userAssignedIdentities', createObject(format('{0}', parameters('userAssignedIdentityId')), createObject())), null()))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2022-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "policyDefinitionId": "[parameters('policyDefinitionId')]", + "parameters": "[parameters('parameters')]", + "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), parameters('nonComplianceMessages'), createArray())]", + "enforcementMode": "[parameters('enforcementMode')]", + "notScopes": "[if(not(empty(parameters('notScopes'))), parameters('notScopes'), createArray())]", + "overrides": "[if(not(empty(parameters('overrides'))), parameters('overrides'), createArray())]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), createArray())]" + }, + "identity": "[variables('identityVar')]" + }, + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('roleDefinitionIds'))]" + }, + "condition": "[and(not(empty(parameters('roleDefinitionIds'))), equals(parameters('identity'), 'SystemAssigned'))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), parameters('roleDefinitionIds')[copyIndex()], parameters('location'), parameters('name'))]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionIds')[copyIndex()]]", + "principalId": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy Assignment Name." + }, + "value": "[parameters('name')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Policy Assignment principal ID." + }, + "value": "[coalesce(tryGet(tryGet(reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Assignment resource ID." + }, + "value": "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the policy was assigned to." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').location]" + } + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy Assignment Name." + }, + "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-MG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.name.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference(subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-Sub-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.name.value, reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.name.value))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Policy Assignment principal ID." + }, + "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-MG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.principalId.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference(subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-Sub-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.principalId.value, reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.principalId.value))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Assignment resource ID." + }, + "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-MG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.resourceId.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference(subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-Sub-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.resourceId.value, reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.resourceId.value))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-MG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.location.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference(subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-Sub-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.location.value, reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('{0}-PolicyAssignment-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.location.value))]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi-def-loop.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi-def-loop.bicep new file mode 100644 index 000000000..4e8d72092 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi-def-loop.bicep @@ -0,0 +1,29 @@ +targetScope = 'managementGroup' + +@sys.description('Optional. An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity.') +param managementGroupsIDsToAssignRbacTo array = [] + +@sys.description('Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') +param roleDefinitionId string + +@sys.description('Optional. Location for all resources.') +param location string = deployment().location + +@sys.description('Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope.') +@maxLength(24) +param name string + +@sys.description('Required. The managed identity principal ID associated with the policy assignment.') +param policyAssignmentIdentityId string + +module additionalManagementGroupRoleAssignmentsPerMG 'management-group-additional-rbac-asi.bicep' = [ + for mg in managementGroupsIDsToAssignRbacTo: { + name: '${uniqueString(deployment().name, location, roleDefinitionId, name)}-PolicyAssignment-MG-Module-Additional-RBAC' + scope: managementGroup(mg) + params: { + name: name + policyAssignmentIdentityId: policyAssignmentIdentityId + roleDefinitionId: roleDefinitionId + } + } +] diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi.bicep new file mode 100644 index 000000000..907f814f6 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/modules/management-group-additional-rbac-asi.bicep @@ -0,0 +1,23 @@ +targetScope = 'managementGroup' + +@sys.description('Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') +param roleDefinitionId string + +@sys.description('Optional. Location for all resources.') +param location string = deployment().location + +@sys.description('Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope.') +@maxLength(24) +param name string + +@sys.description('Required. The managed identity principal ID associated with the policy assignment.') +param policyAssignmentIdentityId string + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(managementGroup().id, roleDefinitionId, location, name) + properties: { + roleDefinitionId: roleDefinitionId + principalId: policyAssignmentIdentityId + principalType: 'ServicePrincipal' + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/modules/management-group.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/modules/management-group.bicep new file mode 100644 index 000000000..b2cb06c8e --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/modules/management-group.bicep @@ -0,0 +1,152 @@ +metadata name = 'Policy Assignments (Management Group scope)' +metadata description = 'This module deploys a Policy Assignment at a Management Group scope.' + +targetScope = 'managementGroup' + +@sys.description('Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope.') +@maxLength(24) +param name string + +@sys.description('Optional. This message will be part of response in case of policy violation.') +param description string = '' + +@sys.description('Optional. The display name of the policy assignment. Maximum length is 128 characters.') +@maxLength(128) +param displayName string = '' + +@sys.description('Required. Specifies the ID of the policy definition or policy set definition being assigned.') +param policyDefinitionId string + +@sys.description('Optional. Parameters for the policy assignment if needed.') +param parameters object = {} + +@sys.description('Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning \'Modify\' policy definitions.') +@allowed([ + 'SystemAssigned' + 'UserAssigned' + 'None' +]) +param identity string = 'SystemAssigned' + +@sys.description('Optional. The Resource ID for the user assigned identity to assign to the policy assignment.') +param userAssignedIdentityId string = '' + +@sys.description('Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') +param roleDefinitionIds array = [] + +@sys.description('Optional. An array of additional management group IDs to assign RBAC to for the policy assignment if it has an identity.') +param additionalManagementGroupsIDsToAssignRbacTo array = [] + +@sys.description('Optional. An array of additional Subscription IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments.') +param additionalSubscriptionIDsToAssignRbacTo array = [] + +@sys.description('Optional. An array of additional Resource Group Resource IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments.') +param additionalResourceGroupResourceIDsToAssignRbacTo array = [] + +@sys.description('Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs.') +param metadata object = {} + +@sys.description('Optional. The messages that describe why a resource is non-compliant with the policy.') +param nonComplianceMessages array = [] + +@sys.description('Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce.') +@allowed([ + 'Default' + 'DoNotEnforce' +]) +param enforcementMode string = 'Default' + +@sys.description('Optional. The policy excluded scopes.') +param notScopes array = [] + +@sys.description('Optional. Location for all resources.') +param location string = deployment().location + +@sys.description('Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition.') +param overrides array = [] + +@sys.description('Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location.') +param resourceSelectors array = [] + +var identityVar = identity == 'SystemAssigned' + ? { + type: identity + } + : identity == 'UserAssigned' + ? { + type: identity + userAssignedIdentities: { + '${userAssignedIdentityId}': {} + } + } + : null + +var finalArrayOfManagementGroupsToAssignRbacTo = identity == 'SystemAssigned' + ? union(additionalManagementGroupsIDsToAssignRbacTo, [managementGroup().name]) + : [] + +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2022-06-01' = { + name: name + location: location + properties: { + displayName: !empty(displayName) ? displayName : null + metadata: !empty(metadata) ? metadata : null + description: !empty(description) ? description : null + policyDefinitionId: policyDefinitionId + parameters: parameters + nonComplianceMessages: !empty(nonComplianceMessages) ? nonComplianceMessages : [] + enforcementMode: enforcementMode + notScopes: !empty(notScopes) ? notScopes : [] + overrides: !empty(overrides) ? overrides : [] + resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : [] + } + identity: identityVar +} + +module managementGroupRoleAssignments 'management-group-additional-rbac-asi-def-loop.bicep' = [ + for roleDefinitionId in roleDefinitionIds: if (!empty(roleDefinitionIds) && !empty(additionalManagementGroupsIDsToAssignRbacTo) && identity == 'SystemAssigned') { + name: '${uniqueString(deployment().name, location, roleDefinitionId, name)}-PolicyAssignment-MG-Module-Additional-RBAC' + params: { + name: name + policyAssignmentIdentityId: policyAssignment.identity.principalId + roleDefinitionId: roleDefinitionId + managementGroupsIDsToAssignRbacTo: finalArrayOfManagementGroupsToAssignRbacTo + } + } +] + +module additionalSubscriptionRoleAssignments 'subscription-additional-rbac-asi-def-loop.bicep' = [ + for roleDefinitionId in roleDefinitionIds: if (!empty(roleDefinitionIds) && !empty(additionalSubscriptionIDsToAssignRbacTo) && identity == 'SystemAssigned') { + name: '${uniqueString(deployment().name, location, roleDefinitionId, name)}-PolicyAssignment-MG-Module-Additional-RBAC-Subs' + params: { + name: name + policyAssignmentIdentityId: policyAssignment.identity.principalId + roleDefinitionId: roleDefinitionId + subscriptionIDsToAssignRbacTo: additionalSubscriptionIDsToAssignRbacTo + } + } +] + +module additionalResourceGroupRoleAssignments 'resource-group-additional-rbac-asi-def-loop.bicep' = [ + for roleDefinitionId in roleDefinitionIds: if (!empty(roleDefinitionIds) && !empty(additionalResourceGroupResourceIDsToAssignRbacTo) && identity == 'SystemAssigned') { + name: '${uniqueString(deployment().name, location, roleDefinitionId, name)}-PolicyAssignment-MG-Module-Additional-RBAC-RGs' + params: { + name: name + policyAssignmentIdentityId: policyAssignment.identity.principalId + roleDefinitionId: roleDefinitionId + resourceGroupResourceIDsToAssignRbacTo: additionalResourceGroupResourceIDsToAssignRbacTo + } + } +] + +@sys.description('Policy Assignment Name.') +output name string = policyAssignment.name + +@sys.description('Policy Assignment principal ID.') +output principalId string = policyAssignment.?identity.?principalId ?? '' + +@sys.description('Policy Assignment resource ID.') +output resourceId string = policyAssignment.id + +@sys.description('The location the resource was deployed into.') +output location string = policyAssignment.location diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/modules/resource-group-additional-rbac-asi-def-loop.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/modules/resource-group-additional-rbac-asi-def-loop.bicep new file mode 100644 index 000000000..77e778fd0 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/modules/resource-group-additional-rbac-asi-def-loop.bicep @@ -0,0 +1,29 @@ +targetScope = 'managementGroup' + +@sys.description('Optional. An array of additional Resource Group Resource IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments.') +param resourceGroupResourceIDsToAssignRbacTo array = [] + +@sys.description('Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') +param roleDefinitionId string + +@sys.description('Optional. Location for all resources.') +param location string = deployment().location + +@sys.description('Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope.') +@maxLength(24) +param name string + +@sys.description('Required. The managed identity principal ID associated with the policy assignment.') +param policyAssignmentIdentityId string + +module additionalResourceGroupResourceIDsRoleAssignmentsPerSub 'resource-group-additional-rbac-asi.bicep' = [ + for rg in resourceGroupResourceIDsToAssignRbacTo: { + name: '${uniqueString(deployment().name, location, roleDefinitionId, name, rg)}-PolicyAssignment-MG-Module-RBAC-RG-Sub-${substring(split(rg, '/')[2], 0, 8)}' + scope: resourceGroup(split(rg, '/')[2], split(rg, '/')[4]) + params: { + name: name + policyAssignmentIdentityId: policyAssignmentIdentityId + roleDefinitionId: roleDefinitionId + } + } +] diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/modules/resource-group-additional-rbac-asi.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/modules/resource-group-additional-rbac-asi.bicep new file mode 100644 index 000000000..120f0aa0d --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/modules/resource-group-additional-rbac-asi.bicep @@ -0,0 +1,21 @@ +@sys.description('Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') +param roleDefinitionId string + +@sys.description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@sys.description('Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope.') +@maxLength(24) +param name string + +@sys.description('Required. The managed identity principal ID associated with the policy assignment.') +param policyAssignmentIdentityId string + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, roleDefinitionId, location, name) + properties: { + roleDefinitionId: roleDefinitionId + principalId: policyAssignmentIdentityId + principalType: 'ServicePrincipal' + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/modules/resource-group.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/modules/resource-group.bicep new file mode 100644 index 000000000..c224e4b2e --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/modules/resource-group.bicep @@ -0,0 +1,123 @@ +metadata name = 'Policy Assignments (Resource Group scope)' +metadata description = 'This module deploys a Policy Assignment at a Resource Group scope.' + +targetScope = 'resourceGroup' + +@sys.description('Required. Specifies the name of the policy assignment. Maximum length is 64 characters for resource group scope.') +@maxLength(64) +param name string + +@sys.description('Optional. This message will be part of response in case of policy violation.') +param description string = '' + +@sys.description('Optional. The display name of the policy assignment. Maximum length is 128 characters.') +@maxLength(128) +param displayName string = '' + +@sys.description('Required. Specifies the ID of the policy definition or policy set definition being assigned.') +param policyDefinitionId string + +@sys.description('Optional. Parameters for the policy assignment if needed.') +param parameters object = {} + +@sys.description('Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning \'Modify\' policy definitions.') +@allowed([ + 'SystemAssigned' + 'UserAssigned' + 'None' +]) +param identity string = 'SystemAssigned' + +@sys.description('Optional. The Resource ID for the user assigned identity to assign to the policy assignment.') +param userAssignedIdentityId string = '' + +@sys.description('Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') +param roleDefinitionIds array = [] + +@sys.description('Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs.') +param metadata object = {} + +@sys.description('Optional. The messages that describe why a resource is non-compliant with the policy.') +param nonComplianceMessages array = [] + +@sys.description('Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce.') +@allowed([ + 'Default' + 'DoNotEnforce' +]) +param enforcementMode string = 'Default' + +@sys.description('Optional. The policy excluded scopes.') +param notScopes array = [] + +@sys.description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@sys.description('Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition.') +param overrides array = [] + +@sys.description('Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location.') +param resourceSelectors array = [] + +@sys.description('Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment.') +param subscriptionId string = subscription().subscriptionId + +@sys.description('Optional. The Target Scope for the Policy. The name of the resource group for the policy assignment. If not provided, will use the current scope for deployment.') +param resourceGroupName string = resourceGroup().name + +var identityVar = identity == 'SystemAssigned' + ? { + type: identity + } + : identity == 'UserAssigned' + ? { + type: identity + userAssignedIdentities: { + '${userAssignedIdentityId}': {} + } + } + : null + +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2022-06-01' = { + name: name + location: location + properties: { + displayName: !empty(displayName) ? displayName : null + metadata: !empty(metadata) ? metadata : null + description: !empty(description) ? description : null + policyDefinitionId: policyDefinitionId + parameters: parameters + nonComplianceMessages: !empty(nonComplianceMessages) ? nonComplianceMessages : [] + enforcementMode: enforcementMode + notScopes: !empty(notScopes) ? notScopes : [] + overrides: !empty(overrides) ? overrides : [] + resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : [] + } + identity: identityVar +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for roleDefinitionId in roleDefinitionIds: if (!empty(roleDefinitionIds) && identity == 'SystemAssigned') { + name: guid(subscriptionId, resourceGroupName, roleDefinitionId, location, name) + properties: { + roleDefinitionId: roleDefinitionId + principalId: policyAssignment.identity.principalId + principalType: 'ServicePrincipal' + } + } +] + +@sys.description('Policy Assignment Name.') +output name string = policyAssignment.name + +@sys.description('Policy Assignment principal ID.') +output principalId string = policyAssignment.?identity.?principalId ?? '' + +@sys.description('Policy Assignment resource ID.') +output resourceId string = policyAssignment.id + +@sys.description('The name of the resource group the policy was assigned to.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The location the resource was deployed into.') +output location string = policyAssignment.location diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/modules/subscription-additional-rbac-asi-def-loop.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/modules/subscription-additional-rbac-asi-def-loop.bicep new file mode 100644 index 000000000..89576ed7f --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/modules/subscription-additional-rbac-asi-def-loop.bicep @@ -0,0 +1,29 @@ +targetScope = 'managementGroup' + +@sys.description('Optional. An array of additional Subscription IDs to assign RBAC to for the policy assignment if it has an identity, only supported for Management Group Policy Assignments.') +param subscriptionIDsToAssignRbacTo array = [] + +@sys.description('Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') +param roleDefinitionId string + +@sys.description('Optional. Location for all resources.') +param location string = deployment().location + +@sys.description('Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope.') +@maxLength(24) +param name string + +@sys.description('Required. The managed identity principal ID associated with the policy assignment.') +param policyAssignmentIdentityId string + +module additionalSubscriptionRoleAssignmentsPerSub 'subscription-additional-rbac-asi.bicep' = [ + for sub in subscriptionIDsToAssignRbacTo: { + name: '${uniqueString(deployment().name, location, roleDefinitionId, name)}-PolicyAssignment-MG-Module-RBAC-Sub-${substring(sub, 0, 8)}' + scope: subscription(sub) + params: { + name: name + policyAssignmentIdentityId: policyAssignmentIdentityId + roleDefinitionId: roleDefinitionId + } + } +] diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/modules/subscription-additional-rbac-asi.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/modules/subscription-additional-rbac-asi.bicep new file mode 100644 index 000000000..fb980fa24 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/modules/subscription-additional-rbac-asi.bicep @@ -0,0 +1,23 @@ +targetScope = 'subscription' + +@sys.description('Required. The ID Of the Azure Role Definition that is used to assign permissions to the identity. You need to provide the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') +param roleDefinitionId string + +@sys.description('Optional. Location for all resources.') +param location string = deployment().location + +@sys.description('Required. Specifies the name of the policy assignment. Maximum length is 24 characters for management group scope.') +@maxLength(24) +param name string + +@sys.description('Required. The managed identity principal ID associated with the policy assignment.') +param policyAssignmentIdentityId string + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().id, roleDefinitionId, location, name) + properties: { + roleDefinitionId: roleDefinitionId + principalId: policyAssignmentIdentityId + principalType: 'ServicePrincipal' + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/modules/subscription.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/modules/subscription.bicep new file mode 100644 index 000000000..504251e1a --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/modules/subscription.bicep @@ -0,0 +1,117 @@ +metadata name = 'Policy Assignments (Subscription scope)' +metadata description = 'This module deploys a Policy Assignment at a Subscription scope.' + +targetScope = 'subscription' + +@sys.description('Required. Specifies the name of the policy assignment. Maximum length is 64 characters for subscription scope.') +@maxLength(64) +param name string + +@sys.description('Optional. This message will be part of response in case of policy violation.') +param description string = '' + +@sys.description('Optional. The display name of the policy assignment. Maximum length is 128 characters.') +@maxLength(128) +param displayName string = '' + +@sys.description('Required. Specifies the ID of the policy definition or policy set definition being assigned.') +param policyDefinitionId string + +@sys.description('Optional. Parameters for the policy assignment if needed.') +param parameters object = {} + +@sys.description('Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning \'Modify\' policy definitions.') +@allowed([ + 'SystemAssigned' + 'UserAssigned' + 'None' +]) +param identity string = 'SystemAssigned' + +@sys.description('Optional. The Resource ID for the user assigned identity to assign to the policy assignment.') +param userAssignedIdentityId string = '' + +@sys.description('Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition.') +param roleDefinitionIds array = [] + +@sys.description('Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs.') +param metadata object = {} + +@sys.description('Optional. The messages that describe why a resource is non-compliant with the policy.') +param nonComplianceMessages array = [] + +@sys.description('Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce.') +@allowed([ + 'Default' + 'DoNotEnforce' +]) +param enforcementMode string = 'Default' + +@sys.description('Optional. The policy excluded scopes.') +param notScopes array = [] + +@sys.description('Optional. Location for all resources.') +param location string = deployment().location + +@sys.description('Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition.') +param overrides array = [] + +@sys.description('Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location.') +param resourceSelectors array = [] + +@sys.description('Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment.') +param subscriptionId string = subscription().subscriptionId + +var identityVar = identity == 'SystemAssigned' + ? { + type: identity + } + : identity == 'UserAssigned' + ? { + type: identity + userAssignedIdentities: { + '${userAssignedIdentityId}': {} + } + } + : null + +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2022-06-01' = { + name: name + location: location + properties: { + displayName: !empty(displayName) ? displayName : null + metadata: !empty(metadata) ? metadata : null + description: !empty(description) ? description : null + policyDefinitionId: policyDefinitionId + parameters: parameters + nonComplianceMessages: !empty(nonComplianceMessages) ? nonComplianceMessages : [] + enforcementMode: enforcementMode + notScopes: !empty(notScopes) ? notScopes : [] + overrides: !empty(overrides) ? overrides : [] + resourceSelectors: !empty(resourceSelectors) ? resourceSelectors : [] + } + identity: identityVar +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for roleDefinitionId in roleDefinitionIds: if (!empty(roleDefinitionIds) && identity == 'SystemAssigned') { + name: guid(subscriptionId, roleDefinitionId, location, name) + properties: { + roleDefinitionId: roleDefinitionId + principalId: policyAssignment.identity.principalId + principalType: 'ServicePrincipal' + } + } +] + +@sys.description('Policy Assignment Name.') +output name string = policyAssignment.name + +@sys.description('Policy Assignment principal ID.') +output principalId string = policyAssignment.?identity.?principalId ?? '' + +@sys.description('Policy Assignment resource ID.') +output resourceId string = policyAssignment.id + +@sys.description('The location the resource was deployed into.') +output location string = policyAssignment.location diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/mg.defaults/main.test.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/mg.defaults/main.test.bicep new file mode 100644 index 000000000..2c043ce04 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/mg.defaults/main.test.bicep @@ -0,0 +1,33 @@ +targetScope = 'managementGroup' +metadata name = 'Policy Assignments (Management Group scope)' +metadata description = 'This module deploys a Policy Assignment at a Management Group scope using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apamgmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + //Audit VMs that do not use managed disks + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + metadata: { + assignedBy: 'Bicep' + } + location: resourceLocation + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/mg.max/main.test.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/mg.max/main.test.bicep new file mode 100644 index 000000000..b91afcf08 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/mg.max/main.test.bicep @@ -0,0 +1,127 @@ +targetScope = 'managementGroup' +metadata name = 'Policy Assignments (Management Group scope)' +metadata description = 'This module deploys a Policy Assignment at a Management Group scope using common parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apamgmax' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.policyassignments-${serviceShort}-rg' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +resource additionalMg 'Microsoft.Management/managementGroups@2023-04-01' = { + scope: tenant() + name: '${uniqueString(deployment().name)}-additional-mg' +} + +module additionalRsg 'br/public:avm/res/resources/resource-group:0.4.0' = { + scope: subscription(subscriptionId) + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: resourceGroupName + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + //Configure Azure Defender for SQL agents on virtual machines + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' + description: '[Description] Policy Assignment at the management group scope' + displayName: '[Display Name] Policy Assignment at the management group scope' + enforcementMode: 'DoNotEnforce' + identity: 'SystemAssigned' + location: resourceLocation + managementGroupId: last(split(managementGroup().id, '/')) + additionalManagementGroupsIDsToAssignRbacTo: [ + additionalMg.name + ] + additionalSubscriptionIDsToAssignRbacTo: [ + subscriptionId + ] + additionalResourceGroupResourceIDsToAssignRbacTo: [ + additionalRsg.outputs.resourceId + ] + metadata: { + category: 'Security' + version: '1.0' + assignedBy: 'Bicep' + } + nonComplianceMessages: [ + { + message: 'Violated Policy Assignment - This is a Non Compliance Message' + } + ] + notScopes: [ + additionalRsg.outputs.resourceId + ] + parameters: { + enableCollectionOfSqlQueriesForSecurityResearch: { + value: false + } + effect: { + value: 'Disabled' + } + } + roleDefinitionIds: [ + '/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor role + ] + overrides: [ + { + kind: 'policyEffect' + value: 'Disabled' + selectors: [ + { + kind: 'policyDefinitionReferenceId' + in: [ + 'ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent' + 'ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent' + ] + } + ] + } + ] + resourceSelectors: [ + { + name: 'resourceSelector-test' + selectors: [ + { + kind: 'resourceType' + in: [ + 'Microsoft.Compute/virtualMachines' + ] + } + { + kind: 'resourceLocation' + in: [ + 'westeurope' + ] + } + ] + } + ] + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/rg.defaults/main.test.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/rg.defaults/main.test.bicep new file mode 100644 index 000000000..35c19bbb5 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/rg.defaults/main.test.bicep @@ -0,0 +1,57 @@ +targetScope = 'managementGroup' +metadata name = 'Policy Assignments (Resource Group)' +metadata description = 'This module deploys a Policy Assignment at a Resource Group scope using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.policyassignments-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apargmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. Subscription ID of the subscription to assign the RBAC role to. If no Resource Group name is provided, the module deploys at subscription level, therefore assigns the provided RBAC role to the subscription.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +module resourceGroup 'br/public:avm/res/resources/resource-group:0.2.3' = { + scope: subscription('${subscriptionId}') + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: resourceGroupName + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + //Audit VMs that do not use managed disks + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + metadata: { + assignedBy: 'Bicep' + } + location: resourceLocation + resourceGroupName: resourceGroup.outputs.name + subscriptionId: subscriptionId + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/rg.max/dependencies.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/rg.max/dependencies.bicep new file mode 100644 index 000000000..f4151d61c --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/rg.max/dependencies.bicep @@ -0,0 +1,33 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + accessPolicies: [] + } +} + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/rg.max/main.test.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/rg.max/main.test.bicep new file mode 100644 index 000000000..811113851 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/rg.max/main.test.bicep @@ -0,0 +1,130 @@ +targetScope = 'managementGroup' +metadata name = 'Policy Assignments (Resource Group)' +metadata description = 'This module deploys a Policy Assignment at a Resource Group scope using common parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.policyassignments-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apargmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. Subscription ID of the subscription to assign the RBAC role to. If no Resource Group name is provided, the module deploys at subscription level, therefore assigns the provided RBAC role to the subscription.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +module resourceGroup 'br/public:avm/res/resources/resource-group:0.2.3' = { + scope: subscription('${subscriptionId}') + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: resourceGroupName + location: resourceLocation + } +} + +module nestedDependencies 'dependencies.bicep' = { + scope: az.resourceGroup(subscriptionId, resourceGroupName) + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + location: resourceLocation + } + dependsOn: [ + resourceGroup + ] +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + //Configure Azure Defender for SQL agents on virtual machines + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' + description: '[Description] Policy Assignment at the resource group scope' + displayName: '[Display Name] Policy Assignment at the resource group scope' + enforcementMode: 'DoNotEnforce' + identity: 'UserAssigned' + location: resourceLocation + metadata: { + category: 'Security' + version: '1.0' + assignedBy: 'Bicep' + } + nonComplianceMessages: [ + { + message: 'Violated Policy Assignment - This is a Non Compliance Message' + } + ] + notScopes: [ + nestedDependencies.outputs.keyVaultResourceId + ] + parameters: { + enableCollectionOfSqlQueriesForSecurityResearch: { + value: false + } + effect: { + value: 'Disabled' + } + } + resourceGroupName: resourceGroup.outputs.name + roleDefinitionIds: [ + '/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + ] + overrides: [ + { + kind: 'policyEffect' + value: 'Disabled' + selectors: [ + { + kind: 'policyDefinitionReferenceId' + in: [ + 'ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent' + 'ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent' + ] + } + ] + } + ] + resourceSelectors: [ + { + name: 'resourceSelector-test' + selectors: [ + { + kind: 'resourceType' + in: [ + 'Microsoft.Compute/virtualMachines' + ] + } + { + kind: 'resourceLocation' + in: [ + 'westeurope' + ] + } + ] + } + ] + subscriptionId: subscriptionId + userAssignedIdentityId: nestedDependencies.outputs.managedIdentityResourceId + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/sub.defaults/main.test.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/sub.defaults/main.test.bicep new file mode 100644 index 000000000..74fef4437 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/sub.defaults/main.test.bicep @@ -0,0 +1,39 @@ +targetScope = 'managementGroup' +metadata name = 'Policy Assignments (Subscription)' +metadata description = 'This module deploys a Policy Assignment at a Subscription scope using common parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apasubmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment.') +param subscriptionId string = '#_subscriptionId_#' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + //Audit VMs that do not use managed disks + policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' + subscriptionId: subscriptionId + metadata: { + category: 'Security' + version: '1.0' + assignedBy: 'Bicep' + } + location: resourceLocation + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/sub.max/dependencies.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/sub.max/dependencies.bicep new file mode 100644 index 000000000..71b8f3cee --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/sub.max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/sub.max/main.test.bicep b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/sub.max/main.test.bicep new file mode 100644 index 000000000..c9a60a551 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/tests/e2e/sub.max/main.test.bicep @@ -0,0 +1,128 @@ +targetScope = 'managementGroup' +metadata name = 'Policy Assignments (Subscription)' +metadata description = 'This module deploys a Policy Assignment at a Subscription scope using common parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.policyassignments-${serviceShort}-rg' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apasubmax' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +module resourceGroup 'br/public:avm/res/resources/resource-group:0.2.3' = { + scope: subscription('${subscriptionId}') + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: resourceGroupName + location: resourceLocation + } +} + +module nestedDependencies 'dependencies.bicep' = { + scope: az.resourceGroup(subscriptionId, resourceGroupName) + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } + dependsOn: [ + resourceGroup + ] +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + //Configure Azure Defender for SQL agents on virtual machines + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' + description: '[Description] Policy Assignment at the subscription scope' + displayName: '[Display Name] Policy Assignment at the subscription scope' + enforcementMode: 'DoNotEnforce' + identity: 'UserAssigned' + location: resourceLocation + metadata: { + category: 'Security' + version: '1.0' + assignedBy: 'Bicep' + } + nonComplianceMessages: [ + { + message: 'Violated Policy Assignment - This is a Non Compliance Message' + } + ] + notScopes: [ + '/subscriptions/${subscriptionId}/resourceGroups/validation-rg' + ] + parameters: { + enableCollectionOfSqlQueriesForSecurityResearch: { + value: false + } + effect: { + value: 'Disabled' + } + } + roleDefinitionIds: [ + '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + ] + overrides: [ + { + kind: 'policyEffect' + value: 'Disabled' + selectors: [ + { + kind: 'policyDefinitionReferenceId' + in: [ + 'ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent' + 'ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent' + ] + } + ] + } + ] + resourceSelectors: [ + { + name: 'resourceSelector-test' + selectors: [ + { + kind: 'resourceType' + in: [ + 'Microsoft.Compute/virtualMachines' + ] + } + { + kind: 'resourceLocation' + in: [ + 'westeurope' + ] + } + ] + } + ] + subscriptionId: subscriptionId + userAssignedIdentityId: nestedDependencies.outputs.managedIdentityResourceId + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-assignment/version.json b/avm/1.1.0/ptn/authorization/policy-assignment/version.json new file mode 100644 index 000000000..76049e1c4 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-assignment/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/ptn/authorization/policy-exemption/README.md b/avm/1.1.0/ptn/authorization/policy-exemption/README.md new file mode 100644 index 000000000..a5ed50b79 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-exemption/README.md @@ -0,0 +1,933 @@ +# Policy Exemptions (All scopes) `[Authorization/PolicyExemption]` + +This module deploys a Policy Exemption at a Management Group, Subscription or Resource Group scope. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/policyExemptions` | [2022-07-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-07-01-preview/policyExemptions) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/authorization/policy-exemption:`. + +- [Policy Exemptions (Management Group scope)](#example-1-policy-exemptions-management-group-scope) +- [Policy Exemptions (Management Group scope)](#example-2-policy-exemptions-management-group-scope) +- [Policy Exemption (Resource Group)](#example-3-policy-exemption-resource-group) +- [Policy Exemption (Resource Group)](#example-4-policy-exemption-resource-group) +- [Policy Exemption (Subscription)](#example-5-policy-exemption-subscription) +- [Policy Exemption (Subscription)](#example-6-policy-exemption-subscription) + +### Example 1: _Policy Exemptions (Management Group scope)_ + +This module deploys a Policy Exemption at a Management Group scope using minimal parameters. + + +

+ +via Bicep module + +```bicep +module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' = { + name: 'policyExemptionDeployment' + params: { + // Required parameters + exemptionCategory: 'Mitigated' + name: 'apemgmin001' + policyAssignmentId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "exemptionCategory": { + "value": "Mitigated" + }, + "name": { + "value": "apemgmin001" + }, + "policyAssignmentId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-exemption:' + +// Required parameters +param exemptionCategory = 'Mitigated' +param name = 'apemgmin001' +param policyAssignmentId = '' +``` + +
+

+ +### Example 2: _Policy Exemptions (Management Group scope)_ + +This module deploys a Policy Exemption at a Management Group scope using common parameters. + + +

+ +via Bicep module + +```bicep +module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' = { + name: 'policyExemptionDeployment' + params: { + // Required parameters + exemptionCategory: 'Mitigated' + name: 'apemgmax001' + policyAssignmentId: '' + // Non-required parameters + assignmentScopeValidation: 'Default' + description: '[Description] Policy Exemption at the management group scope' + displayName: '[DisplayName] Policy Exemption at the management group scope' + enableTelemetry: true + location: '' + managementGroupId: '' + metadata: { + assignedBy: 'Bicep' + category: 'Security' + } + resourceSelectors: [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "exemptionCategory": { + "value": "Mitigated" + }, + "name": { + "value": "apemgmax001" + }, + "policyAssignmentId": { + "value": "" + }, + // Non-required parameters + "assignmentScopeValidation": { + "value": "Default" + }, + "description": { + "value": "[Description] Policy Exemption at the management group scope" + }, + "displayName": { + "value": "[DisplayName] Policy Exemption at the management group scope" + }, + "enableTelemetry": { + "value": true + }, + "location": { + "value": "" + }, + "managementGroupId": { + "value": "" + }, + "metadata": { + "value": { + "assignedBy": "Bicep", + "category": "Security" + } + }, + "resourceSelectors": { + "value": [ + { + "name": "resourceSelector-test", + "selectors": [ + { + "in": [ + "Microsoft.Compute/virtualMachines" + ], + "kind": "resourceType" + }, + { + "in": [ + "westeurope" + ], + "kind": "resourceLocation" + } + ] + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-exemption:' + +// Required parameters +param exemptionCategory = 'Mitigated' +param name = 'apemgmax001' +param policyAssignmentId = '' +// Non-required parameters +param assignmentScopeValidation = 'Default' +param description = '[Description] Policy Exemption at the management group scope' +param displayName = '[DisplayName] Policy Exemption at the management group scope' +param enableTelemetry = true +param location = '' +param managementGroupId = '' +param metadata = { + assignedBy: 'Bicep' + category: 'Security' +} +param resourceSelectors = [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } +] +``` + +
+

+ +### Example 3: _Policy Exemption (Resource Group)_ + +This module deploys a Policy Exemption at a Resource Group scope using minimal parameters. + + +

+ +via Bicep module + +```bicep +module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' = { + name: 'policyExemptionDeployment' + params: { + // Required parameters + exemptionCategory: 'Mitigated' + name: 'apergmin001' + policyAssignmentId: '' + // Non-required parameters + resourceGroupName: '' + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "exemptionCategory": { + "value": "Mitigated" + }, + "name": { + "value": "apergmin001" + }, + "policyAssignmentId": { + "value": "" + }, + // Non-required parameters + "resourceGroupName": { + "value": "" + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-exemption:' + +// Required parameters +param exemptionCategory = 'Mitigated' +param name = 'apergmin001' +param policyAssignmentId = '' +// Non-required parameters +param resourceGroupName = '' +param subscriptionId = '' +``` + +
+

+ +### Example 4: _Policy Exemption (Resource Group)_ + +This module deploys a Policy Exemption at a Resource Group scope using common parameters. + + +

+ +via Bicep module + +```bicep +module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' = { + name: 'policyExemptionDeployment' + params: { + // Required parameters + exemptionCategory: 'Mitigated' + name: 'apergmax001' + policyAssignmentId: '' + // Non-required parameters + assignmentScopeValidation: 'Default' + description: '[Description] Policy Exemption at the management group scope' + displayName: '[DisplayName] Policy Exemption at the management group scope' + enableTelemetry: true + location: '' + metadata: { + assignedBy: 'Bicep' + category: 'Security' + } + resourceGroupName: '' + resourceSelectors: [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } + ] + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "exemptionCategory": { + "value": "Mitigated" + }, + "name": { + "value": "apergmax001" + }, + "policyAssignmentId": { + "value": "" + }, + // Non-required parameters + "assignmentScopeValidation": { + "value": "Default" + }, + "description": { + "value": "[Description] Policy Exemption at the management group scope" + }, + "displayName": { + "value": "[DisplayName] Policy Exemption at the management group scope" + }, + "enableTelemetry": { + "value": true + }, + "location": { + "value": "" + }, + "metadata": { + "value": { + "assignedBy": "Bicep", + "category": "Security" + } + }, + "resourceGroupName": { + "value": "" + }, + "resourceSelectors": { + "value": [ + { + "name": "resourceSelector-test", + "selectors": [ + { + "in": [ + "Microsoft.Compute/virtualMachines" + ], + "kind": "resourceType" + }, + { + "in": [ + "westeurope" + ], + "kind": "resourceLocation" + } + ] + } + ] + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-exemption:' + +// Required parameters +param exemptionCategory = 'Mitigated' +param name = 'apergmax001' +param policyAssignmentId = '' +// Non-required parameters +param assignmentScopeValidation = 'Default' +param description = '[Description] Policy Exemption at the management group scope' +param displayName = '[DisplayName] Policy Exemption at the management group scope' +param enableTelemetry = true +param location = '' +param metadata = { + assignedBy: 'Bicep' + category: 'Security' +} +param resourceGroupName = '' +param resourceSelectors = [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } +] +param subscriptionId = '' +``` + +
+

+ +### Example 5: _Policy Exemption (Subscription)_ + +This module deploys a Policy Exemption at a Subscription scope using minimal parameters. + + +

+ +via Bicep module + +```bicep +module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' = { + name: 'policyExemptionDeployment' + params: { + // Required parameters + exemptionCategory: 'Mitigated' + name: 'apesubmin001' + policyAssignmentId: '' + // Non-required parameters + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "exemptionCategory": { + "value": "Mitigated" + }, + "name": { + "value": "apesubmin001" + }, + "policyAssignmentId": { + "value": "" + }, + // Non-required parameters + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-exemption:' + +// Required parameters +param exemptionCategory = 'Mitigated' +param name = 'apesubmin001' +param policyAssignmentId = '' +// Non-required parameters +param subscriptionId = '' +``` + +
+

+ +### Example 6: _Policy Exemption (Subscription)_ + +This module deploys a Policy Exemption at a Subscription scope using common parameters. + + +

+ +via Bicep module + +```bicep +module policyExemption 'br/public:avm/ptn/authorization/policy-exemption:' = { + name: 'policyExemptionDeployment' + params: { + // Required parameters + exemptionCategory: 'Mitigated' + name: 'apesubmax001' + policyAssignmentId: '' + // Non-required parameters + assignmentScopeValidation: 'Default' + description: '[Description] Policy Exemption at the management group scope' + displayName: '[DisplayName] Policy Exemption at the management group scope' + enableTelemetry: true + location: '' + metadata: { + assignedBy: 'Bicep' + category: 'Security' + } + resourceSelectors: [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } + ] + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "exemptionCategory": { + "value": "Mitigated" + }, + "name": { + "value": "apesubmax001" + }, + "policyAssignmentId": { + "value": "" + }, + // Non-required parameters + "assignmentScopeValidation": { + "value": "Default" + }, + "description": { + "value": "[Description] Policy Exemption at the management group scope" + }, + "displayName": { + "value": "[DisplayName] Policy Exemption at the management group scope" + }, + "enableTelemetry": { + "value": true + }, + "location": { + "value": "" + }, + "metadata": { + "value": { + "assignedBy": "Bicep", + "category": "Security" + } + }, + "resourceSelectors": { + "value": [ + { + "name": "resourceSelector-test", + "selectors": [ + { + "in": [ + "Microsoft.Compute/virtualMachines" + ], + "kind": "resourceType" + }, + { + "in": [ + "westeurope" + ], + "kind": "resourceLocation" + } + ] + } + ] + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-exemption:' + +// Required parameters +param exemptionCategory = 'Mitigated' +param name = 'apesubmax001' +param policyAssignmentId = '' +// Non-required parameters +param assignmentScopeValidation = 'Default' +param description = '[Description] Policy Exemption at the management group scope' +param displayName = '[DisplayName] Policy Exemption at the management group scope' +param enableTelemetry = true +param location = '' +param metadata = { + assignedBy: 'Bicep' + category: 'Security' +} +param resourceSelectors = [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } +] +param subscriptionId = '' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`exemptionCategory`](#parameter-exemptioncategory) | string | The policy exemption category. | +| [`name`](#parameter-name) | string | Specifies the name of the policy exemption. Maximum length is 24 characters for management group scope. | +| [`policyAssignmentId`](#parameter-policyassignmentid) | string | Specifies the ID of the policy assignment that is being exempted. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`assignmentScopeValidation`](#parameter-assignmentscopevalidation) | string | The option to validate whether the exemption is at or under the assignment scope. | +| [`description`](#parameter-description) | string | This message will be part of response in case of policy violation. | +| [`displayName`](#parameter-displayname) | string | The display name of the policy exemption. Maximum length is 128 characters. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`expiresOn`](#parameter-expireson) | string | The expiration date and time (in UTC ISO 8601 format yyyy-MM-ddTHH:mm:ssZ) of the policy exemption. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`managementGroupId`](#parameter-managementgroupid) | string | The Target Scope for the Policy. The name of the management group for the policy exemption. If not provided, will use the current scope for deployment. | +| [`metadata`](#parameter-metadata) | object | The policy exemption metadata. Metadata is an open ended object and is typically a collection of key-value pairs. | +| [`policyDefinitionReferenceIds`](#parameter-policydefinitionreferenceids) | array | The policy definition reference ID list when the associated policy assignment is an assignment of a policy set definition. | +| [`resourceGroupName`](#parameter-resourcegroupname) | string | The Target Scope for the Policy. The name of the resource group for the policy exemption. | +| [`resourceSelectors`](#parameter-resourceselectors) | array | The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out Policy exemptions based on factors like resource location, resource type, or whether a resource has a location. | +| [`subscriptionId`](#parameter-subscriptionid) | string | The Target Scope for the Policy. The subscription ID of the subscription for the policy exemption. | + +### Parameter: `exemptionCategory` + +The policy exemption category. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Mitigated' + 'Waiver' + ] + ``` + +### Parameter: `name` + +Specifies the name of the policy exemption. Maximum length is 24 characters for management group scope. + +- Required: Yes +- Type: string + +### Parameter: `policyAssignmentId` + +Specifies the ID of the policy assignment that is being exempted. + +- Required: Yes +- Type: string + +### Parameter: `assignmentScopeValidation` + +The option to validate whether the exemption is at or under the assignment scope. + +- Required: No +- Type: string +- Default: `'Default'` +- Allowed: + ```Bicep + [ + 'Default' + 'DoNotValidate' + ] + ``` + +### Parameter: `description` + +This message will be part of response in case of policy violation. + +- Required: No +- Type: string + +### Parameter: `displayName` + +The display name of the policy exemption. Maximum length is 128 characters. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `expiresOn` + +The expiration date and time (in UTC ISO 8601 format yyyy-MM-ddTHH:mm:ssZ) of the policy exemption. + +- Required: No +- Type: string + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[deployment().location]` + +### Parameter: `managementGroupId` + +The Target Scope for the Policy. The name of the management group for the policy exemption. If not provided, will use the current scope for deployment. + +- Required: No +- Type: string +- Default: `[managementGroup().name]` + +### Parameter: `metadata` + +The policy exemption metadata. Metadata is an open ended object and is typically a collection of key-value pairs. + +- Required: No +- Type: object + +### Parameter: `policyDefinitionReferenceIds` + +The policy definition reference ID list when the associated policy assignment is an assignment of a policy set definition. + +- Required: No +- Type: array + +### Parameter: `resourceGroupName` + +The Target Scope for the Policy. The name of the resource group for the policy exemption. + +- Required: No +- Type: string + +### Parameter: `resourceSelectors` + +The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out Policy exemptions based on factors like resource location, resource type, or whether a resource has a location. + +- Required: No +- Type: array + +### Parameter: `subscriptionId` + +The Target Scope for the Policy. The subscription ID of the subscription for the policy exemption. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | Policy Exemption Name. | +| `resourceId` | string | Policy Exemption resource ID. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/ptn/authorization/policy-exemption/main.bicep b/avm/1.1.0/ptn/authorization/policy-exemption/main.bicep new file mode 100644 index 000000000..903c76430 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-exemption/main.bicep @@ -0,0 +1,149 @@ +metadata name = 'Policy Exemptions (All scopes)' +metadata description = 'This module deploys a Policy Exemption at a Management Group, Subscription or Resource Group scope.' + +targetScope = 'managementGroup' + +@sys.description('Required. Specifies the name of the policy exemption. Maximum length is 24 characters for management group scope.') +@maxLength(24) +param name string + +@sys.description('Optional. The option to validate whether the exemption is at or under the assignment scope.') +@allowed([ + 'DoNotValidate' + 'Default' +]) +param assignmentScopeValidation string = 'Default' + +@sys.description('Optional. This message will be part of response in case of policy violation.') +param description string? + +@sys.description('Optional. The display name of the policy exemption. Maximum length is 128 characters.') +@maxLength(128) +param displayName string? + +@sys.description('Required. The policy exemption category.') +@allowed([ + 'Mitigated' + 'Waiver' +]) +param exemptionCategory string + +@sys.description('Optional. The expiration date and time (in UTC ISO 8601 format yyyy-MM-ddTHH:mm:ssZ) of the policy exemption.') +@maxLength(20) +@minLength(20) +param expiresOn string? + +@sys.description('Optional. The policy exemption metadata. Metadata is an open ended object and is typically a collection of key-value pairs.') +param metadata object? + +@sys.description('Required. Specifies the ID of the policy assignment that is being exempted.') +param policyAssignmentId string + +@sys.description('Optional. The policy definition reference ID list when the associated policy assignment is an assignment of a policy set definition.') +param policyDefinitionReferenceIds string[]? + +@sys.description('Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out Policy exemptions based on factors like resource location, resource type, or whether a resource has a location.') +param resourceSelectors array? + +@sys.description('Optional. The Target Scope for the Policy. The name of the management group for the policy exemption. If not provided, will use the current scope for deployment.') +param managementGroupId string = managementGroup().name + +@sys.description('Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy exemption.') +param subscriptionId string? + +@sys.description('Optional. The Target Scope for the Policy. The name of the resource group for the policy exemption.') +param resourceGroupName string? + +@sys.description('Optional. Location for all Resources.') +param location string = deployment().location + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.ptn.authorization-policyexemption.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + location: location + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +module policyExemption_mg 'modules/management-group.bicep' = if (empty(subscriptionId) && empty(resourceGroupName)) { + name: '${uniqueString(deployment().name, location)}-PolicyExemption-MG-Module' + scope: managementGroup(managementGroupId) + params: { + name: name + description: description + displayName: displayName + assignmentScopeValidation: assignmentScopeValidation + exemptionCategory: exemptionCategory + expiresOn: expiresOn + metadata: metadata + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceIds: policyDefinitionReferenceIds + resourceSelectors: resourceSelectors + } +} + +module policyExemption_sub 'modules/subscription.bicep' = if (!empty(subscriptionId) && empty(resourceGroupName)) { + name: '${uniqueString(deployment().name, location)}-PolicyExemption-Sub-Module' + scope: subscription(subscriptionId ?? '') + params: { + name: name + description: description + displayName: displayName + assignmentScopeValidation: assignmentScopeValidation + exemptionCategory: exemptionCategory + expiresOn: expiresOn + metadata: metadata + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceIds: policyDefinitionReferenceIds + resourceSelectors: resourceSelectors + } +} + +module policyExemption_rg 'modules/resource-group.bicep' = if (!empty(resourceGroupName) && !empty(subscriptionId)) { + name: '${uniqueString(deployment().name, location)}-PolicyExemption-RG-Module' + scope: resourceGroup(subscriptionId ?? '', resourceGroupName ?? '') + params: { + name: name + description: description + displayName: displayName + assignmentScopeValidation: assignmentScopeValidation + exemptionCategory: exemptionCategory + expiresOn: expiresOn + metadata: metadata + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceIds: policyDefinitionReferenceIds + resourceSelectors: resourceSelectors + } +} + +@sys.description('Policy Exemption Name.') +output name string = empty(subscriptionId) && empty(resourceGroupName) + ? policyExemption_mg.outputs.name + : (!empty(subscriptionId) && empty(resourceGroupName) + ? policyExemption_sub.outputs.name + : policyExemption_rg.outputs.name) + +@sys.description('Policy Exemption resource ID.') +output resourceId string = empty(subscriptionId) && empty(resourceGroupName) + ? policyExemption_mg.outputs.resourceId + : (!empty(subscriptionId) && empty(resourceGroupName) + ? policyExemption_sub.outputs.resourceId + : policyExemption_rg.outputs.resourceId) diff --git a/avm/1.1.0/ptn/authorization/policy-exemption/main.json b/avm/1.1.0/ptn/authorization/policy-exemption/main.json new file mode 100644 index 000000000..63e538c30 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-exemption/main.json @@ -0,0 +1,706 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "860469689601275144" + }, + "name": "Policy Exemptions (All scopes)", + "description": "This module deploys a Policy Exemption at a Management Group, Subscription or Resource Group scope." + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Specifies the name of the policy exemption. Maximum length is 24 characters for management group scope." + } + }, + "assignmentScopeValidation": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "DoNotValidate", + "Default" + ], + "metadata": { + "description": "Optional. The option to validate whether the exemption is at or under the assignment scope." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This message will be part of response in case of policy violation." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy exemption. Maximum length is 128 characters." + } + }, + "exemptionCategory": { + "type": "string", + "allowedValues": [ + "Mitigated", + "Waiver" + ], + "metadata": { + "description": "Required. The policy exemption category." + } + }, + "expiresOn": { + "type": "string", + "nullable": true, + "minLength": 20, + "maxLength": 20, + "metadata": { + "description": "Optional. The expiration date and time (in UTC ISO 8601 format yyyy-MM-ddTHH:mm:ssZ) of the policy exemption." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The policy exemption metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "policyAssignmentId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the ID of the policy assignment that is being exempted." + } + }, + "policyDefinitionReferenceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The policy definition reference ID list when the associated policy assignment is an assignment of a policy set definition." + } + }, + "resourceSelectors": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out Policy exemptions based on factors like resource location, resource type, or whether a resource has a location." + } + }, + "managementGroupId": { + "type": "string", + "defaultValue": "[managementGroup().name]", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The name of the management group for the policy exemption. If not provided, will use the current scope for deployment." + } + }, + "subscriptionId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy exemption." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Target Scope for the Policy. The name of the resource group for the policy exemption." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.ptn.authorization-policyexemption.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "location": "[parameters('location')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "policyExemption_mg": { + "condition": "[and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyExemption-MG-Module', uniqueString(deployment().name, parameters('location')))]", + "scope": "[format('Microsoft.Management/managementGroups/{0}', parameters('managementGroupId'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "description": { + "value": "[parameters('description')]" + }, + "displayName": { + "value": "[parameters('displayName')]" + }, + "assignmentScopeValidation": { + "value": "[parameters('assignmentScopeValidation')]" + }, + "exemptionCategory": { + "value": "[parameters('exemptionCategory')]" + }, + "expiresOn": { + "value": "[parameters('expiresOn')]" + }, + "metadata": { + "value": "[parameters('metadata')]" + }, + "policyAssignmentId": { + "value": "[parameters('policyAssignmentId')]" + }, + "policyDefinitionReferenceIds": { + "value": "[parameters('policyDefinitionReferenceIds')]" + }, + "resourceSelectors": { + "value": "[parameters('resourceSelectors')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "5428405035932847140" + }, + "name": "Policy Exemptions (Management Group scope)", + "description": "This module deploys a policy exemption at a Management Group scope." + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. Specifies the name of the policy exemption. Maximum length is 64 characters for management group scope." + } + }, + "assignmentScopeValidation": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "DoNotValidate", + "Default" + ], + "metadata": { + "description": "Optional. The option to validate whether the exemption is at or under the assignment scope." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This message will be part of response in case of policy violation." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy exemption. Maximum length is 128 characters." + } + }, + "exemptionCategory": { + "type": "string", + "allowedValues": [ + "Mitigated", + "Waiver" + ], + "metadata": { + "description": "Required. The policy exemption category." + } + }, + "expiresOn": { + "type": "string", + "nullable": true, + "minLength": 20, + "maxLength": 20, + "metadata": { + "description": "Optional. The expiration date and time (in UTC ISO 8601 format yyyy-MM-ddTHH:mm:ssZ) of the policy exemption." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The policy exemption metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "policyAssignmentId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the ID of the policy assignment that is being exempted." + } + }, + "policyDefinitionReferenceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The policy definition reference ID list when the associated policy assignment is an assignment of a policy set definition." + } + }, + "resourceSelectors": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out Policy exemptions based on factors like resource location, resource type, or whether a resource has a location." + } + } + }, + "resources": { + "policyExemption": { + "type": "Microsoft.Authorization/policyExemptions", + "apiVersion": "2022-07-01-preview", + "name": "[parameters('name')]", + "properties": { + "description": "[parameters('description')]", + "displayName": "[parameters('displayName')]", + "assignmentScopeValidation": "[parameters('assignmentScopeValidation')]", + "exemptionCategory": "[parameters('exemptionCategory')]", + "expiresOn": "[parameters('expiresOn')]", + "metadata": "[parameters('metadata')]", + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceIds": "[parameters('policyDefinitionReferenceIds')]", + "resourceSelectors": "[parameters('resourceSelectors')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy exemption name." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy exemption resource ID." + }, + "value": "[extensionResourceId(managementGroup().id, 'Microsoft.Authorization/policyExemptions', parameters('name'))]" + } + } + } + } + }, + "policyExemption_sub": { + "condition": "[and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyExemption-Sub-Module', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[coalesce(parameters('subscriptionId'), '')]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "description": { + "value": "[parameters('description')]" + }, + "displayName": { + "value": "[parameters('displayName')]" + }, + "assignmentScopeValidation": { + "value": "[parameters('assignmentScopeValidation')]" + }, + "exemptionCategory": { + "value": "[parameters('exemptionCategory')]" + }, + "expiresOn": { + "value": "[parameters('expiresOn')]" + }, + "metadata": { + "value": "[parameters('metadata')]" + }, + "policyAssignmentId": { + "value": "[parameters('policyAssignmentId')]" + }, + "policyDefinitionReferenceIds": { + "value": "[parameters('policyDefinitionReferenceIds')]" + }, + "resourceSelectors": { + "value": "[parameters('resourceSelectors')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "5505971988172423733" + }, + "name": "Policy Exemptions (Subscription scope)", + "description": "This module deploys a policy exemption at a Subscription scope." + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. Specifies the name of the policy exemption. Maximum length is 64 characters for subscription scope." + } + }, + "assignmentScopeValidation": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "DoNotValidate", + "Default" + ], + "metadata": { + "description": "Optional. The option to validate whether the exemption is at or under the assignment scope." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This message will be part of response in case of policy violation." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy exemption. Maximum length is 128 characters." + } + }, + "exemptionCategory": { + "type": "string", + "allowedValues": [ + "Mitigated", + "Waiver" + ], + "metadata": { + "description": "Required. The policy exemption category." + } + }, + "expiresOn": { + "type": "string", + "nullable": true, + "minLength": 20, + "maxLength": 20, + "metadata": { + "description": "Optional. The expiration date and time (in UTC ISO 8601 format yyyy-MM-ddTHH:mm:ssZ) of the policy exemption." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The policy exemption metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "policyAssignmentId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the ID of the policy assignment that is being exempted." + } + }, + "policyDefinitionReferenceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The policy definition reference ID list when the associated policy assignment is an assignment of a policy set definition." + } + }, + "resourceSelectors": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out Policy exemptions based on factors like resource location, resource type, or whether a resource has a location." + } + } + }, + "resources": { + "policyExemption": { + "type": "Microsoft.Authorization/policyExemptions", + "apiVersion": "2022-07-01-preview", + "name": "[parameters('name')]", + "properties": { + "description": "[parameters('description')]", + "displayName": "[parameters('displayName')]", + "assignmentScopeValidation": "[parameters('assignmentScopeValidation')]", + "exemptionCategory": "[parameters('exemptionCategory')]", + "expiresOn": "[parameters('expiresOn')]", + "metadata": "[parameters('metadata')]", + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceIds": "[parameters('policyDefinitionReferenceIds')]", + "resourceSelectors": "[parameters('resourceSelectors')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy exemption name." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy exemption resource ID." + }, + "value": "[subscriptionResourceId('Microsoft.Authorization/policyExemptions', parameters('name'))]" + } + } + } + } + }, + "policyExemption_rg": { + "condition": "[and(not(empty(parameters('resourceGroupName'))), not(empty(parameters('subscriptionId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PolicyExemption-RG-Module', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[coalesce(parameters('subscriptionId'), '')]", + "resourceGroup": "[coalesce(parameters('resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "description": { + "value": "[parameters('description')]" + }, + "displayName": { + "value": "[parameters('displayName')]" + }, + "assignmentScopeValidation": { + "value": "[parameters('assignmentScopeValidation')]" + }, + "exemptionCategory": { + "value": "[parameters('exemptionCategory')]" + }, + "expiresOn": { + "value": "[parameters('expiresOn')]" + }, + "metadata": { + "value": "[parameters('metadata')]" + }, + "policyAssignmentId": { + "value": "[parameters('policyAssignmentId')]" + }, + "policyDefinitionReferenceIds": { + "value": "[parameters('policyDefinitionReferenceIds')]" + }, + "resourceSelectors": { + "value": "[parameters('resourceSelectors')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "11896729454122030890" + }, + "name": "Policy Exemptions (Resource Group scope)", + "description": "This module deploys a policy exemption at a Resource Group scope." + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. Specifies the name of the policy exemption. Maximum length is 64 characters for resource group scope." + } + }, + "assignmentScopeValidation": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "DoNotValidate", + "Default" + ], + "metadata": { + "description": "Optional. The option to validate whether the exemption is at or under the assignment scope." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This message will be part of response in case of policy violation." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy exemption. Maximum length is 128 characters." + } + }, + "exemptionCategory": { + "type": "string", + "allowedValues": [ + "Mitigated", + "Waiver" + ], + "metadata": { + "description": "Required. The policy exemption category." + } + }, + "expiresOn": { + "type": "string", + "nullable": true, + "minLength": 20, + "maxLength": 20, + "metadata": { + "description": "Optional. The expiration date and time (in UTC ISO 8601 format yyyy-MM-ddTHH:mm:ssZ) of the policy exemption." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The policy exemption metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "policyAssignmentId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the ID of the policy assignment that is being exempted." + } + }, + "policyDefinitionReferenceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The policy definition reference ID list when the associated policy assignment is an assignment of a policy set definition." + } + }, + "resourceSelectors": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out Policy exemptions based on factors like resource location, resource type, or whether a resource has a location." + } + } + }, + "resources": { + "policyExemption": { + "type": "Microsoft.Authorization/policyExemptions", + "apiVersion": "2022-07-01-preview", + "name": "[parameters('name')]", + "properties": { + "description": "[parameters('description')]", + "displayName": "[parameters('displayName')]", + "assignmentScopeValidation": "[parameters('assignmentScopeValidation')]", + "exemptionCategory": "[parameters('exemptionCategory')]", + "expiresOn": "[parameters('expiresOn')]", + "metadata": "[parameters('metadata')]", + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceIds": "[parameters('policyDefinitionReferenceIds')]", + "resourceSelectors": "[parameters('resourceSelectors')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy exemption name." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy exemption resource ID." + }, + "value": "[resourceId('Microsoft.Authorization/policyExemptions', parameters('name'))]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy Exemption Name." + }, + "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference('policyExemption_mg').outputs.name.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference('policyExemption_sub').outputs.name.value, reference('policyExemption_rg').outputs.name.value))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Exemption resource ID." + }, + "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference('policyExemption_mg').outputs.resourceId.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference('policyExemption_sub').outputs.resourceId.value, reference('policyExemption_rg').outputs.resourceId.value))]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/ptn/authorization/policy-exemption/modules/management-group.bicep b/avm/1.1.0/ptn/authorization/policy-exemption/modules/management-group.bicep new file mode 100644 index 000000000..acf34d166 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-exemption/modules/management-group.bicep @@ -0,0 +1,67 @@ +metadata name = 'Policy Exemptions (Management Group scope)' +metadata description = 'This module deploys a policy exemption at a Management Group scope.' + +targetScope = 'managementGroup' + +@sys.description('Required. Specifies the name of the policy exemption. Maximum length is 64 characters for management group scope.') +@maxLength(64) +param name string + +@sys.description('Optional. The option to validate whether the exemption is at or under the assignment scope.') +@allowed([ + 'DoNotValidate' + 'Default' +]) +param assignmentScopeValidation string = 'Default' + +@sys.description('Optional. This message will be part of response in case of policy violation.') +param description string? + +@sys.description('Optional. The display name of the policy exemption. Maximum length is 128 characters.') +@maxLength(128) +param displayName string? + +@sys.description('Required. The policy exemption category.') +@allowed([ + 'Mitigated' + 'Waiver' +]) +param exemptionCategory string + +@sys.description('Optional. The expiration date and time (in UTC ISO 8601 format yyyy-MM-ddTHH:mm:ssZ) of the policy exemption.') +@maxLength(20) +@minLength(20) +param expiresOn string? + +@sys.description('Optional. The policy exemption metadata. Metadata is an open ended object and is typically a collection of key-value pairs.') +param metadata object? + +@sys.description('Required. Specifies the ID of the policy assignment that is being exempted.') +param policyAssignmentId string + +@sys.description('Optional. The policy definition reference ID list when the associated policy assignment is an assignment of a policy set definition.') +param policyDefinitionReferenceIds string[]? + +@sys.description('Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out Policy exemptions based on factors like resource location, resource type, or whether a resource has a location.') +param resourceSelectors array? + +resource policyExemption 'Microsoft.Authorization/policyExemptions@2022-07-01-preview' = { + name: name + properties: { + description: description + displayName: displayName + assignmentScopeValidation: assignmentScopeValidation + exemptionCategory: exemptionCategory + expiresOn: expiresOn + metadata: metadata + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceIds: policyDefinitionReferenceIds + resourceSelectors: resourceSelectors + } +} + +@sys.description('Policy exemption name.') +output name string = policyExemption.name + +@sys.description('Policy exemption resource ID.') +output resourceId string = policyExemption.id diff --git a/avm/1.1.0/ptn/authorization/policy-exemption/modules/resource-group.bicep b/avm/1.1.0/ptn/authorization/policy-exemption/modules/resource-group.bicep new file mode 100644 index 000000000..d2b2d115c --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-exemption/modules/resource-group.bicep @@ -0,0 +1,67 @@ +metadata name = 'Policy Exemptions (Resource Group scope)' +metadata description = 'This module deploys a policy exemption at a Resource Group scope.' + +targetScope = 'resourceGroup' + +@sys.description('Required. Specifies the name of the policy exemption. Maximum length is 64 characters for resource group scope.') +@maxLength(64) +param name string + +@sys.description('Optional. The option to validate whether the exemption is at or under the assignment scope.') +@allowed([ + 'DoNotValidate' + 'Default' +]) +param assignmentScopeValidation string = 'Default' + +@sys.description('Optional. This message will be part of response in case of policy violation.') +param description string? + +@sys.description('Optional. The display name of the policy exemption. Maximum length is 128 characters.') +@maxLength(128) +param displayName string? + +@sys.description('Required. The policy exemption category.') +@allowed([ + 'Mitigated' + 'Waiver' +]) +param exemptionCategory string + +@sys.description('Optional. The expiration date and time (in UTC ISO 8601 format yyyy-MM-ddTHH:mm:ssZ) of the policy exemption.') +@maxLength(20) +@minLength(20) +param expiresOn string? + +@sys.description('Optional. The policy exemption metadata. Metadata is an open ended object and is typically a collection of key-value pairs.') +param metadata object? + +@sys.description('Required. Specifies the ID of the policy assignment that is being exempted.') +param policyAssignmentId string + +@sys.description('Optional. The policy definition reference ID list when the associated policy assignment is an assignment of a policy set definition.') +param policyDefinitionReferenceIds string[]? + +@sys.description('Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out Policy exemptions based on factors like resource location, resource type, or whether a resource has a location.') +param resourceSelectors array? + +resource policyExemption 'Microsoft.Authorization/policyExemptions@2022-07-01-preview' = { + name: name + properties: { + description: description + displayName: displayName + assignmentScopeValidation: assignmentScopeValidation + exemptionCategory: exemptionCategory + expiresOn: expiresOn + metadata: metadata + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceIds: policyDefinitionReferenceIds + resourceSelectors: resourceSelectors + } +} + +@sys.description('Policy exemption name.') +output name string = policyExemption.name + +@sys.description('Policy exemption resource ID.') +output resourceId string = policyExemption.id diff --git a/avm/1.1.0/ptn/authorization/policy-exemption/modules/subscription.bicep b/avm/1.1.0/ptn/authorization/policy-exemption/modules/subscription.bicep new file mode 100644 index 000000000..ec03b122e --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-exemption/modules/subscription.bicep @@ -0,0 +1,67 @@ +metadata name = 'Policy Exemptions (Subscription scope)' +metadata description = 'This module deploys a policy exemption at a Subscription scope.' + +targetScope = 'subscription' + +@sys.description('Required. Specifies the name of the policy exemption. Maximum length is 64 characters for subscription scope.') +@maxLength(64) +param name string + +@sys.description('Optional. The option to validate whether the exemption is at or under the assignment scope.') +@allowed([ + 'DoNotValidate' + 'Default' +]) +param assignmentScopeValidation string = 'Default' + +@sys.description('Optional. This message will be part of response in case of policy violation.') +param description string? + +@sys.description('Optional. The display name of the policy exemption. Maximum length is 128 characters.') +@maxLength(128) +param displayName string? + +@sys.description('Required. The policy exemption category.') +@allowed([ + 'Mitigated' + 'Waiver' +]) +param exemptionCategory string + +@sys.description('Optional. The expiration date and time (in UTC ISO 8601 format yyyy-MM-ddTHH:mm:ssZ) of the policy exemption.') +@maxLength(20) +@minLength(20) +param expiresOn string? + +@sys.description('Optional. The policy exemption metadata. Metadata is an open ended object and is typically a collection of key-value pairs.') +param metadata object? + +@sys.description('Required. Specifies the ID of the policy assignment that is being exempted.') +param policyAssignmentId string + +@sys.description('Optional. The policy definition reference ID list when the associated policy assignment is an assignment of a policy set definition.') +param policyDefinitionReferenceIds string[]? + +@sys.description('Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out Policy exemptions based on factors like resource location, resource type, or whether a resource has a location.') +param resourceSelectors array? + +resource policyExemption 'Microsoft.Authorization/policyExemptions@2022-07-01-preview' = { + name: name + properties: { + description: description + displayName: displayName + assignmentScopeValidation: assignmentScopeValidation + exemptionCategory: exemptionCategory + expiresOn: expiresOn + metadata: metadata + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceIds: policyDefinitionReferenceIds + resourceSelectors: resourceSelectors + } +} + +@sys.description('Policy exemption name.') +output name string = policyExemption.name + +@sys.description('Policy exemption resource ID.') +output resourceId string = policyExemption.id diff --git a/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/mg.defaults/main.test.bicep b/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/mg.defaults/main.test.bicep new file mode 100644 index 000000000..5d332a51d --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/mg.defaults/main.test.bicep @@ -0,0 +1,53 @@ +targetScope = 'managementGroup' +metadata name = 'Policy Exemptions (Management Group scope)' +metadata description = 'This module deploys a Policy Exemption at a Management Group scope using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apemgmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // + +resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2025-01-01' existing = { + name: '06a78e20-9358-41c9-923c-fb736d382a4d' + scope: tenant() +} + +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2024-04-01' = { + name: 'audit-vm-managed-disks' + scope: managementGroup() + properties: { + metadata: { + assignedBy: 'Bicep' + } + policyDefinitionId: policyDefinition.id + description: ' This policy audits VMs that do not use managed disks' + displayName: 'Audit VMs that do not use managed disks' + enforcementMode: 'DoNotEnforce' + nonComplianceMessages: [ + { + message: 'Virtual machines should use managed disks' + } + ] + } +} + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + exemptionCategory: 'Mitigated' + policyAssignmentId: policyAssignment.id + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/mg.max/main.test.bicep b/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/mg.max/main.test.bicep new file mode 100644 index 000000000..428351966 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/mg.max/main.test.bicep @@ -0,0 +1,82 @@ +targetScope = 'managementGroup' +metadata name = 'Policy Exemptions (Management Group scope)' +metadata description = 'This module deploys a Policy Exemption at a Management Group scope using common parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apemgmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // + +resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2025-01-01' existing = { + name: '06a78e20-9358-41c9-923c-fb736d382a4d' + scope: tenant() +} + +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2024-04-01' = { + name: 'audit-vm-managed-disks' + scope: managementGroup() + properties: { + metadata: { + assignedBy: 'Bicep' + } + policyDefinitionId: policyDefinition.id + description: ' This policy audits VMs that do not use managed disks' + displayName: 'Audit VMs that do not use managed disks' + enforcementMode: 'DoNotEnforce' + nonComplianceMessages: [ + { + message: 'Virtual machines should use managed disks' + } + ] + } +} + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + exemptionCategory: 'Mitigated' + policyAssignmentId: policyAssignment.id + assignmentScopeValidation: 'Default' + description: '[Description] Policy Exemption at the management group scope' + displayName: '[DisplayName] Policy Exemption at the management group scope' + enableTelemetry: true + location: resourceLocation + managementGroupId: managementGroup().name + metadata: { + category: 'Security' + assignedBy: 'Bicep' + } + resourceSelectors: [ + { + name: 'resourceSelector-test' + selectors: [ + { + kind: 'resourceType' + in: [ + 'Microsoft.Compute/virtualMachines' + ] + } + { + kind: 'resourceLocation' + in: [ + 'westeurope' + ] + } + ] + } + ] + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/rg.defaults/main.test.bicep b/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/rg.defaults/main.test.bicep new file mode 100644 index 000000000..1e680c912 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/rg.defaults/main.test.bicep @@ -0,0 +1,72 @@ +targetScope = 'managementGroup' +metadata name = 'Policy Exemption (Resource Group)' +metadata description = 'This module deploys a Policy Exemption at a Resource Group scope using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apergmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The target scope for the policy exemption. If not provided, will use the current scope for deployment.') +param subscriptionId string = '#_subscriptionId_#' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.policyassignments-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // + +module resourceGroup 'br/public:avm/res/resources/resource-group:0.2.3' = { + scope: subscription('${subscriptionId}') + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: resourceGroupName + location: resourceLocation + } +} + +resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2025-01-01' existing = { + name: '06a78e20-9358-41c9-923c-fb736d382a4d' + scope: tenant() +} + +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2024-04-01' = { + name: 'audit-vm-managed-disks' + scope: managementGroup() + properties: { + metadata: { + assignedBy: 'Bicep' + } + policyDefinitionId: policyDefinition.id + description: ' This policy audits VMs that do not use managed disks' + displayName: 'Audit VMs that do not use managed disks' + enforcementMode: 'DoNotEnforce' + nonComplianceMessages: [ + { + message: 'Virtual machines should use managed disks' + } + ] + } +} + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + exemptionCategory: 'Mitigated' + subscriptionId: subscriptionId + resourceGroupName: resourceGroup.outputs.name + policyAssignmentId: policyAssignment.id + } +} + diff --git a/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/rg.max/main.test.bicep b/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/rg.max/main.test.bicep new file mode 100644 index 000000000..832dd7bb8 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/rg.max/main.test.bicep @@ -0,0 +1,98 @@ +targetScope = 'managementGroup' +metadata name = 'Policy Exemption (Resource Group)' +metadata description = 'This module deploys a Policy Exemption at a Resource Group scope using common parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apergmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The target scope for the policy exemption. If not provided, will use the current scope for deployment.') +param subscriptionId string = '#_subscriptionId_#' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.policyassignments-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // +module resourceGroup 'br/public:avm/res/resources/resource-group:0.2.3' = { + scope: subscription('${subscriptionId}') + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: resourceGroupName + location: resourceLocation + } +} + +resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2025-01-01' existing = { + name: '06a78e20-9358-41c9-923c-fb736d382a4d' + scope: tenant() +} + +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2024-04-01' = { + name: 'audit-vm-managed-disks' + scope: managementGroup() + properties: { + metadata: { + assignedBy: 'Bicep' + } + policyDefinitionId: policyDefinition.id + description: ' This policy audits VMs that do not use managed disks' + displayName: 'Audit VMs that do not use managed disks' + enforcementMode: 'DoNotEnforce' + nonComplianceMessages: [ + { + message: 'Virtual machines should use managed disks' + } + ] + } +} + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + exemptionCategory: 'Mitigated' + policyAssignmentId: policyAssignment.id + assignmentScopeValidation: 'Default' + description: '[Description] Policy Exemption at the management group scope' + displayName: '[DisplayName] Policy Exemption at the management group scope' + enableTelemetry: true + location: resourceLocation + subscriptionId: subscriptionId + resourceGroupName: resourceGroup.outputs.name + metadata: { + category: 'Security' + assignedBy: 'Bicep' + } + resourceSelectors: [ + { + name: 'resourceSelector-test' + selectors: [ + { + kind: 'resourceType' + in: [ + 'Microsoft.Compute/virtualMachines' + ] + } + { + kind: 'resourceLocation' + in: [ + 'westeurope' + ] + } + ] + } + ] + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/sub.defaults/main.test.bicep b/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/sub.defaults/main.test.bicep new file mode 100644 index 000000000..1864acb75 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/sub.defaults/main.test.bicep @@ -0,0 +1,57 @@ +targetScope = 'managementGroup' +metadata name = 'Policy Exemption (Subscription)' +metadata description = 'This module deploys a Policy Exemption at a Subscription scope using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apesubmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The target Scope for the policy exemption. If not provided, will use the current scope for deployment.') +param subscriptionId string = '#_subscriptionId_#' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // + +resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2025-01-01' existing = { + name: '06a78e20-9358-41c9-923c-fb736d382a4d' + scope: tenant() +} + +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2024-04-01' = { + name: 'audit-vm-managed-disks' + scope: managementGroup() + properties: { + metadata: { + assignedBy: 'Bicep' + } + policyDefinitionId: policyDefinition.id + description: ' This policy audits VMs that do not use managed disks' + displayName: 'Audit VMs that do not use managed disks' + enforcementMode: 'DoNotEnforce' + nonComplianceMessages: [ + { + message: 'Virtual machines should use managed disks' + } + ] + } +} + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + exemptionCategory: 'Mitigated' + subscriptionId: subscriptionId + policyAssignmentId: policyAssignment.id + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/sub.max/main.test.bicep b/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/sub.max/main.test.bicep new file mode 100644 index 000000000..ba00f5e21 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-exemption/tests/e2e/sub.max/main.test.bicep @@ -0,0 +1,85 @@ +targetScope = 'managementGroup' +metadata name = 'Policy Exemption (Subscription)' +metadata description = 'This module deploys a Policy Exemption at a Subscription scope using common parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apesubmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The target Scope for the policy exemption. If not provided, will use the current scope for deployment.') +param subscriptionId string = '#_subscriptionId_#' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // + +resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2025-01-01' existing = { + name: '06a78e20-9358-41c9-923c-fb736d382a4d' + scope: tenant() +} + +resource policyAssignment 'Microsoft.Authorization/policyAssignments@2024-04-01' = { + name: 'audit-vm-managed-disks' + scope: managementGroup() + properties: { + metadata: { + assignedBy: 'Bicep' + } + policyDefinitionId: policyDefinition.id + description: ' This policy audits VMs that do not use managed disks' + displayName: 'Audit VMs that do not use managed disks' + enforcementMode: 'DoNotEnforce' + nonComplianceMessages: [ + { + message: 'Virtual machines should use managed disks' + } + ] + } +} + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + exemptionCategory: 'Mitigated' + subscriptionId: subscriptionId + policyAssignmentId: policyAssignment.id + assignmentScopeValidation: 'Default' + description: '[Description] Policy Exemption at the management group scope' + displayName: '[DisplayName] Policy Exemption at the management group scope' + enableTelemetry: true + location: resourceLocation + metadata: { + category: 'Security' + assignedBy: 'Bicep' + } + resourceSelectors: [ + { + name: 'resourceSelector-test' + selectors: [ + { + kind: 'resourceType' + in: [ + 'Microsoft.Compute/virtualMachines' + ] + } + { + kind: 'resourceLocation' + in: [ + 'westeurope' + ] + } + ] + } + ] + } +} diff --git a/avm/1.1.0/ptn/authorization/policy-exemption/version.json b/avm/1.1.0/ptn/authorization/policy-exemption/version.json new file mode 100644 index 000000000..8def869ed --- /dev/null +++ b/avm/1.1.0/ptn/authorization/policy-exemption/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/ptn/authorization/resource-role-assignment/README.md b/avm/1.1.0/ptn/authorization/resource-role-assignment/README.md new file mode 100644 index 000000000..4e02efebc --- /dev/null +++ b/avm/1.1.0/ptn/authorization/resource-role-assignment/README.md @@ -0,0 +1,289 @@ +# Resource-scoped role assignment `[Authorization/ResourceRoleAssignment]` + +This module deploys a Role Assignment for a specific resource. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## Resource Types + +_None_ + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/authorization/resource-role-assignment:`. + +- [Resource Role Assignments](#example-1-resource-role-assignments) +- [Resource Role Assignments](#example-2-resource-role-assignments) + +### Example 1: _Resource Role Assignments_ + +This module deploys a Resource Role Assignment using all parameters. + + +

+ +via Bicep module + +```bicep +module resourceRoleAssignment 'br/public:avm/ptn/authorization/resource-role-assignment:' = { + name: 'resourceRoleAssignmentDeployment' + params: { + // Required parameters + principalId: '' + resourceId: '' + roleDefinitionId: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' + // Non-required parameters + description: 'Assign Storage Blob Data Reader role to the managed identity on the storage account.' + principalType: 'ServicePrincipal' + roleName: 'Storage Blob Data Reader' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "principalId": { + "value": "" + }, + "resourceId": { + "value": "" + }, + "roleDefinitionId": { + "value": "2a2b9908-6ea1-4ae2-8e65-a410df84e7d1" + }, + // Non-required parameters + "description": { + "value": "Assign Storage Blob Data Reader role to the managed identity on the storage account." + }, + "principalType": { + "value": "ServicePrincipal" + }, + "roleName": { + "value": "Storage Blob Data Reader" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/resource-role-assignment:' + +// Required parameters +param principalId = '' +param resourceId = '' +param roleDefinitionId = '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' +// Non-required parameters +param description = 'Assign Storage Blob Data Reader role to the managed identity on the storage account.' +param principalType = 'ServicePrincipal' +param roleName = 'Storage Blob Data Reader' +``` + +
+

+ +### Example 2: _Resource Role Assignments_ + +This module deploys a Resource Role Assignment using minimal parameters. + + +

+ +via Bicep module + +```bicep +module resourceRoleAssignment 'br/public:avm/ptn/authorization/resource-role-assignment:' = { + name: 'resourceRoleAssignmentDeployment' + params: { + // Required parameters + principalId: '' + resourceId: '' + roleDefinitionId: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' + // Non-required parameters + principalType: 'ServicePrincipal' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "principalId": { + "value": "" + }, + "resourceId": { + "value": "" + }, + "roleDefinitionId": { + "value": "2a2b9908-6ea1-4ae2-8e65-a410df84e7d1" + }, + // Non-required parameters + "principalType": { + "value": "ServicePrincipal" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/resource-role-assignment:' + +// Required parameters +param principalId = '' +param resourceId = '' +param roleDefinitionId = '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' +// Non-required parameters +param principalType = 'ServicePrincipal' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-principalid) | string | The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity). | +| [`resourceId`](#parameter-resourceid) | string | The scope for the role assignment, fully qualified resourceId. | +| [`roleDefinitionId`](#parameter-roledefinitionid) | string | The role definition ID for the role assignment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | The description of role assignment. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`name`](#parameter-name) | string | The unique guid name for the role assignment. | +| [`principalType`](#parameter-principaltype) | string | The principal type of the assigned principal ID. | +| [`roleName`](#parameter-rolename) | string | The name for the role, used for logging. | + +### Parameter: `principalId` + +The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity). + +- Required: Yes +- Type: string + +### Parameter: `resourceId` + +The scope for the role assignment, fully qualified resourceId. + +- Required: Yes +- Type: string + +### Parameter: `roleDefinitionId` + +The role definition ID for the role assignment. + +- Required: Yes +- Type: string + +### Parameter: `description` + +The description of role assignment. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `name` + +The unique guid name for the role assignment. + +- Required: No +- Type: string +- Default: `[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]` + +### Parameter: `principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `roleName` + +The name for the role, used for logging. + +- Required: No +- Type: string +- Default: `''` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The GUID of the Role Assignment. | +| `resourceGroupName` | string | The name of the resource group the role assignment was applied at. | +| `resourceId` | string | The resource ID of the Role Assignment. | +| `roleName` | string | The name for the role, used for logging. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/ptn/authorization/resource-role-assignment/main.bicep b/avm/1.1.0/ptn/authorization/resource-role-assignment/main.bicep new file mode 100644 index 000000000..3ffe3887b --- /dev/null +++ b/avm/1.1.0/ptn/authorization/resource-role-assignment/main.bicep @@ -0,0 +1,108 @@ +metadata name = 'Resource-scoped role assignment' +metadata description = 'This module deploys a Role Assignment for a specific resource.' + +@sys.description('Required. The scope for the role assignment, fully qualified resourceId.') +param resourceId string + +@sys.description('Optional. The unique guid name for the role assignment.') +param name string = guid( + resourceId, + principalId, + contains(roleDefinitionId, '/providers/Microsoft.Authorization/roleDefinitions/') + ? roleDefinitionId + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) +) + +@sys.description('Required. The role definition ID for the role assignment.') +param roleDefinitionId string + +@sys.description('Optional. The name for the role, used for logging.') +param roleName string = '' + +@sys.description('Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity).') +param principalId 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 role assignment.') +param description string = '' + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// =============== // +// Definitions // +// =============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.authorization-resourceroleassignment.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource resourceRoleAssignment 'Microsoft.Resources/deployments@2023-07-01' = { + name: '${guid(resourceId, principalId, roleDefinitionId)}-ResourceRoleAssignment' + properties: { + mode: 'Incremental' + expressionEvaluationOptions: { + scope: 'Outer' + } + template: loadJsonContent('modules/generic-role-assignment.json') + parameters: { + scope: { + value: resourceId + } + name: { + value: name + } + roleDefinitionId: { + value: contains(roleDefinitionId, '/providers/Microsoft.Authorization/roleDefinitions/') + ? roleDefinitionId + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) + } + principalId: { + value: principalId + } + principalType: { + value: principalType + } + description: { + value: description + } + } + } +} + +@sys.description('The GUID of the Role Assignment.') +output name string = name + +@sys.description('The name for the role, used for logging.') +output roleName string = roleName + +@sys.description('The resource ID of the Role Assignment.') +output resourceId string = resourceRoleAssignment.properties.outputs.roleAssignmentId.value + +@sys.description('The name of the resource group the role assignment was applied at.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/ptn/authorization/resource-role-assignment/main.json b/avm/1.1.0/ptn/authorization/resource-role-assignment/main.json new file mode 100644 index 000000000..7747d287f --- /dev/null +++ b/avm/1.1.0/ptn/authorization/resource-role-assignment/main.json @@ -0,0 +1,218 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12809426710118192869" + }, + "name": "Resource-scoped role assignment", + "description": "This module deploys a Role Assignment for a specific resource." + }, + "parameters": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The scope for the role assignment, fully qualified resourceId." + } + }, + "name": { + "type": "string", + "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", + "metadata": { + "description": "Optional. The unique guid name for the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition ID for the role assignment." + } + }, + "roleName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name for the role, used for logging." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of role assignment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string" + }, + "name": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "principalType": "[[parameters('principalType')]", + "description": "[[parameters('description')]" + } + } + ], + "outputs": { + "roleAssignmentId": { + "type": "string", + "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + } + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[parameters('resourceId')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "principalType": { + "value": "[parameters('principalType')]" + }, + "description": { + "value": "[parameters('description')]" + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[parameters('name')]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The name for the role, used for logging." + }, + "value": "[parameters('roleName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/ptn/authorization/resource-role-assignment/modules/generic-role-assignment.json b/avm/1.1.0/ptn/authorization/resource-role-assignment/modules/generic-role-assignment.json new file mode 100644 index 000000000..2e18bcc95 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/resource-role-assignment/modules/generic-role-assignment.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string" + }, + "name": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[parameters('scope')]", + "name": "[parameters('name')]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('principalId')]", + "principalType": "[parameters('principalType')]", + "description": "[parameters('description')]" + } + } + ], + "outputs": { + "roleAssignmentId": { + "type": "string", + "value": "[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/all/dependencies.bicep b/avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/all/dependencies.bicep new file mode 100644 index 000000000..195c02ed8 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/all/dependencies.bicep @@ -0,0 +1,28 @@ +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/all/main.test.bicep b/avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/all/main.test.bicep new file mode 100644 index 000000000..2bc06f024 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/all/main.test.bicep @@ -0,0 +1,61 @@ +targetScope = 'subscription' +metadata name = 'Resource Role Assignments' +metadata description = 'This module deploys a Resource Role Assignment using all parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.resourceroleassignment-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'arraall' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + name: '${guid(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + scope: resourceGroup + params: { + resourceId: nestedDependencies.outputs.storageAccountResourceId + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + roleDefinitionId: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' + roleName: 'Storage Blob Data Reader' + description: 'Assign Storage Blob Data Reader role to the managed identity on the storage account.' + } + } +] diff --git a/avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..ac2fbefc4 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,28 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..252442bc3 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/resource-role-assignment/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,59 @@ +targetScope = 'subscription' +metadata name = 'Resource Role Assignments' +metadata description = 'This module deploys a Resource Role Assignment using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.resourceroleassignment-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'arramin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + name: '${guid(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + scope: resourceGroup + params: { + resourceId: nestedDependencies.outputs.storageAccountResourceId + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + roleDefinitionId: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' // Storage Blob Data Reader + } + } +] diff --git a/avm/1.1.0/ptn/authorization/resource-role-assignment/version.json b/avm/1.1.0/ptn/authorization/resource-role-assignment/version.json new file mode 100644 index 000000000..8def869ed --- /dev/null +++ b/avm/1.1.0/ptn/authorization/resource-role-assignment/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/ptn/authorization/role-assignment/README.md b/avm/1.1.0/ptn/authorization/role-assignment/README.md new file mode 100644 index 000000000..b5046b581 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/README.md @@ -0,0 +1,673 @@ +# Role Assignments (All scopes) `[Authorization/RoleAssignment]` + +This module deploys a Role Assignment at a Management Group, Subscription or Resource Group scope. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/authorization/role-assignment:`. + +- [Role Assignments (Management Group scope)](#example-1-role-assignments-management-group-scope) +- [Role Assignments (Management Group scope)](#example-2-role-assignments-management-group-scope) +- [Role Assignments (Resource Group scope)](#example-3-role-assignments-resource-group-scope) +- [Role Assignments (Resource Group)](#example-4-role-assignments-resource-group) +- [Role Assignments (Subscription scope)](#example-5-role-assignments-subscription-scope) +- [Role Assignments (Subscription scope)](#example-6-role-assignments-subscription-scope) + +### Example 1: _Role Assignments (Management Group scope)_ + +This module deploys a Role Assignment at a Management Group scope using minimal parameters. + + +

+ +via Bicep module + +```bicep +module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:' = { + name: 'roleAssignmentDeployment' + params: { + // Required parameters + principalId: '' + roleDefinitionIdOrName: 'Resource Policy Contributor' + // Non-required parameters + location: '' + principalType: 'ServicePrincipal' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "principalId": { + "value": "" + }, + "roleDefinitionIdOrName": { + "value": "Resource Policy Contributor" + }, + // Non-required parameters + "location": { + "value": "" + }, + "principalType": { + "value": "ServicePrincipal" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-assignment:' + +// Required parameters +param principalId = '' +param roleDefinitionIdOrName = 'Resource Policy Contributor' +// Non-required parameters +param location = '' +param principalType = 'ServicePrincipal' +``` + +
+

+ +### Example 2: _Role Assignments (Management Group scope)_ + +This module deploys a Role Assignment at a Management Group scope using common parameters. + + +

+ +via Bicep module + +```bicep +module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:' = { + name: 'roleAssignmentDeployment' + params: { + // Required parameters + principalId: '' + roleDefinitionIdOrName: 'Management Group Reader' + // Non-required parameters + description: 'Role Assignment (management group scope)' + location: '' + managementGroupId: '' + principalType: 'ServicePrincipal' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "principalId": { + "value": "" + }, + "roleDefinitionIdOrName": { + "value": "Management Group Reader" + }, + // Non-required parameters + "description": { + "value": "Role Assignment (management group scope)" + }, + "location": { + "value": "" + }, + "managementGroupId": { + "value": "" + }, + "principalType": { + "value": "ServicePrincipal" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-assignment:' + +// Required parameters +param principalId = '' +param roleDefinitionIdOrName = 'Management Group Reader' +// Non-required parameters +param description = 'Role Assignment (management group scope)' +param location = '' +param managementGroupId = '' +param principalType = 'ServicePrincipal' +``` + +
+

+ +### Example 3: _Role Assignments (Resource Group scope)_ + +This module deploys a Role Assignment at a Resource Group scope using minimal parameters. + + +

+ +via Bicep module + +```bicep +module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:' = { + name: 'roleAssignmentDeployment' + params: { + // Required parameters + principalId: '' + roleDefinitionIdOrName: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11' + // Non-required parameters + location: '' + principalType: 'ServicePrincipal' + resourceGroupName: '' + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "principalId": { + "value": "" + }, + "roleDefinitionIdOrName": { + "value": "/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11" + }, + // Non-required parameters + "location": { + "value": "" + }, + "principalType": { + "value": "ServicePrincipal" + }, + "resourceGroupName": { + "value": "" + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-assignment:' + +// Required parameters +param principalId = '' +param roleDefinitionIdOrName = '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11' +// Non-required parameters +param location = '' +param principalType = 'ServicePrincipal' +param resourceGroupName = '' +param subscriptionId = '' +``` + +
+

+ +### Example 4: _Role Assignments (Resource Group)_ + +This module deploys a Role Assignment at a Resource Group scope using common parameters. + + +

+ +via Bicep module + +```bicep +module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:' = { + name: 'roleAssignmentDeployment' + params: { + // Required parameters + principalId: '' + roleDefinitionIdOrName: 'Reader' + // Non-required parameters + description: 'Role Assignment (resource group scope)' + location: '' + principalType: 'ServicePrincipal' + resourceGroupName: '' + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "principalId": { + "value": "" + }, + "roleDefinitionIdOrName": { + "value": "Reader" + }, + // Non-required parameters + "description": { + "value": "Role Assignment (resource group scope)" + }, + "location": { + "value": "" + }, + "principalType": { + "value": "ServicePrincipal" + }, + "resourceGroupName": { + "value": "" + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-assignment:' + +// Required parameters +param principalId = '' +param roleDefinitionIdOrName = 'Reader' +// Non-required parameters +param description = 'Role Assignment (resource group scope)' +param location = '' +param principalType = 'ServicePrincipal' +param resourceGroupName = '' +param subscriptionId = '' +``` + +
+

+ +### Example 5: _Role Assignments (Subscription scope)_ + +This module deploys a Role Assignment at a Subscription scope using minimal parameters. + + +

+ +via Bicep module + +```bicep +module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:' = { + name: 'roleAssignmentDeployment' + params: { + // Required parameters + principalId: '' + roleDefinitionIdOrName: '' + // Non-required parameters + location: '' + principalType: 'ServicePrincipal' + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "principalId": { + "value": "" + }, + "roleDefinitionIdOrName": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + }, + "principalType": { + "value": "ServicePrincipal" + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-assignment:' + +// Required parameters +param principalId = '' +param roleDefinitionIdOrName = '' +// Non-required parameters +param location = '' +param principalType = 'ServicePrincipal' +param subscriptionId = '' +``` + +
+

+ +### Example 6: _Role Assignments (Subscription scope)_ + +This module deploys a Role Assignment at a Subscription scope using common parameters. + + +

+ +via Bicep module + +```bicep +module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:' = { + name: 'roleAssignmentDeployment' + params: { + // Required parameters + principalId: '' + roleDefinitionIdOrName: 'Reader' + // Non-required parameters + description: 'Role Assignment (subscription scope)' + location: '' + principalType: 'ServicePrincipal' + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "principalId": { + "value": "" + }, + "roleDefinitionIdOrName": { + "value": "Reader" + }, + // Non-required parameters + "description": { + "value": "Role Assignment (subscription scope)" + }, + "location": { + "value": "" + }, + "principalType": { + "value": "ServicePrincipal" + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-assignment:' + +// Required parameters +param principalId = '' +param roleDefinitionIdOrName = 'Reader' +// Non-required parameters +param description = 'Role Assignment (subscription scope)' +param location = '' +param principalType = 'ServicePrincipal' +param subscriptionId = '' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-principalid) | string | The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity). | +| [`roleDefinitionIdOrName`](#parameter-roledefinitionidorname) | string | You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-condition) | string | The conditions on the role assignment. This limits the resources it can be assigned to. | +| [`conditionVersion`](#parameter-conditionversion) | string | Version of the condition. Currently accepted value is "2.0". | +| [`delegatedManagedIdentityResourceId`](#parameter-delegatedmanagedidentityresourceid) | string | ID of the delegated managed identity resource. | +| [`description`](#parameter-description) | string | The description of the role assignment. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location deployment metadata. | +| [`managementGroupId`](#parameter-managementgroupid) | string | Group ID of the Management Group to assign the RBAC role to. If not provided, will use the current scope for deployment. | +| [`principalType`](#parameter-principaltype) | string | The principal type of the assigned principal ID. | +| [`resourceGroupName`](#parameter-resourcegroupname) | string | Name of the Resource Group to assign the RBAC role to. If Resource Group name is provided, and Subscription ID is provided, the module deploys at resource group level, therefore assigns the provided RBAC role to the resource group. | +| [`subscriptionId`](#parameter-subscriptionid) | string | Subscription ID of the subscription to assign the RBAC role to. If no Resource Group name is provided, the module deploys at subscription level, therefore assigns the provided RBAC role to the subscription. | + +### Parameter: `principalId` + +The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity). + +- Required: Yes +- Type: string + +### Parameter: `roleDefinitionIdOrName` + +You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `condition` + +The conditions on the role assignment. This limits the resources it can be assigned to. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `conditionVersion` + +Version of the condition. Currently accepted value is "2.0". + +- Required: No +- Type: string +- Default: `'2.0'` +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `delegatedManagedIdentityResourceId` + +ID of the delegated managed identity resource. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `description` + +The description of the role assignment. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location deployment metadata. + +- Required: No +- Type: string +- Default: `[deployment().location]` + +### Parameter: `managementGroupId` + +Group ID of the Management Group to assign the RBAC role to. If not provided, will use the current scope for deployment. + +- Required: No +- Type: string +- Default: `[managementGroup().name]` + +### Parameter: `principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `resourceGroupName` + +Name of the Resource Group to assign the RBAC role to. If Resource Group name is provided, and Subscription ID is provided, the module deploys at resource group level, therefore assigns the provided RBAC role to the resource group. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `subscriptionId` + +Subscription ID of the subscription to assign the RBAC role to. If no Resource Group name is provided, the module deploys at subscription level, therefore assigns the provided RBAC role to the subscription. + +- Required: No +- Type: string +- Default: `''` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The GUID of the Role Assignment. | +| `resourceId` | string | The resource ID of the Role Assignment. | +| `scope` | string | The scope this Role Assignment applies to. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/ptn/authorization/role-assignment/main.bicep b/avm/1.1.0/ptn/authorization/role-assignment/main.bicep new file mode 100644 index 000000000..b0777ade9 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/main.bicep @@ -0,0 +1,144 @@ +metadata name = 'Role Assignments (All scopes)' +metadata description = 'This module deploys a Role Assignment at a Management Group, Subscription or Resource Group scope.' + +targetScope = 'managementGroup' + +@sys.description('Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') +param roleDefinitionIdOrName string + +@sys.description('Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity).') +param principalId string + +@sys.description('Optional. Name of the Resource Group to assign the RBAC role to. If Resource Group name is provided, and Subscription ID is provided, the module deploys at resource group level, therefore assigns the provided RBAC role to the resource group.') +param resourceGroupName string = '' + +@sys.description('Optional. Subscription ID of the subscription to assign the RBAC role to. If no Resource Group name is provided, the module deploys at subscription level, therefore assigns the provided RBAC role to the subscription.') +param subscriptionId string = '' + +@sys.description('Optional. Group ID of the Management Group to assign the RBAC role to. If not provided, will use the current scope for deployment.') +param managementGroupId string = managementGroup().name + +@sys.description('Optional. Location deployment metadata.') +param location string = deployment().location + +@sys.description('Optional. The description of the role assignment.') +param description string = '' + +@sys.description('Optional. ID of the delegated managed identity resource.') +param delegatedManagedIdentityResourceId string = '' + +@sys.description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to.') +param condition string = '' + +@sys.description('Optional. Version of the condition. Currently accepted value is "2.0".') +@allowed([ + '2.0' +]) +param conditionVersion string = '2.0' + +@sys.description('Optional. The principal type of the assigned principal ID.') +@allowed([ + 'ServicePrincipal' + 'Group' + 'User' + 'ForeignGroup' + 'Device' + '' +]) +param principalType string = '' + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.authorization-roleassignment.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } + location: location +} + +module roleAssignment_mg 'modules/management-group.bicep' = if (empty(subscriptionId) && empty(resourceGroupName)) { + name: '${uniqueString(deployment().name, location)}-RoleAssignment-MG-Module' + scope: managementGroup(managementGroupId) + params: { + roleDefinitionIdOrName: roleDefinitionIdOrName + principalId: principalId + managementGroupId: managementGroupId + description: !empty(description) ? description : '' + principalType: !empty(principalType) ? principalType : '' + delegatedManagedIdentityResourceId: !empty(delegatedManagedIdentityResourceId) + ? delegatedManagedIdentityResourceId + : '' + conditionVersion: conditionVersion + condition: !empty(condition) ? condition : '' + } +} + +module roleAssignment_sub 'modules/subscription.bicep' = if (!empty(subscriptionId) && empty(resourceGroupName)) { + name: '${uniqueString(deployment().name, location)}-RoleAssignment-Sub-Module' + scope: subscription(subscriptionId) + params: { + roleDefinitionIdOrName: roleDefinitionIdOrName + principalId: principalId + subscriptionId: subscriptionId + description: !empty(description) ? description : '' + principalType: !empty(principalType) ? principalType : '' + delegatedManagedIdentityResourceId: !empty(delegatedManagedIdentityResourceId) + ? delegatedManagedIdentityResourceId + : '' + conditionVersion: conditionVersion + condition: !empty(condition) ? condition : '' + } +} + +module roleAssignment_rg 'modules/resource-group.bicep' = if (!empty(resourceGroupName) && !empty(subscriptionId)) { + name: '${uniqueString(deployment().name, location)}-RoleAssignment-RG-Module' + scope: resourceGroup(subscriptionId, resourceGroupName) + params: { + roleDefinitionIdOrName: roleDefinitionIdOrName + principalId: principalId + subscriptionId: subscriptionId + resourceGroupName: resourceGroupName + description: !empty(description) ? description : '' + principalType: !empty(principalType) ? principalType : '' + delegatedManagedIdentityResourceId: !empty(delegatedManagedIdentityResourceId) + ? delegatedManagedIdentityResourceId + : '' + conditionVersion: conditionVersion + condition: !empty(condition) ? condition : '' + } +} + +@sys.description('The GUID of the Role Assignment.') +output name string = empty(subscriptionId) && empty(resourceGroupName) + ? roleAssignment_mg.outputs.name + : (!empty(subscriptionId) && empty(resourceGroupName) + ? roleAssignment_sub.outputs.name + : roleAssignment_rg.outputs.name) + +@sys.description('The resource ID of the Role Assignment.') +output resourceId string = empty(subscriptionId) && empty(resourceGroupName) + ? roleAssignment_mg.outputs.resourceId + : (!empty(subscriptionId) && empty(resourceGroupName) + ? roleAssignment_sub.outputs.resourceId + : roleAssignment_rg.outputs.resourceId) + +@sys.description('The scope this Role Assignment applies to.') +output scope string = empty(subscriptionId) && empty(resourceGroupName) + ? roleAssignment_mg.outputs.scope + : (!empty(subscriptionId) && empty(resourceGroupName) + ? roleAssignment_sub.outputs.scope + : roleAssignment_rg.outputs.scope) diff --git a/avm/1.1.0/ptn/authorization/role-assignment/main.json b/avm/1.1.0/ptn/authorization/role-assignment/main.json new file mode 100644 index 000000000..2bbd025bb --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/main.json @@ -0,0 +1,662 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3151673760807490995" + }, + "name": "Role Assignments (All scopes)", + "description": "This module deploys a Role Assignment at a Management Group, Subscription or Resource Group scope." + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the Resource Group to assign the RBAC role to. If Resource Group name is provided, and Subscription ID is provided, the module deploys at resource group level, therefore assigns the provided RBAC role to the resource group." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If no Resource Group name is provided, the module deploys at subscription level, therefore assigns the provided RBAC role to the subscription." + } + }, + "managementGroupId": { + "type": "string", + "defaultValue": "[managementGroup().name]", + "metadata": { + "description": "Optional. Group ID of the Management Group to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location deployment metadata." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.authorization-roleassignment.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + }, + "location": "[parameters('location')]" + }, + { + "condition": "[and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-RoleAssignment-MG-Module', uniqueString(deployment().name, parameters('location')))]", + "scope": "[format('Microsoft.Management/managementGroups/{0}', parameters('managementGroupId'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "roleDefinitionIdOrName": { + "value": "[parameters('roleDefinitionIdOrName')]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "managementGroupId": { + "value": "[parameters('managementGroupId')]" + }, + "description": "[if(not(empty(parameters('description'))), createObject('value', parameters('description')), createObject('value', ''))]", + "principalType": "[if(not(empty(parameters('principalType'))), createObject('value', parameters('principalType')), createObject('value', ''))]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), createObject('value', parameters('delegatedManagedIdentityResourceId')), createObject('value', ''))]", + "conditionVersion": { + "value": "[parameters('conditionVersion')]" + }, + "condition": "[if(not(empty(parameters('condition'))), createObject('value', parameters('condition')), createObject('value', ''))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "2146197675736538693" + }, + "name": "Role Assignments (Management Group scope)", + "description": "This module deploys a Role Assignment at a Management Group scope." + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "managementGroupId": { + "type": "string", + "defaultValue": "[managementGroup().name]", + "metadata": { + "description": "Optional. Group ID of the Management Group to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "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": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Management Group Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ac63b705-f282-497d-ac71-919bf39d939d')]" + }, + "roleDefinitionIdVar": "[coalesce(tryGet(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), parameters('roleDefinitionIdOrName'))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('managementGroupId'), variables('roleDefinitionIdVar'), parameters('principalId'))]", + "properties": { + "roleDefinitionId": "[variables('roleDefinitionIdVar')]", + "principalId": "[parameters('principalId')]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[guid(parameters('managementGroupId'), variables('roleDefinitionIdVar'), parameters('principalId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[extensionResourceId(managementGroup().id, 'Microsoft.Authorization/roleAssignments', guid(parameters('managementGroupId'), variables('roleDefinitionIdVar'), parameters('principalId')))]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[resourceId('Microsoft.Management/managementGroups', parameters('managementGroupId'))]" + } + } + } + } + }, + { + "condition": "[and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-RoleAssignment-Sub-Module', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[parameters('subscriptionId')]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "roleDefinitionIdOrName": { + "value": "[parameters('roleDefinitionIdOrName')]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "subscriptionId": { + "value": "[parameters('subscriptionId')]" + }, + "description": "[if(not(empty(parameters('description'))), createObject('value', parameters('description')), createObject('value', ''))]", + "principalType": "[if(not(empty(parameters('principalType'))), createObject('value', parameters('principalType')), createObject('value', ''))]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), createObject('value', parameters('delegatedManagedIdentityResourceId')), createObject('value', ''))]", + "conditionVersion": { + "value": "[parameters('conditionVersion')]" + }, + "condition": "[if(not(empty(parameters('condition'))), createObject('value', parameters('condition')), createObject('value', ''))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "18268822790511715012" + }, + "name": "Role Assignments (Subscription scope)", + "description": "This module deploys a Role Assignment at a Subscription scope." + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "roleDefinitionIdVar": "[coalesce(tryGet(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), parameters('roleDefinitionIdOrName'))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), variables('roleDefinitionIdVar'), parameters('principalId'))]", + "properties": { + "roleDefinitionId": "[variables('roleDefinitionIdVar')]", + "principalId": "[parameters('principalId')]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[guid(parameters('subscriptionId'), variables('roleDefinitionIdVar'), parameters('principalId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[subscriptionResourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), variables('roleDefinitionIdVar'), parameters('principalId')))]" + }, + "subscriptionName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[subscription().displayName]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[subscription().id]" + } + } + } + } + }, + { + "condition": "[and(not(empty(parameters('resourceGroupName'))), not(empty(parameters('subscriptionId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-RoleAssignment-RG-Module', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "roleDefinitionIdOrName": { + "value": "[parameters('roleDefinitionIdOrName')]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "subscriptionId": { + "value": "[parameters('subscriptionId')]" + }, + "resourceGroupName": { + "value": "[parameters('resourceGroupName')]" + }, + "description": "[if(not(empty(parameters('description'))), createObject('value', parameters('description')), createObject('value', ''))]", + "principalType": "[if(not(empty(parameters('principalType'))), createObject('value', parameters('principalType')), createObject('value', ''))]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), createObject('value', parameters('delegatedManagedIdentityResourceId')), createObject('value', ''))]", + "conditionVersion": { + "value": "[parameters('conditionVersion')]" + }, + "condition": "[if(not(empty(parameters('condition'))), createObject('value', parameters('condition')), createObject('value', ''))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "8200662209265445642" + }, + "name": "Role Assignments (Resource Group scope)", + "description": "This module deploys a Role Assignment at a Resource Group scope." + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "roleDefinitionIdVar": "[coalesce(tryGet(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), parameters('roleDefinitionIdOrName'))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", + "properties": { + "roleDefinitionId": "[variables('roleDefinitionIdVar')]", + "principalId": "[parameters('principalId')]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[resourceGroup().id]" + } + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-RoleAssignment-MG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.name.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference(subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('{0}-RoleAssignment-Sub-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.name.value, reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('{0}-RoleAssignment-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.name.value))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-RoleAssignment-MG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.resourceId.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference(subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('{0}-RoleAssignment-Sub-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.resourceId.value, reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('{0}-RoleAssignment-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.resourceId.value))]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-RoleAssignment-MG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.scope.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference(subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('{0}-RoleAssignment-Sub-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.scope.value, reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('{0}-RoleAssignment-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.scope.value))]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/ptn/authorization/role-assignment/modules/management-group.bicep b/avm/1.1.0/ptn/authorization/role-assignment/modules/management-group.bicep new file mode 100644 index 000000000..ddb61d447 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/modules/management-group.bicep @@ -0,0 +1,87 @@ +metadata name = 'Role Assignments (Management Group scope)' +metadata description = 'This module deploys a Role Assignment at a Management Group scope.' + +targetScope = 'managementGroup' + +@sys.description('Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') +param roleDefinitionIdOrName string + +@sys.description('Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity).') +param principalId string + +@sys.description('Optional. Group ID of the Management Group to assign the RBAC role to. If not provided, will use the current scope for deployment.') +param managementGroupId string = managementGroup().name + +@sys.description('Optional. The description of the role assignment.') +param description string = '' + +@sys.description('Optional. ID of the delegated managed identity resource.') +param delegatedManagedIdentityResourceId string = '' + +@sys.description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to.') +param condition string = '' + +@sys.description('Optional. Version of the condition. Currently accepted value is "2.0".') +@allowed([ + '2.0' +]) +param conditionVersion string = '2.0' + +@sys.description('Optional. The principal type of the assigned principal ID.') +@allowed([ + 'ServicePrincipal' + 'Group' + 'User' + 'ForeignGroup' + 'Device' + '' +]) +param principalType string = '' + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 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': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) + 'Management Group Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'ac63b705-f282-497d-ac71-919bf39d939d' + ) +} + +var roleDefinitionIdVar = (builtInRoleNames[?roleDefinitionIdOrName] ?? roleDefinitionIdOrName) + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(managementGroupId, roleDefinitionIdVar, principalId) + properties: { + roleDefinitionId: roleDefinitionIdVar + principalId: principalId + description: !empty(description) ? description : null + principalType: !empty(principalType) ? any(principalType) : null + delegatedManagedIdentityResourceId: !empty(delegatedManagedIdentityResourceId) + ? delegatedManagedIdentityResourceId + : null + conditionVersion: !empty(conditionVersion) && !empty(condition) ? conditionVersion : null + condition: !empty(condition) ? condition : null + } +} + +@sys.description('The GUID of the Role Assignment.') +output name string = roleAssignment.name + +@sys.description('The resource ID of the Role Assignment.') +output resourceId string = roleAssignment.id + +@sys.description('The scope this Role Assignment applies to.') +output scope string = az.resourceId('Microsoft.Management/managementGroups', managementGroupId) diff --git a/avm/1.1.0/ptn/authorization/role-assignment/modules/resource-group.bicep b/avm/1.1.0/ptn/authorization/role-assignment/modules/resource-group.bicep new file mode 100644 index 000000000..c73d5d07f --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/modules/resource-group.bicep @@ -0,0 +1,85 @@ +metadata name = 'Role Assignments (Resource Group scope)' +metadata description = 'This module deploys a Role Assignment at a Resource Group scope.' + +targetScope = 'resourceGroup' + +@sys.description('Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') +param roleDefinitionIdOrName string + +@sys.description('Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity).') +param principalId string + +@sys.description('Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment.') +param resourceGroupName string = resourceGroup().name + +@sys.description('Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment.') +param subscriptionId string = subscription().subscriptionId + +@sys.description('Optional. The description of the role assignment.') +param description string = '' + +@sys.description('Optional. ID of the delegated managed identity resource.') +param delegatedManagedIdentityResourceId string = '' + +@sys.description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to.') +param condition string = '' + +@sys.description('Optional. Version of the condition. Currently accepted value is "2.0".') +@allowed([ + '2.0' +]) +param conditionVersion string = '2.0' + +@sys.description('Optional. The principal type of the assigned principal ID.') +@allowed([ + 'ServicePrincipal' + 'Group' + 'User' + 'ForeignGroup' + 'Device' + '' +]) +param principalType string + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var roleDefinitionIdVar = (builtInRoleNames[?roleDefinitionIdOrName] ?? roleDefinitionIdOrName) + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscriptionId, resourceGroupName, roleDefinitionIdVar, principalId) + properties: { + roleDefinitionId: roleDefinitionIdVar + principalId: principalId + description: !empty(description) ? description : null + principalType: !empty(principalType) ? any(principalType) : null + delegatedManagedIdentityResourceId: !empty(delegatedManagedIdentityResourceId) + ? delegatedManagedIdentityResourceId + : null + conditionVersion: !empty(conditionVersion) && !empty(condition) ? conditionVersion : null + condition: !empty(condition) ? condition : null + } +} + +@sys.description('The GUID of the Role Assignment.') +output name string = roleAssignment.name + +@sys.description('The resource ID of the Role Assignment.') +output resourceId string = roleAssignment.id + +@sys.description('The name of the resource group the role assignment was applied at.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The scope this Role Assignment applies to.') +output scope string = resourceGroup().id diff --git a/avm/1.1.0/ptn/authorization/role-assignment/modules/subscription.bicep b/avm/1.1.0/ptn/authorization/role-assignment/modules/subscription.bicep new file mode 100644 index 000000000..1142912b4 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/modules/subscription.bicep @@ -0,0 +1,82 @@ +metadata name = 'Role Assignments (Subscription scope)' +metadata description = 'This module deploys a Role Assignment at a Subscription scope.' + +targetScope = 'subscription' + +@sys.description('Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') +param roleDefinitionIdOrName string + +@sys.description('Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity).') +param principalId string + +@sys.description('Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment.') +param subscriptionId string = subscription().subscriptionId + +@sys.description('Optional. The description of the role assignment.') +param description string = '' + +@sys.description('Optional. ID of the delegated managed identity resource.') +param delegatedManagedIdentityResourceId string = '' + +@sys.description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to.') +param condition string = '' + +@sys.description('Optional. Version of the condition. Currently accepted value is "2.0".') +@allowed([ + '2.0' +]) +param conditionVersion string = '2.0' + +@sys.description('Optional. The principal type of the assigned principal ID.') +@allowed([ + 'ServicePrincipal' + 'Group' + 'User' + 'ForeignGroup' + 'Device' + '' +]) +param principalType string = '' + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var roleDefinitionIdVar = (builtInRoleNames[?roleDefinitionIdOrName] ?? roleDefinitionIdOrName) + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscriptionId, roleDefinitionIdVar, principalId) + properties: { + roleDefinitionId: roleDefinitionIdVar + principalId: principalId + description: !empty(description) ? description : null + principalType: !empty(principalType) ? any(principalType) : null + delegatedManagedIdentityResourceId: !empty(delegatedManagedIdentityResourceId) + ? delegatedManagedIdentityResourceId + : null + conditionVersion: !empty(conditionVersion) && !empty(condition) ? conditionVersion : null + condition: !empty(condition) ? condition : null + } +} + +@sys.description('The GUID of the Role Assignment.') +output name string = roleAssignment.name + +@sys.description('The resource ID of the Role Assignment.') +output resourceId string = roleAssignment.id + +@sys.description('The name of the resource group the role assignment was applied at.') +output subscriptionName string = subscription().displayName + +@sys.description('The scope this Role Assignment applies to.') +output scope string = subscription().id diff --git a/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.defaults/dependencies.bicep b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.defaults/dependencies.bicep new file mode 100644 index 000000000..d36777043 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.defaults/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.defaults/main.test.bicep b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.defaults/main.test.bicep new file mode 100644 index 000000000..197bc7745 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.defaults/main.test.bicep @@ -0,0 +1,64 @@ +targetScope = 'managementGroup' +metadata name = 'Role Assignments (Management Group scope)' +metadata description = 'This module deploys a Role Assignment at a Management Group scope using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.roleassignments-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'aramgmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. Subscription ID of the subscription to assign the RBAC role to. If no Resource Group name is provided, the module deploys at subscription level, therefore assigns the provided RBAC role to the subscription.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +module resourceGroup 'br/public:avm/res/resources/resource-group:0.2.3' = { + scope: subscription('${subscriptionId}') + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: resourceGroupName + location: resourceLocation + } +} + +module nestedDependencies 'dependencies.bicep' = { + scope: az.resourceGroup(subscriptionId, resourceGroupName) + name: '${uniqueString(deployment().name, resourceLocation)}-${serviceShort}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } + dependsOn: [ + resourceGroup + ] +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + roleDefinitionIdOrName: 'Resource Policy Contributor' + principalType: 'ServicePrincipal' + location: resourceLocation + } +} diff --git a/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.max/dependencies.bicep b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.max/dependencies.bicep new file mode 100644 index 000000000..d36777043 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.max/main.test.bicep b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.max/main.test.bicep new file mode 100644 index 000000000..f5823ecf2 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/mg.max/main.test.bicep @@ -0,0 +1,66 @@ +targetScope = 'managementGroup' +metadata name = 'Role Assignments (Management Group scope)' +metadata description = 'This module deploys a Role Assignment at a Management Group scope using common parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.roleassignments-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'aramgmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. Subscription ID of the subscription to assign the RBAC role to. If no Resource Group name is provided, the module deploys at subscription level, therefore assigns the provided RBAC role to the subscription.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +module resourceGroup 'br/public:avm/res/resources/resource-group:0.2.3' = { + scope: subscription('${subscriptionId}') + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: resourceGroupName + location: resourceLocation + } +} + +module nestedDependencies 'dependencies.bicep' = { + scope: az.resourceGroup(subscriptionId, resourceGroupName) + name: '${uniqueString(deployment().name, resourceLocation)}-${serviceShort}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } + dependsOn: [ + resourceGroup + ] +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + roleDefinitionIdOrName: 'Management Group Reader' + description: 'Role Assignment (management group scope)' + managementGroupId: last(split(managementGroup().id, '/')) + principalType: 'ServicePrincipal' + location: resourceLocation + } +} diff --git a/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.default/dependencies.bicep b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.default/dependencies.bicep new file mode 100644 index 000000000..5681a8998 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.default/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.default/main.test.bicep b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.default/main.test.bicep new file mode 100644 index 000000000..f1ceac719 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.default/main.test.bicep @@ -0,0 +1,65 @@ +targetScope = 'managementGroup' +metadata name = 'Role Assignments (Resource Group scope)' +metadata description = 'This module deploys a Role Assignment at a Resource Group scope using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.roleassignments-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'arargmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. Subscription ID of the subscription to assign the RBAC role to. If no Resource Group name is provided, the module deploys at subscription level, therefore assigns the provided RBAC role to the subscription.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +module resourceGroup 'br/public:avm/res/resources/resource-group:0.2.3' = { + scope: subscription('${subscriptionId}') + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: resourceGroupName + location: resourceLocation + } +} +module nestedDependencies 'dependencies.bicep' = { + scope: az.resourceGroup(subscriptionId, resourceGroupName) + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } + dependsOn: [ + resourceGroup + ] +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + roleDefinitionIdOrName: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11' + principalType: 'ServicePrincipal' + location: resourceLocation + subscriptionId: subscriptionId + resourceGroupName: resourceGroup.outputs.name + } +} diff --git a/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.max/dependencies.bicep b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.max/dependencies.bicep new file mode 100644 index 000000000..5681a8998 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.max/main.test.bicep b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.max/main.test.bicep new file mode 100644 index 000000000..d99d0486d --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/rg.max/main.test.bicep @@ -0,0 +1,67 @@ +targetScope = 'managementGroup' +metadata name = 'Role Assignments (Resource Group)' +metadata description = 'This module deploys a Role Assignment at a Resource Group scope using common parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.roleassignments-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'arargmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. Subscription ID of the subscription to assign the RBAC role to. If no Resource Group name is provided, the module deploys at subscription level, therefore assigns the provided RBAC role to the subscription.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +module resourceGroup 'br/public:avm/res/resources/resource-group:0.2.3' = { + scope: subscription('${subscriptionId}') + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: resourceGroupName + location: resourceLocation + } +} + +module nestedDependencies 'dependencies.bicep' = { + scope: az.resourceGroup(subscriptionId, resourceGroupName) + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } + dependsOn: [ + resourceGroup + ] +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + roleDefinitionIdOrName: 'Reader' + description: 'Role Assignment (resource group scope)' + principalType: 'ServicePrincipal' + location: resourceLocation + subscriptionId: subscriptionId + resourceGroupName: resourceGroup.outputs.name + } +} diff --git a/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.default/dependencies.bicep b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.default/dependencies.bicep new file mode 100644 index 000000000..d36777043 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.default/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.default/main.test.bicep b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.default/main.test.bicep new file mode 100644 index 000000000..a75d2689c --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.default/main.test.bicep @@ -0,0 +1,69 @@ +targetScope = 'managementGroup' +metadata name = 'Role Assignments (Subscription scope)' +metadata description = 'This module deploys a Role Assignment at a Subscription scope using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.roleassignments-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'arasubmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. Subscription ID of the subscription to assign the RBAC role to. If no Resource Group name is provided, the module deploys at subscription level, therefore assigns the provided RBAC role to the subscription.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +module resourceGroup 'br/public:avm/res/resources/resource-group:0.2.3' = { + scope: subscription('${subscriptionId}') + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: resourceGroupName + location: resourceLocation + } +} + +module nestedDependencies 'dependencies.bicep' = { + scope: az.resourceGroup(subscriptionId, resourceGroupName) + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } + dependsOn: [ + resourceGroup + ] +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalType: 'ServicePrincipal' + location: resourceLocation + subscriptionId: subscriptionId + } +} diff --git a/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.max/dependencies.bicep b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.max/dependencies.bicep new file mode 100644 index 000000000..d36777043 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.max/main.test.bicep b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.max/main.test.bicep new file mode 100644 index 000000000..2fa7aec23 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/tests/e2e/sub.max/main.test.bicep @@ -0,0 +1,66 @@ +targetScope = 'managementGroup' +metadata name = 'Role Assignments (Subscription scope)' +metadata description = 'This module deploys a Role Assignment at a Subscription scope using common parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-authorization.roleassignments-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'arasubmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. Subscription ID of the subscription to assign the RBAC role to. If no Resource Group name is provided, the module deploys at subscription level, therefore assigns the provided RBAC role to the subscription.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +module resourceGroup 'br/public:avm/res/resources/resource-group:0.2.3' = { + scope: subscription('${subscriptionId}') + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: resourceGroupName + location: resourceLocation + } +} +module nestedDependencies 'dependencies.bicep' = { + scope: az.resourceGroup(subscriptionId, resourceGroupName) + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } + dependsOn: [ + resourceGroup + ] +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + roleDefinitionIdOrName: 'Reader' + description: 'Role Assignment (subscription scope)' + principalType: 'ServicePrincipal' + location: resourceLocation + subscriptionId: subscriptionId + } +} diff --git a/avm/1.1.0/ptn/authorization/role-assignment/version.json b/avm/1.1.0/ptn/authorization/role-assignment/version.json new file mode 100644 index 000000000..1c035df49 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-assignment/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.2", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/ptn/authorization/role-definition/README.md b/avm/1.1.0/ptn/authorization/role-definition/README.md new file mode 100644 index 000000000..c6339e376 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-definition/README.md @@ -0,0 +1,302 @@ +# avm/ptn/authorization/role-definition `[Authorization/RoleDefinition]` + +This module deploys a custom role definition to a Management Group. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleDefinitions` | [2022-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-05-01-preview/roleDefinitions) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/authorization/role-definition:`. + +- [Role Definition (Management Group scope) - Required Parameters](#example-1-role-definition-management-group-scope---required-parameters) +- [Role Definition (Management Group scope) - Using loadJsonContent](#example-2-role-definition-management-group-scope---using-loadjsoncontent) + +### Example 1: _Role Definition (Management Group scope) - Required Parameters_ + +This module deploys a Role Definition at a Management Group scope using minimal parameters. + + +

+ +via Bicep module + +```bicep +module roleDefinition 'br/public:avm/ptn/authorization/role-definition:' = { + name: 'roleDefinitionDeployment' + params: { + // Required parameters + name: 'rbac-custom-role-reader' + // Non-required parameters + actions: [ + '*/read' + ] + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "rbac-custom-role-reader" + }, + // Non-required parameters + "actions": { + "value": [ + "*/read" + ] + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-definition:' + +// Required parameters +param name = 'rbac-custom-role-reader' +// Non-required parameters +param actions = [ + '*/read' +] +param location = '' +``` + +
+

+ +### Example 2: _Role Definition (Management Group scope) - Using loadJsonContent_ + +This module deploys a Role Definition at a Management Group scope using loadJsonContent to load a custom role definition stored in a JSON file. + + +

+ +via Bicep module + +```bicep +module roleDefinition 'br/public:avm/ptn/authorization/role-definition:' = { + name: 'roleDefinitionDeployment' + params: { + // Required parameters + name: '' + // Non-required parameters + actions: '' + dataActions: '' + description: '' + location: '' + notActions: '' + notDataActions: '' + roleName: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "" + }, + // Non-required parameters + "actions": { + "value": "" + }, + "dataActions": { + "value": "" + }, + "description": { + "value": "" + }, + "location": { + "value": "" + }, + "notActions": { + "value": "" + }, + "notDataActions": { + "value": "" + }, + "roleName": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-definition:' + +// Required parameters +param name = '' +// Non-required parameters +param actions = '' +param dataActions = '' +param description = '' +param location = '' +param notActions = '' +param notDataActions = '' +param roleName = '' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the custom role definition. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`actions`](#parameter-actions) | array | The permission actions of the custom role definition. | +| [`assignableScopes`](#parameter-assignablescopes) | array | The assignable scopes of the custom role definition. If not specified, the management group being targeted in the parameter managementGroupName will be used. | +| [`dataActions`](#parameter-dataactions) | array | The permission data actions of the custom role definition. | +| [`description`](#parameter-description) | string | The description of the custom role definition. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | The location of the telemetry deployment to be created. Default is location of deployment. | +| [`notActions`](#parameter-notactions) | array | The permission not actions of the custom role definition. | +| [`notDataActions`](#parameter-notdataactions) | array | The permission not data actions of the custom role definition. | +| [`roleName`](#parameter-rolename) | string | The display name of the custom role definition. If not specified, the name will be used. | + +### Parameter: `name` + +The name of the custom role definition. + +- Required: Yes +- Type: string + +### Parameter: `actions` + +The permission actions of the custom role definition. + +- Required: No +- Type: array + +### Parameter: `assignableScopes` + +The assignable scopes of the custom role definition. If not specified, the management group being targeted in the parameter managementGroupName will be used. + +- Required: No +- Type: array + +### Parameter: `dataActions` + +The permission data actions of the custom role definition. + +- Required: No +- Type: array + +### Parameter: `description` + +The description of the custom role definition. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +The location of the telemetry deployment to be created. Default is location of deployment. + +- Required: No +- Type: string +- Default: `[deployment().location]` + +### Parameter: `notActions` + +The permission not actions of the custom role definition. + +- Required: No +- Type: array + +### Parameter: `notDataActions` + +The permission not data actions of the custom role definition. + +- Required: No +- Type: array + +### Parameter: `roleName` + +The display name of the custom role definition. If not specified, the name will be used. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `managementGroupCustomRoleDefinitionIds` | object | An object containing the resourceId, roleDefinitionId, and displayName of the custom role definition. | +| `roleDefinitionIdName` | string | The ID/name of the custom role definition created. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/ptn/authorization/role-definition/main.bicep b/avm/1.1.0/ptn/authorization/role-definition/main.bicep new file mode 100644 index 000000000..2ef438ad3 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-definition/main.bicep @@ -0,0 +1,98 @@ +metadata name = 'avm/ptn/authorization/role-definition' +metadata description = 'This module deploys a custom role definition to a Management Group.' + +targetScope = 'managementGroup' + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@sys.description('Optional. The location of the telemetry deployment to be created. Default is location of deployment.') +param location string = deployment().location + +@sys.description('Required. The name of the custom role definition.') +param name string + +@sys.description('Optional. The description of the custom role definition.') +param description string? + +@sys.description('Optional. The assignable scopes of the custom role definition. If not specified, the management group being targeted in the parameter managementGroupName will be used.') +param assignableScopes array? + +@sys.description('Optional. The permission actions of the custom role definition.') +param actions array? + +@sys.description('Optional. The permission not actions of the custom role definition.') +param notActions array? + +@sys.description('Optional. The permission data actions of the custom role definition.') +param dataActions array? + +@sys.description('Optional. The permission not data actions of the custom role definition.') +param notDataActions array? + +@sys.description('Optional. The display name of the custom role definition. If not specified, the name will be used.') +param roleName string? + +// ============ // +// Variables // +// ============ // + +var roleDefNameFinalGuid = contains(name, '-') && length(name) == 36 && length(split(name, '-')) == 5 + ? name + : guid(name) + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.authorization-roledefinition.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + location: location + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource res_roleDefinition_mg 'Microsoft.Authorization/roleDefinitions@2022-05-01-preview' = { + name: roleDefNameFinalGuid + properties: { + roleName: roleName ?? roleDefNameFinalGuid + description: description + type: 'CustomRole' + assignableScopes: !empty(assignableScopes) ? assignableScopes : [managementGroup().id] + permissions: [ + { + actions: actions ?? [] + notActions: notActions ?? [] + dataActions: dataActions ?? [] + notDataActions: notDataActions ?? [] + } + ] + } +} + +// ============ // +// Outputs // +// ============ // + +@sys.description('An object containing the resourceId, roleDefinitionId, and displayName of the custom role definition.') +output managementGroupCustomRoleDefinitionIds object = { + resourceId: res_roleDefinition_mg.id + roleDefinitionIdName: res_roleDefinition_mg.name + displayName: res_roleDefinition_mg.properties.roleName +} + +@sys.description('The ID/name of the custom role definition created.') +output roleDefinitionIdName string = res_roleDefinition_mg.id diff --git a/avm/1.1.0/ptn/authorization/role-definition/main.json b/avm/1.1.0/ptn/authorization/role-definition/main.json new file mode 100644 index 000000000..4a0f67c5d --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-definition/main.json @@ -0,0 +1,150 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "13498060084797132903" + }, + "name": "avm/ptn/authorization/role-definition", + "description": "This module deploys a custom role definition to a Management Group." + }, + "parameters": { + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. The location of the telemetry deployment to be created. Default is location of deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the custom role definition." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the custom role definition." + } + }, + "assignableScopes": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The assignable scopes of the custom role definition. If not specified, the management group being targeted in the parameter managementGroupName will be used." + } + }, + "actions": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The permission actions of the custom role definition." + } + }, + "notActions": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The permission not actions of the custom role definition." + } + }, + "dataActions": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The permission data actions of the custom role definition." + } + }, + "notDataActions": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The permission not data actions of the custom role definition." + } + }, + "roleName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The display name of the custom role definition. If not specified, the name will be used." + } + } + }, + "variables": { + "roleDefNameFinalGuid": "[if(and(and(contains(parameters('name'), '-'), equals(length(parameters('name')), 36)), equals(length(split(parameters('name'), '-')), 5)), parameters('name'), guid(parameters('name')))]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.authorization-roledefinition.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "location": "[parameters('location')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "res_roleDefinition_mg": { + "type": "Microsoft.Authorization/roleDefinitions", + "apiVersion": "2022-05-01-preview", + "name": "[variables('roleDefNameFinalGuid')]", + "properties": { + "roleName": "[coalesce(parameters('roleName'), variables('roleDefNameFinalGuid'))]", + "description": "[parameters('description')]", + "type": "CustomRole", + "assignableScopes": "[if(not(empty(parameters('assignableScopes'))), parameters('assignableScopes'), createArray(managementGroup().id))]", + "permissions": [ + { + "actions": "[coalesce(parameters('actions'), createArray())]", + "notActions": "[coalesce(parameters('notActions'), createArray())]", + "dataActions": "[coalesce(parameters('dataActions'), createArray())]", + "notDataActions": "[coalesce(parameters('notDataActions'), createArray())]" + } + ] + } + } + }, + "outputs": { + "managementGroupCustomRoleDefinitionIds": { + "type": "object", + "metadata": { + "description": "An object containing the resourceId, roleDefinitionId, and displayName of the custom role definition." + }, + "value": { + "resourceId": "[extensionResourceId(managementGroup().id, 'Microsoft.Authorization/roleDefinitions', variables('roleDefNameFinalGuid'))]", + "roleDefinitionIdName": "[variables('roleDefNameFinalGuid')]", + "displayName": "[reference('res_roleDefinition_mg').roleName]" + } + }, + "roleDefinitionIdName": { + "type": "string", + "metadata": { + "description": "The ID/name of the custom role definition created." + }, + "value": "[extensionResourceId(managementGroup().id, 'Microsoft.Authorization/roleDefinitions', variables('roleDefNameFinalGuid'))]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/ptn/authorization/role-definition/tests/e2e/mg.default/main.test.bicep b/avm/1.1.0/ptn/authorization/role-definition/tests/e2e/mg.default/main.test.bicep new file mode 100644 index 000000000..13b27a9c9 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-definition/tests/e2e/mg.default/main.test.bicep @@ -0,0 +1,31 @@ +targetScope = 'managementGroup' +metadata name = 'Role Definition (Management Group scope) - Required Parameters' +metadata description = 'This module deploys a Role Definition at a Management Group scope using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'acrdmgmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}-rbac-custom-role-reader' + actions: [ + '*/read' + ] + location: resourceLocation + } +} diff --git a/avm/1.1.0/ptn/authorization/role-definition/tests/e2e/mg.loadJson/lib/subscription_owner.alz_role_definition.json b/avm/1.1.0/ptn/authorization/role-definition/tests/e2e/mg.loadJson/lib/subscription_owner.alz_role_definition.json new file mode 100644 index 000000000..b09d16ac6 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-definition/tests/e2e/mg.loadJson/lib/subscription_owner.alz_role_definition.json @@ -0,0 +1,27 @@ +{ + "name": "402344ce-48c4-5ac1-9320-16726050f964", + "type": "Microsoft.Authorization/roleDefinitions", + "apiVersion": "2018-01-01-preview", + "properties": { + "roleName": "Subscription-Owner", + "description": "Delegated role for subscription owner generated from subscription Owner role", + "type": "CustomRole", + "permissions": [ + { + "actions": [ + "*" + ], + "notActions": [ + "Microsoft.Authorization/*/write", + "Microsoft.Network/vpnGateways/*", + "Microsoft.Network/expressRouteCircuits/*", + "Microsoft.Network/routeTables/write", + "Microsoft.Network/vpnSites/*" + ], + "dataActions": [], + "notDataActions": [] + } + ], + "assignableScopes": [] + } +} \ No newline at end of file diff --git a/avm/1.1.0/ptn/authorization/role-definition/tests/e2e/mg.loadJson/main.test.bicep b/avm/1.1.0/ptn/authorization/role-definition/tests/e2e/mg.loadJson/main.test.bicep new file mode 100644 index 000000000..19cbe4a35 --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-definition/tests/e2e/mg.loadJson/main.test.bicep @@ -0,0 +1,36 @@ +targetScope = 'managementGroup' +metadata name = 'Role Definition (Management Group scope) - Using loadJsonContent' +metadata description = 'This module deploys a Role Definition at a Management Group scope using loadJsonContent to load a custom role definition stored in a JSON file.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'acrdmgjson' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +// ============== // +// Test Execution // +// ============== // + +param customRoleDefinitionJson object = loadJsonContent('lib/subscription_owner.alz_role_definition.json') + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: customRoleDefinitionJson.name + roleName: customRoleDefinitionJson.properties.roleName + description: customRoleDefinitionJson.properties.description + actions: customRoleDefinitionJson.properties.permissions[0].actions + notActions: customRoleDefinitionJson.properties.permissions[0].notActions + dataActions: customRoleDefinitionJson.properties.permissions[0].dataActions + notDataActions: customRoleDefinitionJson.properties.permissions[0].notDataActions + location: resourceLocation + } +} diff --git a/avm/1.1.0/ptn/authorization/role-definition/version.json b/avm/1.1.0/ptn/authorization/role-definition/version.json new file mode 100644 index 000000000..8def869ed --- /dev/null +++ b/avm/1.1.0/ptn/authorization/role-definition/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/ptn/policy-insights/remediation/README.md b/avm/1.1.0/ptn/policy-insights/remediation/README.md new file mode 100644 index 000000000..521a3c10d --- /dev/null +++ b/avm/1.1.0/ptn/policy-insights/remediation/README.md @@ -0,0 +1,734 @@ +# Policy Insights Remediations `[PolicyInsights/Remediation]` + +This module deploys a Policy Insights Remediation. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.PolicyInsights/remediations` | [2021-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.PolicyInsights/2021-10-01/remediations) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/policy-insights/remediation:`. + +- [Policy Remediation (Management Group scope)](#example-1-policy-remediation-management-group-scope) +- [Policy Remediation (Management Group scope)](#example-2-policy-remediation-management-group-scope) +- [Policy Remediation (Resource Group scope)](#example-3-policy-remediation-resource-group-scope) +- [Policy Remediation (Resource Group scope)](#example-4-policy-remediation-resource-group-scope) +- [Policy Remediation (Subscription scope)](#example-5-policy-remediation-subscription-scope) +- [Policy Remediation (Subscription scope)](#example-6-policy-remediation-subscription-scope) + +### Example 1: _Policy Remediation (Management Group scope)_ + +This module runs a Policy remediation task at Management Group scope using minimal parameters. + + +

+ +via Bicep module + +```bicep +module remediation 'br/public:avm/ptn/policy-insights/remediation:' = { + name: 'remediationDeployment' + params: { + // Required parameters + name: 'pirmgmin001' + policyAssignmentId: '' + // Non-required parameters + location: '' + policyDefinitionReferenceId: 'Prerequisite_DeployExtensionWindows' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "pirmgmin001" + }, + "policyAssignmentId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + }, + "policyDefinitionReferenceId": { + "value": "Prerequisite_DeployExtensionWindows" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/policy-insights/remediation:' + +// Required parameters +param name = 'pirmgmin001' +param policyAssignmentId = '' +// Non-required parameters +param location = '' +param policyDefinitionReferenceId = 'Prerequisite_DeployExtensionWindows' +``` + +
+

+ +### Example 2: _Policy Remediation (Management Group scope)_ + +This module runs a Policy remediation task at Management Group scope using common parameters. + + +

+ +via Bicep module + +```bicep +module remediation 'br/public:avm/ptn/policy-insights/remediation:' = { + name: 'remediationDeployment' + params: { + // Required parameters + name: 'pirmgmax001' + policyAssignmentId: '' + // Non-required parameters + failureThresholdPercentage: '0.5' + filtersLocations: [] + location: '' + parallelDeployments: 1 + policyDefinitionReferenceId: 'Prerequisite_DeployExtensionWindows' + resourceCount: 10 + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "pirmgmax001" + }, + "policyAssignmentId": { + "value": "" + }, + // Non-required parameters + "failureThresholdPercentage": { + "value": "0.5" + }, + "filtersLocations": { + "value": [] + }, + "location": { + "value": "" + }, + "parallelDeployments": { + "value": 1 + }, + "policyDefinitionReferenceId": { + "value": "Prerequisite_DeployExtensionWindows" + }, + "resourceCount": { + "value": 10 + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/policy-insights/remediation:' + +// Required parameters +param name = 'pirmgmax001' +param policyAssignmentId = '' +// Non-required parameters +param failureThresholdPercentage = '0.5' +param filtersLocations = [] +param location = '' +param parallelDeployments = 1 +param policyDefinitionReferenceId = 'Prerequisite_DeployExtensionWindows' +param resourceCount = 10 +``` + +
+

+ +### Example 3: _Policy Remediation (Resource Group scope)_ + +This module runs a Policy remediation task at Resource Group scope using minimal parameters. + + +

+ +via Bicep module + +```bicep +module remediation 'br/public:avm/ptn/policy-insights/remediation:' = { + name: 'remediationDeployment' + params: { + // Required parameters + name: 'pirrgmin001' + policyAssignmentId: '' + // Non-required parameters + location: '' + policyDefinitionReferenceId: 'Prerequisite_DeployExtensionWindows' + resourceGroupName: '' + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "pirrgmin001" + }, + "policyAssignmentId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + }, + "policyDefinitionReferenceId": { + "value": "Prerequisite_DeployExtensionWindows" + }, + "resourceGroupName": { + "value": "" + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/policy-insights/remediation:' + +// Required parameters +param name = 'pirrgmin001' +param policyAssignmentId = '' +// Non-required parameters +param location = '' +param policyDefinitionReferenceId = 'Prerequisite_DeployExtensionWindows' +param resourceGroupName = '' +param subscriptionId = '' +``` + +
+

+ +### Example 4: _Policy Remediation (Resource Group scope)_ + +This module runs a Policy remediation task at Resource Group scope using common parameters. + + +

+ +via Bicep module + +```bicep +module remediation 'br/public:avm/ptn/policy-insights/remediation:' = { + name: 'remediationDeployment' + params: { + // Required parameters + name: 'pirrgmax001' + policyAssignmentId: '' + // Non-required parameters + failureThresholdPercentage: '0.5' + filtersLocations: [] + location: '' + parallelDeployments: 1 + policyDefinitionReferenceId: 'Prerequisite_DeployExtensionWindows' + resourceCount: 10 + resourceDiscoveryMode: 'ReEvaluateCompliance' + resourceGroupName: '' + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "pirrgmax001" + }, + "policyAssignmentId": { + "value": "" + }, + // Non-required parameters + "failureThresholdPercentage": { + "value": "0.5" + }, + "filtersLocations": { + "value": [] + }, + "location": { + "value": "" + }, + "parallelDeployments": { + "value": 1 + }, + "policyDefinitionReferenceId": { + "value": "Prerequisite_DeployExtensionWindows" + }, + "resourceCount": { + "value": 10 + }, + "resourceDiscoveryMode": { + "value": "ReEvaluateCompliance" + }, + "resourceGroupName": { + "value": "" + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/policy-insights/remediation:' + +// Required parameters +param name = 'pirrgmax001' +param policyAssignmentId = '' +// Non-required parameters +param failureThresholdPercentage = '0.5' +param filtersLocations = [] +param location = '' +param parallelDeployments = 1 +param policyDefinitionReferenceId = 'Prerequisite_DeployExtensionWindows' +param resourceCount = 10 +param resourceDiscoveryMode = 'ReEvaluateCompliance' +param resourceGroupName = '' +param subscriptionId = '' +``` + +
+

+ +### Example 5: _Policy Remediation (Subscription scope)_ + +This module runs a Policy remediation task at subscription scope using minimal parameters. + + +

+ +via Bicep module + +```bicep +module remediation 'br/public:avm/ptn/policy-insights/remediation:' = { + name: 'remediationDeployment' + params: { + // Required parameters + name: 'pirsubmin001' + policyAssignmentId: '' + // Non-required parameters + location: '' + policyDefinitionReferenceId: 'Prerequisite_DeployExtensionWindows' + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "pirsubmin001" + }, + "policyAssignmentId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + }, + "policyDefinitionReferenceId": { + "value": "Prerequisite_DeployExtensionWindows" + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/policy-insights/remediation:' + +// Required parameters +param name = 'pirsubmin001' +param policyAssignmentId = '' +// Non-required parameters +param location = '' +param policyDefinitionReferenceId = 'Prerequisite_DeployExtensionWindows' +param subscriptionId = '' +``` + +
+

+ +### Example 6: _Policy Remediation (Subscription scope)_ + +This module runs a Policy remediation task at subscription scope using common parameters. + + +

+ +via Bicep module + +```bicep +module remediation 'br/public:avm/ptn/policy-insights/remediation:' = { + name: 'remediationDeployment' + params: { + // Required parameters + name: 'pirsubmax001' + policyAssignmentId: '' + // Non-required parameters + failureThresholdPercentage: '0.5' + filtersLocations: [] + location: '' + parallelDeployments: 1 + policyDefinitionReferenceId: 'Prerequisite_DeployExtensionWindows' + resourceCount: 10 + resourceDiscoveryMode: 'ReEvaluateCompliance' + subscriptionId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "pirsubmax001" + }, + "policyAssignmentId": { + "value": "" + }, + // Non-required parameters + "failureThresholdPercentage": { + "value": "0.5" + }, + "filtersLocations": { + "value": [] + }, + "location": { + "value": "" + }, + "parallelDeployments": { + "value": 1 + }, + "policyDefinitionReferenceId": { + "value": "Prerequisite_DeployExtensionWindows" + }, + "resourceCount": { + "value": 10 + }, + "resourceDiscoveryMode": { + "value": "ReEvaluateCompliance" + }, + "subscriptionId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/policy-insights/remediation:' + +// Required parameters +param name = 'pirsubmax001' +param policyAssignmentId = '' +// Non-required parameters +param failureThresholdPercentage = '0.5' +param filtersLocations = [] +param location = '' +param parallelDeployments = 1 +param policyDefinitionReferenceId = 'Prerequisite_DeployExtensionWindows' +param resourceCount = 10 +param resourceDiscoveryMode = 'ReEvaluateCompliance' +param subscriptionId = '' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Specifies the name of the policy remediation. | +| [`policyAssignmentId`](#parameter-policyassignmentid) | string | The resource ID of the policy assignment that should be remediated. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`failureThresholdPercentage`](#parameter-failurethresholdpercentage) | string | The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail. | +| [`filtersLocations`](#parameter-filterslocations) | array | The filters that will be applied to determine which resources to remediate. | +| [`location`](#parameter-location) | string | Location deployment metadata. | +| [`managementGroupId`](#parameter-managementgroupid) | string | The target scope for the remediation. The name of the management group for the policy assignment. If not provided, will use the current scope for deployment. | +| [`parallelDeployments`](#parameter-paralleldeployments) | int | Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used. | +| [`policyDefinitionReferenceId`](#parameter-policydefinitionreferenceid) | string | The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition. | +| [`resourceCount`](#parameter-resourcecount) | int | Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used. | +| [`resourceDiscoveryMode`](#parameter-resourcediscoverymode) | string | The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified. | +| [`resourceGroupName`](#parameter-resourcegroupname) | string | The target scope for the remediation. The name of the resource group for the policy assignment. | +| [`subscriptionId`](#parameter-subscriptionid) | string | The target scope for the remediation. The subscription ID of the subscription for the policy assignment. | + +### Parameter: `name` + +Specifies the name of the policy remediation. + +- Required: Yes +- Type: string + +### Parameter: `policyAssignmentId` + +The resource ID of the policy assignment that should be remediated. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `failureThresholdPercentage` + +The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail. + +- Required: No +- Type: string +- Default: `'1'` + +### Parameter: `filtersLocations` + +The filters that will be applied to determine which resources to remediate. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `location` + +Location deployment metadata. + +- Required: No +- Type: string +- Default: `[deployment().location]` + +### Parameter: `managementGroupId` + +The target scope for the remediation. The name of the management group for the policy assignment. If not provided, will use the current scope for deployment. + +- Required: No +- Type: string +- Default: `[managementGroup().name]` + +### Parameter: `parallelDeployments` + +Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used. + +- Required: No +- Type: int +- Default: `10` +- MinValue: 1 +- MaxValue: 30 + +### Parameter: `policyDefinitionReferenceId` + +The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition. + +- Required: No +- Type: string +- Default: `''` +- MinValue: 1 +- MaxValue: 30 + +### Parameter: `resourceCount` + +Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used. + +- Required: No +- Type: int +- Default: `500` +- MinValue: 1 +- MaxValue: 50000 + +### Parameter: `resourceDiscoveryMode` + +The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified. + +- Required: No +- Type: string +- Default: `'ExistingNonCompliant'` +- Allowed: + ```Bicep + [ + 'ExistingNonCompliant' + 'ReEvaluateCompliance' + ] + ``` +- MinValue: 1 +- MaxValue: 50000 + +### Parameter: `resourceGroupName` + +The target scope for the remediation. The name of the resource group for the policy assignment. + +- Required: No +- Type: string +- Default: `''` +- MinValue: 1 +- MaxValue: 50000 + +### Parameter: `subscriptionId` + +The target scope for the remediation. The subscription ID of the subscription for the policy assignment. + +- Required: No +- Type: string +- Default: `''` +- MinValue: 1 +- MaxValue: 50000 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the remediation. | +| `resourceId` | string | The resource ID of the remediation. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/ptn/policy-insights/remediation/main.bicep b/avm/1.1.0/ptn/policy-insights/remediation/main.bicep new file mode 100644 index 000000000..0fec97233 --- /dev/null +++ b/avm/1.1.0/ptn/policy-insights/remediation/main.bicep @@ -0,0 +1,152 @@ +metadata name = 'Policy Insights Remediations' +metadata description = 'This module deploys a Policy Insights Remediation.' + +targetScope = 'managementGroup' + +// ================ // +// Parameters // +// ================ // + +@sys.description('Required. Specifies the name of the policy remediation.') +param name string + +@sys.description('Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail.') +param failureThresholdPercentage string = '1' + +@sys.description('Optional. The filters that will be applied to determine which resources to remediate.') +param filtersLocations array = [] + +@sys.description('Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used.') +@minValue(1) +@maxValue(30) +param parallelDeployments int = 10 + +@sys.description('Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used.') +@minValue(1) +@maxValue(50000) +param resourceCount int = 500 + +@sys.description('Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified.') +@allowed([ + 'ExistingNonCompliant' + 'ReEvaluateCompliance' +]) +param resourceDiscoveryMode string = 'ExistingNonCompliant' + +@sys.description('Required. The resource ID of the policy assignment that should be remediated.') +param policyAssignmentId string + +@sys.description('Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition.') +param policyDefinitionReferenceId string = '' + +@sys.description('Optional. The target scope for the remediation. The name of the management group for the policy assignment. If not provided, will use the current scope for deployment.') +param managementGroupId string = managementGroup().name + +@sys.description('Optional. The target scope for the remediation. The subscription ID of the subscription for the policy assignment.') +param subscriptionId string = '' + +@sys.description('Optional. The target scope for the remediation. The name of the resource group for the policy assignment.') +param resourceGroupName string = '' + +@sys.description('Optional. Location deployment metadata.') +param location string = deployment().location + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// ================ // +// Resources // +// ================ // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.ptn.policyinsights-remediation.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + location: location + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +module remediation_mg 'modules/management-group.bicep' = if (empty(subscriptionId) && empty(resourceGroupName)) { + name: '${uniqueString(deployment().name, location)}-Remediation-MG-Module' + scope: managementGroup(managementGroupId) + params: { + name: name + location: location + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceId: policyDefinitionReferenceId + filtersLocations: filtersLocations + resourceCount: resourceCount + parallelDeployments: parallelDeployments + failureThresholdPercentage: failureThresholdPercentage + } +} + +module remediation_sub 'modules/subscription.bicep' = if (!empty(subscriptionId) && empty(resourceGroupName)) { + name: '${uniqueString(deployment().name, location)}-Remediation-Sub-Module' + scope: subscription(subscriptionId) + params: { + name: name + location: location + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceId: policyDefinitionReferenceId + filtersLocations: filtersLocations + resourceCount: resourceCount + resourceDiscoveryMode: resourceDiscoveryMode + parallelDeployments: parallelDeployments + failureThresholdPercentage: failureThresholdPercentage + } +} + +module remediation_rg 'modules/resource-group.bicep' = if (!empty(resourceGroupName) && !empty(subscriptionId)) { + name: '${uniqueString(deployment().name, location)}-Remediation-RG-Module' + scope: resourceGroup(subscriptionId, resourceGroupName) + params: { + name: name + location: location + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceId: policyDefinitionReferenceId + filtersLocations: filtersLocations + resourceCount: resourceCount + resourceDiscoveryMode: resourceDiscoveryMode + parallelDeployments: parallelDeployments + failureThresholdPercentage: failureThresholdPercentage + } +} + +// ================ // +// Outputs // +// ================ // + +@sys.description('The name of the remediation.') +output name string = empty(subscriptionId) && empty(resourceGroupName) + ? remediation_mg.outputs.name + : (!empty(subscriptionId) && empty(resourceGroupName) ? remediation_sub.outputs.name : remediation_rg.outputs.name) + +@sys.description('The resource ID of the remediation.') +output resourceId string = empty(subscriptionId) && empty(resourceGroupName) + ? remediation_mg.outputs.resourceId + : (!empty(subscriptionId) && empty(resourceGroupName) + ? remediation_sub.outputs.resourceId + : remediation_rg.outputs.resourceId) + +@sys.description('The location the resource was deployed into.') +output location string = empty(subscriptionId) && empty(resourceGroupName) + ? remediation_mg.outputs.location + : (!empty(subscriptionId) && empty(resourceGroupName) + ? remediation_sub.outputs.location + : remediation_rg.outputs.location) diff --git a/avm/1.1.0/ptn/policy-insights/remediation/main.json b/avm/1.1.0/ptn/policy-insights/remediation/main.json new file mode 100644 index 000000000..ad5063e06 --- /dev/null +++ b/avm/1.1.0/ptn/policy-insights/remediation/main.json @@ -0,0 +1,674 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "7690893143895476601" + }, + "name": "Policy Insights Remediations", + "description": "This module deploys a Policy Insights Remediation." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specifies the name of the policy remediation." + } + }, + "failureThresholdPercentage": { + "type": "string", + "defaultValue": "1", + "metadata": { + "description": "Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail." + } + }, + "filtersLocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The filters that will be applied to determine which resources to remediate." + } + }, + "parallelDeployments": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "maxValue": 30, + "metadata": { + "description": "Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used." + } + }, + "resourceCount": { + "type": "int", + "defaultValue": 500, + "minValue": 1, + "maxValue": 50000, + "metadata": { + "description": "Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used." + } + }, + "resourceDiscoveryMode": { + "type": "string", + "defaultValue": "ExistingNonCompliant", + "allowedValues": [ + "ExistingNonCompliant", + "ReEvaluateCompliance" + ], + "metadata": { + "description": "Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified." + } + }, + "policyAssignmentId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the policy assignment that should be remediated." + } + }, + "policyDefinitionReferenceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition." + } + }, + "managementGroupId": { + "type": "string", + "defaultValue": "[managementGroup().name]", + "metadata": { + "description": "Optional. The target scope for the remediation. The name of the management group for the policy assignment. If not provided, will use the current scope for deployment." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The target scope for the remediation. The subscription ID of the subscription for the policy assignment." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The target scope for the remediation. The name of the resource group for the policy assignment." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location deployment metadata." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.ptn.policyinsights-remediation.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "location": "[parameters('location')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "condition": "[and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Remediation-MG-Module', uniqueString(deployment().name, parameters('location')))]", + "scope": "[format('Microsoft.Management/managementGroups/{0}', parameters('managementGroupId'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "policyAssignmentId": { + "value": "[parameters('policyAssignmentId')]" + }, + "policyDefinitionReferenceId": { + "value": "[parameters('policyDefinitionReferenceId')]" + }, + "filtersLocations": { + "value": "[parameters('filtersLocations')]" + }, + "resourceCount": { + "value": "[parameters('resourceCount')]" + }, + "parallelDeployments": { + "value": "[parameters('parallelDeployments')]" + }, + "failureThresholdPercentage": { + "value": "[parameters('failureThresholdPercentage')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3942331630377598660" + }, + "name": "Policy Insights Remediations (Management Group scope)", + "description": "This module starts a Policy Remediation task at a Management Group scope." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specifies the name of the policy remediation." + } + }, + "failureThresholdPercentage": { + "type": "string", + "defaultValue": "1", + "metadata": { + "description": "Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail." + } + }, + "filtersLocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The filters that will be applied to determine which resources to remediate." + } + }, + "parallelDeployments": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "maxValue": 30, + "metadata": { + "description": "Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used." + } + }, + "resourceCount": { + "type": "int", + "defaultValue": 500, + "minValue": 1, + "maxValue": 50000, + "metadata": { + "description": "Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used." + } + }, + "policyAssignmentId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the policy assignment that should be remediated." + } + }, + "policyDefinitionReferenceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location deployment metadata." + } + } + }, + "resources": [ + { + "type": "Microsoft.PolicyInsights/remediations", + "apiVersion": "2021-10-01", + "name": "[parameters('name')]", + "properties": { + "failureThreshold": { + "percentage": "[json(parameters('failureThresholdPercentage'))]" + }, + "filters": { + "locations": "[parameters('filtersLocations')]" + }, + "parallelDeployments": "[parameters('parallelDeployments')]", + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceId": "[parameters('policyDefinitionReferenceId')]", + "resourceCount": "[parameters('resourceCount')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the remediation." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the remediation." + }, + "value": "[extensionResourceId(managementGroup().id, 'Microsoft.PolicyInsights/remediations', parameters('name'))]" + }, + "managementGroupName": { + "type": "string", + "metadata": { + "description": "The managmeent group of the deployed remediation." + }, + "value": "[managementGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[parameters('location')]" + } + } + } + } + }, + { + "condition": "[and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Remediation-Sub-Module', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[parameters('subscriptionId')]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "policyAssignmentId": { + "value": "[parameters('policyAssignmentId')]" + }, + "policyDefinitionReferenceId": { + "value": "[parameters('policyDefinitionReferenceId')]" + }, + "filtersLocations": { + "value": "[parameters('filtersLocations')]" + }, + "resourceCount": { + "value": "[parameters('resourceCount')]" + }, + "resourceDiscoveryMode": { + "value": "[parameters('resourceDiscoveryMode')]" + }, + "parallelDeployments": { + "value": "[parameters('parallelDeployments')]" + }, + "failureThresholdPercentage": { + "value": "[parameters('failureThresholdPercentage')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12178537364329357242" + }, + "name": "Policy Insights Remediations (Subscription scope)", + "description": "This module deploys a Policy Insights Remediation on a Subscription scope." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specifies the name of the policy remediation." + } + }, + "failureThresholdPercentage": { + "type": "string", + "defaultValue": "1", + "metadata": { + "description": "Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail." + } + }, + "filtersLocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The filters that will be applied to determine which resources to remediate." + } + }, + "parallelDeployments": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "maxValue": 30, + "metadata": { + "description": "Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used." + } + }, + "resourceCount": { + "type": "int", + "defaultValue": 500, + "minValue": 1, + "maxValue": 50000, + "metadata": { + "description": "Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used." + } + }, + "resourceDiscoveryMode": { + "type": "string", + "defaultValue": "ExistingNonCompliant", + "allowedValues": [ + "ExistingNonCompliant", + "ReEvaluateCompliance" + ], + "metadata": { + "description": "Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified." + } + }, + "policyAssignmentId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the policy assignment that should be remediated." + } + }, + "policyDefinitionReferenceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location deployment metadata." + } + } + }, + "resources": [ + { + "type": "Microsoft.PolicyInsights/remediations", + "apiVersion": "2021-10-01", + "name": "[parameters('name')]", + "properties": { + "failureThreshold": { + "percentage": "[json(parameters('failureThresholdPercentage'))]" + }, + "filters": { + "locations": "[parameters('filtersLocations')]" + }, + "parallelDeployments": "[parameters('parallelDeployments')]", + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceId": "[parameters('policyDefinitionReferenceId')]", + "resourceCount": "[parameters('resourceCount')]", + "resourceDiscoveryMode": "[parameters('resourceDiscoveryMode')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the remediation." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the remediation." + }, + "value": "[subscriptionResourceId('Microsoft.PolicyInsights/remediations', parameters('name'))]" + }, + "subscriptionName": { + "type": "string", + "metadata": { + "description": "The subscription name of the deployed remediation." + }, + "value": "[subscription().displayName]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[parameters('location')]" + } + } + } + } + }, + { + "condition": "[and(not(empty(parameters('resourceGroupName'))), not(empty(parameters('subscriptionId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Remediation-RG-Module', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "policyAssignmentId": { + "value": "[parameters('policyAssignmentId')]" + }, + "policyDefinitionReferenceId": { + "value": "[parameters('policyDefinitionReferenceId')]" + }, + "filtersLocations": { + "value": "[parameters('filtersLocations')]" + }, + "resourceCount": { + "value": "[parameters('resourceCount')]" + }, + "resourceDiscoveryMode": { + "value": "[parameters('resourceDiscoveryMode')]" + }, + "parallelDeployments": { + "value": "[parameters('parallelDeployments')]" + }, + "failureThresholdPercentage": { + "value": "[parameters('failureThresholdPercentage')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "11631247936706483329" + }, + "name": "Policy Insights Remediations (Resource Group scope)", + "description": "This module deploys a Policy Insights Remediation on a Resource Group scope." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specifies the name of the policy remediation." + } + }, + "failureThresholdPercentage": { + "type": "string", + "defaultValue": "1", + "metadata": { + "description": "Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail." + } + }, + "filtersLocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The filters that will be applied to determine which resources to remediate." + } + }, + "parallelDeployments": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "maxValue": 30, + "metadata": { + "description": "Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used." + } + }, + "resourceCount": { + "type": "int", + "defaultValue": 500, + "minValue": 1, + "maxValue": 50000, + "metadata": { + "description": "Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used." + } + }, + "resourceDiscoveryMode": { + "type": "string", + "defaultValue": "ExistingNonCompliant", + "allowedValues": [ + "ExistingNonCompliant", + "ReEvaluateCompliance" + ], + "metadata": { + "description": "Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified." + } + }, + "policyAssignmentId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the policy assignment that should be remediated." + } + }, + "policyDefinitionReferenceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location deployment metadata." + } + } + }, + "resources": [ + { + "type": "Microsoft.PolicyInsights/remediations", + "apiVersion": "2021-10-01", + "name": "[parameters('name')]", + "properties": { + "failureThreshold": { + "percentage": "[json(parameters('failureThresholdPercentage'))]" + }, + "filters": { + "locations": "[parameters('filtersLocations')]" + }, + "parallelDeployments": "[parameters('parallelDeployments')]", + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceId": "[parameters('policyDefinitionReferenceId')]", + "resourceCount": "[parameters('resourceCount')]", + "resourceDiscoveryMode": "[parameters('resourceDiscoveryMode')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the remediation." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the remediation." + }, + "value": "[resourceId('Microsoft.PolicyInsights/remediations', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed remediation." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[parameters('location')]" + } + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the remediation." + }, + "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-Remediation-MG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.name.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference(subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('{0}-Remediation-Sub-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.name.value, reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('{0}-Remediation-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.name.value))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the remediation." + }, + "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-Remediation-MG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.resourceId.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference(subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('{0}-Remediation-Sub-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.resourceId.value, reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('{0}-Remediation-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.resourceId.value))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[if(and(empty(parameters('subscriptionId')), empty(parameters('resourceGroupName'))), reference(extensionResourceId(tenantResourceId('Microsoft.Management/managementGroups', parameters('managementGroupId')), 'Microsoft.Resources/deployments', format('{0}-Remediation-MG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.location.value, if(and(not(empty(parameters('subscriptionId'))), empty(parameters('resourceGroupName'))), reference(subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('{0}-Remediation-Sub-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.location.value, reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('{0}-Remediation-RG-Module', uniqueString(deployment().name, parameters('location')))), '2022-09-01').outputs.location.value))]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/ptn/policy-insights/remediation/modules/management-group.bicep b/avm/1.1.0/ptn/policy-insights/remediation/modules/management-group.bicep new file mode 100644 index 000000000..a6ed04fc8 --- /dev/null +++ b/avm/1.1.0/ptn/policy-insights/remediation/modules/management-group.bicep @@ -0,0 +1,72 @@ +metadata name = 'Policy Insights Remediations (Management Group scope)' +metadata description = 'This module starts a Policy Remediation task at a Management Group scope.' + +targetScope = 'managementGroup' + +// ================ // +// Parameters // +// ================ // + +@sys.description('Required. Specifies the name of the policy remediation.') +param name string + +@sys.description('Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail.') +param failureThresholdPercentage string = '1' + +@sys.description('Optional. The filters that will be applied to determine which resources to remediate.') +param filtersLocations array = [] + +@sys.description('Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used.') +@minValue(1) +@maxValue(30) +param parallelDeployments int = 10 + +@sys.description('Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used.') +@minValue(1) +@maxValue(50000) +param resourceCount int = 500 + +@sys.description('Required. The resource ID of the policy assignment that should be remediated.') +param policyAssignmentId string + +@sys.description('Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition.') +param policyDefinitionReferenceId string = '' + +@sys.description('Optional. Location deployment metadata.') +param location string = deployment().location + +// ================ // +// Resources // +// ================ // + +resource remediation 'Microsoft.PolicyInsights/remediations@2021-10-01' = { + name: name + properties: { + failureThreshold: { + percentage: json(failureThresholdPercentage) // The json() function is used to allow specifying a decimal value. + } + filters: { + locations: filtersLocations + } + parallelDeployments: parallelDeployments + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceId: policyDefinitionReferenceId + resourceCount: resourceCount + } +} + +// ================ // +// Outputs // +// ================ // + +@sys.description('The name of the remediation.') +output name string = remediation.name + +@sys.description('The resource ID of the remediation.') +output resourceId string = remediation.id + +@sys.description('The managmeent group of the deployed remediation.') +output managementGroupName string = managementGroup().name + +@sys.description('The location the resource was deployed into.') +output location string = location diff --git a/avm/1.1.0/ptn/policy-insights/remediation/modules/resource-group.bicep b/avm/1.1.0/ptn/policy-insights/remediation/modules/resource-group.bicep new file mode 100644 index 000000000..9b807aa27 --- /dev/null +++ b/avm/1.1.0/ptn/policy-insights/remediation/modules/resource-group.bicep @@ -0,0 +1,80 @@ +metadata name = 'Policy Insights Remediations (Resource Group scope)' +metadata description = 'This module deploys a Policy Insights Remediation on a Resource Group scope.' + +targetScope = 'resourceGroup' + +// ================ // +// Parameters // +// ================ // + +@sys.description('Required. Specifies the name of the policy remediation.') +param name string + +@sys.description('Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail.') +param failureThresholdPercentage string = '1' + +@sys.description('Optional. The filters that will be applied to determine which resources to remediate.') +param filtersLocations array = [] + +@sys.description('Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used.') +@minValue(1) +@maxValue(30) +param parallelDeployments int = 10 + +@sys.description('Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used.') +@minValue(1) +@maxValue(50000) +param resourceCount int = 500 + +@sys.description('Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified.') +@allowed([ + 'ExistingNonCompliant' + 'ReEvaluateCompliance' +]) +param resourceDiscoveryMode string = 'ExistingNonCompliant' + +@sys.description('Required. The resource ID of the policy assignment that should be remediated.') +param policyAssignmentId string + +@sys.description('Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition.') +param policyDefinitionReferenceId string = '' + +@sys.description('Optional. Location deployment metadata.') +param location string = resourceGroup().location + +// ================ // +// Resources // +// ================ // + +resource remediation 'Microsoft.PolicyInsights/remediations@2021-10-01' = { + name: name + properties: { + failureThreshold: { + percentage: json(failureThresholdPercentage) // The json() function is used to allow specifying a decimal value. + } + filters: { + locations: filtersLocations + } + parallelDeployments: parallelDeployments + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceId: policyDefinitionReferenceId + resourceCount: resourceCount + resourceDiscoveryMode: resourceDiscoveryMode + } +} + +// ================ // +// Outputs // +// ================ // + +@sys.description('The name of the remediation.') +output name string = remediation.name + +@sys.description('The resource ID of the remediation.') +output resourceId string = remediation.id + +@sys.description('The resource group of the deployed remediation.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The location the resource was deployed into.') +output location string = location diff --git a/avm/1.1.0/ptn/policy-insights/remediation/modules/subscription.bicep b/avm/1.1.0/ptn/policy-insights/remediation/modules/subscription.bicep new file mode 100644 index 000000000..b5a771fa3 --- /dev/null +++ b/avm/1.1.0/ptn/policy-insights/remediation/modules/subscription.bicep @@ -0,0 +1,80 @@ +metadata name = 'Policy Insights Remediations (Subscription scope)' +metadata description = 'This module deploys a Policy Insights Remediation on a Subscription scope.' + +targetScope = 'subscription' + +// ================ // +// Parameters // +// ================ // + +@sys.description('Required. Specifies the name of the policy remediation.') +param name string + +@sys.description('Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail.') +param failureThresholdPercentage string = '1' + +@sys.description('Optional. The filters that will be applied to determine which resources to remediate.') +param filtersLocations array = [] + +@sys.description('Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used.') +@minValue(1) +@maxValue(30) +param parallelDeployments int = 10 + +@sys.description('Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used.') +@minValue(1) +@maxValue(50000) +param resourceCount int = 500 + +@sys.description('Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified.') +@allowed([ + 'ExistingNonCompliant' + 'ReEvaluateCompliance' +]) +param resourceDiscoveryMode string = 'ExistingNonCompliant' + +@sys.description('Required. The resource ID of the policy assignment that should be remediated.') +param policyAssignmentId string + +@sys.description('Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition.') +param policyDefinitionReferenceId string = '' + +@sys.description('Optional. Location deployment metadata.') +param location string = deployment().location + +// ================ // +// Resources // +// ================ // + +resource remediation 'Microsoft.PolicyInsights/remediations@2021-10-01' = { + name: name + properties: { + failureThreshold: { + percentage: json(failureThresholdPercentage) // The json() function is used to allow specifying a decimal value. + } + filters: { + locations: filtersLocations + } + parallelDeployments: parallelDeployments + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceId: policyDefinitionReferenceId + resourceCount: resourceCount + resourceDiscoveryMode: resourceDiscoveryMode + } +} + +// ================ // +// Outputs // +// ================ // + +@sys.description('The name of the remediation.') +output name string = remediation.name + +@sys.description('The resource ID of the remediation.') +output resourceId string = remediation.id + +@sys.description('The subscription name of the deployed remediation.') +output subscriptionName string = subscription().displayName + +@sys.description('The location the resource was deployed into.') +output location string = location diff --git a/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/mg.defaults/main.test.bicep b/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/mg.defaults/main.test.bicep new file mode 100644 index 000000000..eae75d89e --- /dev/null +++ b/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/mg.defaults/main.test.bicep @@ -0,0 +1,49 @@ +targetScope = 'managementGroup' + +metadata name = 'Policy Remediation (Management Group scope)' +metadata description = 'This module runs a Policy remediation task at Management Group scope using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@sys.description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@sys.description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'pirmgmin' + +@sys.description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource policySetAssignments 'Microsoft.Authorization/policyAssignments@2022-06-01' = { + name: 'dep-${namePrefix}-psa-${serviceShort}' + identity: { + type: 'SystemAssigned' + } + location: resourceLocation + properties: { + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/12794019-7a00-42cf-95c2-882eed337cc8' + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + policyAssignmentId: policySetAssignments.id + policyDefinitionReferenceId: 'Prerequisite_DeployExtensionWindows' + } +} diff --git a/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/mg.max/main.test.bicep b/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/mg.max/main.test.bicep new file mode 100644 index 000000000..bd89bdf9c --- /dev/null +++ b/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/mg.max/main.test.bicep @@ -0,0 +1,53 @@ +targetScope = 'managementGroup' + +metadata name = 'Policy Remediation (Management Group scope)' +metadata description = 'This module runs a Policy remediation task at Management Group scope using common parameters.' + +// ========== // +// Parameters // +// ========== // + +@sys.description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@sys.description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'pirmgmax' + +@sys.description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource policySetAssignments 'Microsoft.Authorization/policyAssignments@2022-06-01' = { + name: 'dep-${namePrefix}-psa-${serviceShort}' + identity: { + type: 'SystemAssigned' + } + location: resourceLocation + properties: { + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/12794019-7a00-42cf-95c2-882eed337cc8' + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + policyAssignmentId: policySetAssignments.id + policyDefinitionReferenceId: 'Prerequisite_DeployExtensionWindows' + filtersLocations: [] + resourceCount: 10 + parallelDeployments: 1 + failureThresholdPercentage: '0.5' + } +} diff --git a/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/rg.defaults/main.test.bicep b/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/rg.defaults/main.test.bicep new file mode 100644 index 000000000..d28faf5b6 --- /dev/null +++ b/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/rg.defaults/main.test.bicep @@ -0,0 +1,63 @@ +targetScope = 'managementGroup' + +metadata name = 'Policy Remediation (Resource Group scope)' +metadata description = 'This module runs a Policy remediation task at Resource Group scope using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@sys.description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@sys.description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'pirrgmin' + +@sys.description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. Subscription ID of the subscription to deploy the resource group.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +module resourceGroupDeploy 'br/public:avm/res/resources/resource-group:0.2.3' = { + scope: subscription(subscriptionId) + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: 'dep-${namePrefix}-policy-remediation-${serviceShort}-rg' + location: resourceLocation + } +} + +module policySetAssignments 'br/public:avm/ptn/authorization/policy-assignment:0.1.0' = { + name: '${uniqueString(deployment().name, resourceLocation)}-policySetAssignment-rg' + params: { + name: 'dep-${namePrefix}-psa-${serviceShort}' + subscriptionId: subscriptionId + resourceGroupName: resourceGroupDeploy.outputs.name + location: resourceLocation + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/12794019-7a00-42cf-95c2-882eed337cc8' + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + subscriptionId: subscriptionId + resourceGroupName: resourceGroupDeploy.outputs.name + policyAssignmentId: policySetAssignments.outputs.resourceId + policyDefinitionReferenceId: 'Prerequisite_DeployExtensionWindows' + } +} diff --git a/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/rg.max/main.test.bicep b/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/rg.max/main.test.bicep new file mode 100644 index 000000000..736296908 --- /dev/null +++ b/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/rg.max/main.test.bicep @@ -0,0 +1,68 @@ +targetScope = 'managementGroup' + +metadata name = 'Policy Remediation (Resource Group scope)' +metadata description = 'This module runs a Policy remediation task at Resource Group scope using common parameters.' + +// ========== // +// Parameters // +// ========== // + +@sys.description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@sys.description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'pirrgmax' + +@sys.description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. Subscription ID of the subscription to deploy the resource group.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +module resourceGroupDeploy 'br/public:avm/res/resources/resource-group:0.2.3' = { + scope: subscription(subscriptionId) + name: '${uniqueString(deployment().name, resourceLocation)}-resourceGroup' + params: { + name: 'dep-${namePrefix}-policy-remediation-${serviceShort}-rg' + location: resourceLocation + } +} + +module policySetAssignments 'br/public:avm/ptn/authorization/policy-assignment:0.1.0' = { + name: '${uniqueString(deployment().name, resourceLocation)}-policySetAssignment-rg' + params: { + name: 'dep-${namePrefix}-psa-${serviceShort}' + subscriptionId: subscriptionId + resourceGroupName: resourceGroupDeploy.outputs.name + location: resourceLocation + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/12794019-7a00-42cf-95c2-882eed337cc8' + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + subscriptionId: subscriptionId + resourceGroupName: resourceGroupDeploy.outputs.name + policyAssignmentId: policySetAssignments.outputs.resourceId + policyDefinitionReferenceId: 'Prerequisite_DeployExtensionWindows' + filtersLocations: [] + resourceCount: 10 + resourceDiscoveryMode: 'ReEvaluateCompliance' + parallelDeployments: 1 + failureThresholdPercentage: '0.5' + } +} diff --git a/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/sub.defaults/main.test.bicep b/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/sub.defaults/main.test.bicep new file mode 100644 index 000000000..f82fc9f28 --- /dev/null +++ b/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/sub.defaults/main.test.bicep @@ -0,0 +1,52 @@ +targetScope = 'managementGroup' + +metadata name = 'Policy Remediation (Subscription scope)' +metadata description = 'This module runs a Policy remediation task at subscription scope using minimal parameters.' + +// ========== // +// Parameters // +// ========== // + +@sys.description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@sys.description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'pirsubmin' + +@sys.description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. Subscription ID of the target subscription.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +module policySetAssignments 'br/public:avm/ptn/authorization/policy-assignment:0.1.0' = { + name: '${uniqueString(deployment().name, resourceLocation)}-policySetAssignment-sub' + params: { + name: 'dep-${namePrefix}-psa-${serviceShort}' + subscriptionId: subscriptionId + location: resourceLocation + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/12794019-7a00-42cf-95c2-882eed337cc8' + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + subscriptionId: subscriptionId + policyAssignmentId: policySetAssignments.outputs.resourceId + policyDefinitionReferenceId: 'Prerequisite_DeployExtensionWindows' + } +} diff --git a/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/sub.max/main.test.bicep b/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/sub.max/main.test.bicep new file mode 100644 index 000000000..77979a6c4 --- /dev/null +++ b/avm/1.1.0/ptn/policy-insights/remediation/tests/e2e/sub.max/main.test.bicep @@ -0,0 +1,57 @@ +targetScope = 'managementGroup' + +metadata name = 'Policy Remediation (Subscription scope)' +metadata description = 'This module runs a Policy remediation task at subscription scope using common parameters.' + +// ========== // +// Parameters // +// ========== // + +@sys.description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@sys.description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'pirsubmax' + +@sys.description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. Subscription ID of the target subscription.') +param subscriptionId string = '#_subscriptionId_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +module policySetAssignments 'br/public:avm/ptn/authorization/policy-assignment:0.1.0' = { + name: '${uniqueString(deployment().name, resourceLocation)}-policySetAssignment-sub' + params: { + name: 'dep-${namePrefix}-psa-${serviceShort}' + subscriptionId: subscriptionId + location: resourceLocation + policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/12794019-7a00-42cf-95c2-882eed337cc8' + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + subscriptionId: subscriptionId + policyAssignmentId: policySetAssignments.outputs.resourceId + policyDefinitionReferenceId: 'Prerequisite_DeployExtensionWindows' + filtersLocations: [] + resourceCount: 10 + resourceDiscoveryMode: 'ReEvaluateCompliance' + parallelDeployments: 1 + failureThresholdPercentage: '0.5' + } +} diff --git a/avm/1.1.0/ptn/policy-insights/remediation/version.json b/avm/1.1.0/ptn/policy-insights/remediation/version.json new file mode 100644 index 000000000..4a115b2fd --- /dev/null +++ b/avm/1.1.0/ptn/policy-insights/remediation/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] + } diff --git a/avm/1.1.0/res/automation/automation-account/README.md b/avm/1.1.0/res/automation/automation-account/README.md new file mode 100644 index 000000000..47dbff731 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/README.md @@ -0,0 +1,2721 @@ +# Automation Accounts `[Microsoft.Automation/automationAccounts]` + +This module deploys an Azure Automation Account. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Automation/automationAccounts` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts) | +| `Microsoft.Automation/automationAccounts/credentials` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2023-11-01/automationAccounts/credentials) | +| `Microsoft.Automation/automationAccounts/jobSchedules` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/jobSchedules) | +| `Microsoft.Automation/automationAccounts/modules` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/modules) | +| `Microsoft.Automation/automationAccounts/runbooks` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2023-11-01/automationAccounts/runbooks) | +| `Microsoft.Automation/automationAccounts/schedules` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/schedules) | +| `Microsoft.Automation/automationAccounts/softwareUpdateConfigurations` | [2019-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2019-06-01/automationAccounts/softwareUpdateConfigurations) | +| `Microsoft.Automation/automationAccounts/variables` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/variables) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | +| `Microsoft.OperationalInsights/workspaces/linkedServices` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/linkedServices) | +| `Microsoft.OperationsManagement/solutions` | [2015-11-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationsManagement/2015-11-01-preview/solutions) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/automation/automation-account:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using encryption with Customer-Managed-Key](#example-2-using-encryption-with-customer-managed-key) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [WAF-aligned](#example-4-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module automationAccount 'br/public:avm/res/automation/automation-account:' = { + name: 'automationAccountDeployment' + params: { + // Required parameters + name: 'aamin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "aamin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/automation/automation-account:' + +// Required parameters +param name = 'aamin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using encryption with Customer-Managed-Key_ + +This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. + + +

+ +via Bicep module + +```bicep +module automationAccount 'br/public:avm/res/automation/automation-account:' = { + name: 'automationAccountDeployment' + params: { + // Required parameters + name: 'aaencr001' + // Non-required parameters + customerManagedKey: { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' + } + location: '' + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "aaencr001" + }, + // Non-required parameters + "customerManagedKey": { + "value": { + "keyName": "", + "keyVaultResourceId": "", + "userAssignedIdentityResourceId": "" + } + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/automation/automation-account:' + +// Required parameters +param name = 'aaencr001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +``` + +
+

+ +### Example 3: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module automationAccount 'br/public:avm/res/automation/automation-account:' = { + name: 'automationAccountDeployment' + params: { + // Required parameters + name: 'aamax001' + // Non-required parameters + credentials: [ + { + description: 'Description of Credential01' + name: 'Credential01' + password: '' + userName: 'userName01' + } + { + name: 'Credential02' + password: '' + userName: 'username02' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + disableLocalAuth: true + gallerySolutions: [ + { + name: '' + plan: { + product: 'OMSGallery/Updates' + publisher: 'Microsoft' + } + } + ] + jobSchedules: [ + { + runbookName: 'TestRunbook' + scheduleName: 'TestSchedule' + } + ] + linkedWorkspaceResourceId: '' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] + } + modules: [ + { + name: 'PSWindowsUpdate' + uri: 'https://www.powershellgallery.com/api/v2/package' + version: 'latest' + } + ] + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Webhook' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Webhook' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'DSCAndHybridWorker' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + roleAssignments: [ + { + name: 'de334944-f952-4273-8ab3-bd523380034c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + runbooks: [ + { + description: 'Test runbook' + name: 'TestRunbook' + type: 'PowerShell' + uri: 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.automation/101-automation/scripts/AzureAutomationTutorial.ps1' + version: '1.0.0.0' + } + ] + schedules: [ + { + advancedSchedule: {} + expiryTime: '9999-12-31T13:00' + frequency: 'Hour' + interval: 12 + name: 'TestSchedule' + startTime: '' + timeZone: 'Europe/Berlin' + } + ] + softwareUpdateConfigurations: [ + { + excludeUpdates: [ + '123456' + ] + frequency: 'Month' + includeUpdates: [ + '654321' + ] + interval: 1 + maintenanceWindow: 'PT4H' + monthlyOccurrences: [ + { + day: 'Friday' + occurrence: 3 + } + ] + name: 'Windows_ZeroDay' + operatingSystem: 'Windows' + rebootSetting: 'IfRequired' + scopeByTags: { + Update: [ + 'Automatic-Wave1' + ] + } + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Definition' + 'FeaturePack' + 'Security' + 'ServicePack' + 'Tools' + 'UpdateRollup' + 'Updates' + ] + } + { + excludeUpdates: [ + 'icacls' + ] + frequency: 'OneTime' + includeUpdates: [ + 'kernel' + ] + maintenanceWindow: 'PT4H' + name: 'Linux_ZeroDay' + operatingSystem: 'Linux' + rebootSetting: 'IfRequired' + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Other' + 'Security' + ] + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + variables: [ + { + description: 'TestStringDescription' + name: 'TestString' + value: '\'TestString\'' + } + { + description: 'TestIntegerDescription' + name: 'TestInteger' + value: '500' + } + { + description: 'TestBooleanDescription' + name: 'TestBoolean' + value: 'false' + } + { + description: 'TestDateTimeDescription' + isEncrypted: false + name: 'TestDateTime' + value: '\'\\/Date(1637934042656)\\/\'' + } + { + description: 'TestEncryptedDescription' + name: 'TestEncryptedVariable' + value: '\'TestEncryptedValue\'' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "aamax001" + }, + // Non-required parameters + "credentials": { + "value": [ + { + "description": "Description of Credential01", + "name": "Credential01", + "password": "", + "userName": "userName01" + }, + { + "name": "Credential02", + "password": "", + "userName": "username02" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "disableLocalAuth": { + "value": true + }, + "gallerySolutions": { + "value": [ + { + "name": "", + "plan": { + "product": "OMSGallery/Updates", + "publisher": "Microsoft" + } + } + ] + }, + "jobSchedules": { + "value": [ + { + "runbookName": "TestRunbook", + "scheduleName": "TestSchedule" + } + ] + }, + "linkedWorkspaceResourceId": { + "value": "" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "" + ] + } + }, + "modules": { + "value": [ + { + "name": "PSWindowsUpdate", + "uri": "https://www.powershellgallery.com/api/v2/package", + "version": "latest" + } + ] + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "Webhook", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "Webhook", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "DSCAndHybridWorker", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "de334944-f952-4273-8ab3-bd523380034c", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "runbooks": { + "value": [ + { + "description": "Test runbook", + "name": "TestRunbook", + "type": "PowerShell", + "uri": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.automation/101-automation/scripts/AzureAutomationTutorial.ps1", + "version": "1.0.0.0" + } + ] + }, + "schedules": { + "value": [ + { + "advancedSchedule": {}, + "expiryTime": "9999-12-31T13:00", + "frequency": "Hour", + "interval": 12, + "name": "TestSchedule", + "startTime": "", + "timeZone": "Europe/Berlin" + } + ] + }, + "softwareUpdateConfigurations": { + "value": [ + { + "excludeUpdates": [ + "123456" + ], + "frequency": "Month", + "includeUpdates": [ + "654321" + ], + "interval": 1, + "maintenanceWindow": "PT4H", + "monthlyOccurrences": [ + { + "day": "Friday", + "occurrence": 3 + } + ], + "name": "Windows_ZeroDay", + "operatingSystem": "Windows", + "rebootSetting": "IfRequired", + "scopeByTags": { + "Update": [ + "Automatic-Wave1" + ] + }, + "startTime": "22:00", + "updateClassifications": [ + "Critical", + "Definition", + "FeaturePack", + "Security", + "ServicePack", + "Tools", + "UpdateRollup", + "Updates" + ] + }, + { + "excludeUpdates": [ + "icacls" + ], + "frequency": "OneTime", + "includeUpdates": [ + "kernel" + ], + "maintenanceWindow": "PT4H", + "name": "Linux_ZeroDay", + "operatingSystem": "Linux", + "rebootSetting": "IfRequired", + "startTime": "22:00", + "updateClassifications": [ + "Critical", + "Other", + "Security" + ] + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "variables": { + "value": [ + { + "description": "TestStringDescription", + "name": "TestString", + "value": "\"TestString\"" + }, + { + "description": "TestIntegerDescription", + "name": "TestInteger", + "value": "500" + }, + { + "description": "TestBooleanDescription", + "name": "TestBoolean", + "value": "false" + }, + { + "description": "TestDateTimeDescription", + "isEncrypted": false, + "name": "TestDateTime", + "value": "\"\\/Date(1637934042656)\\/\"" + }, + { + "description": "TestEncryptedDescription", + "name": "TestEncryptedVariable", + "value": "\"TestEncryptedValue\"" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/automation/automation-account:' + +// Required parameters +param name = 'aamax001' +// Non-required parameters +param credentials = [ + { + description: 'Description of Credential01' + name: 'Credential01' + password: '' + userName: 'userName01' + } + { + name: 'Credential02' + password: '' + userName: 'username02' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = true +param gallerySolutions = [ + { + name: '' + plan: { + product: 'OMSGallery/Updates' + publisher: 'Microsoft' + } + } +] +param jobSchedules = [ + { + runbookName: 'TestRunbook' + scheduleName: 'TestSchedule' + } +] +param linkedWorkspaceResourceId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param modules = [ + { + name: 'PSWindowsUpdate' + uri: 'https://www.powershellgallery.com/api/v2/package' + version: 'latest' + } +] +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Webhook' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Webhook' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'DSCAndHybridWorker' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param roleAssignments = [ + { + name: 'de334944-f952-4273-8ab3-bd523380034c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param runbooks = [ + { + description: 'Test runbook' + name: 'TestRunbook' + type: 'PowerShell' + uri: 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.automation/101-automation/scripts/AzureAutomationTutorial.ps1' + version: '1.0.0.0' + } +] +param schedules = [ + { + advancedSchedule: {} + expiryTime: '9999-12-31T13:00' + frequency: 'Hour' + interval: 12 + name: 'TestSchedule' + startTime: '' + timeZone: 'Europe/Berlin' + } +] +param softwareUpdateConfigurations = [ + { + excludeUpdates: [ + '123456' + ] + frequency: 'Month' + includeUpdates: [ + '654321' + ] + interval: 1 + maintenanceWindow: 'PT4H' + monthlyOccurrences: [ + { + day: 'Friday' + occurrence: 3 + } + ] + name: 'Windows_ZeroDay' + operatingSystem: 'Windows' + rebootSetting: 'IfRequired' + scopeByTags: { + Update: [ + 'Automatic-Wave1' + ] + } + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Definition' + 'FeaturePack' + 'Security' + 'ServicePack' + 'Tools' + 'UpdateRollup' + 'Updates' + ] + } + { + excludeUpdates: [ + 'icacls' + ] + frequency: 'OneTime' + includeUpdates: [ + 'kernel' + ] + maintenanceWindow: 'PT4H' + name: 'Linux_ZeroDay' + operatingSystem: 'Linux' + rebootSetting: 'IfRequired' + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Other' + 'Security' + ] + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param variables = [ + { + description: 'TestStringDescription' + name: 'TestString' + value: '\'TestString\'' + } + { + description: 'TestIntegerDescription' + name: 'TestInteger' + value: '500' + } + { + description: 'TestBooleanDescription' + name: 'TestBoolean' + value: 'false' + } + { + description: 'TestDateTimeDescription' + isEncrypted: false + name: 'TestDateTime' + value: '\'\\/Date(1637934042656)\\/\'' + } + { + description: 'TestEncryptedDescription' + name: 'TestEncryptedVariable' + value: '\'TestEncryptedValue\'' + } +] +``` + +
+

+ +### Example 4: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module automationAccount 'br/public:avm/res/automation/automation-account:' = { + name: 'automationAccountDeployment' + params: { + // Required parameters + name: 'aawaf001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + disableLocalAuth: true + gallerySolutions: [ + { + name: '' + plan: { + product: 'OMSGallery/Updates' + } + } + ] + jobSchedules: [ + { + runbookName: 'TestRunbook' + scheduleName: 'TestSchedule' + } + ] + linkedWorkspaceResourceId: '' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] + } + modules: [ + { + name: 'PSWindowsUpdate' + uri: 'https://www.powershellgallery.com/api/v2/package' + version: 'latest' + } + ] + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Webhook' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'DSCAndHybridWorker' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + runbooks: [ + { + description: 'Test runbook' + name: 'TestRunbook' + type: 'PowerShell' + uri: 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.automation/101-automation/scripts/AzureAutomationTutorial.ps1' + version: '1.0.0.0' + } + ] + schedules: [ + { + advancedSchedule: {} + expiryTime: '9999-12-31T13:00' + frequency: 'Hour' + interval: 12 + name: 'TestSchedule' + startTime: '' + timeZone: 'Europe/Berlin' + } + ] + softwareUpdateConfigurations: [ + { + excludeUpdates: [ + '123456' + ] + frequency: 'Month' + includeUpdates: [ + '654321' + ] + interval: 1 + maintenanceWindow: 'PT4H' + monthlyOccurrences: [ + { + day: 'Friday' + occurrence: 3 + } + ] + name: 'Windows_ZeroDay' + operatingSystem: 'Windows' + rebootSetting: 'IfRequired' + scopeByTags: { + Update: [ + 'Automatic-Wave1' + ] + } + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Definition' + 'FeaturePack' + 'Security' + 'ServicePack' + 'Tools' + 'UpdateRollup' + 'Updates' + ] + } + { + excludeUpdates: [ + 'icacls' + ] + frequency: 'OneTime' + includeUpdates: [ + 'kernel' + ] + maintenanceWindow: 'PT4H' + name: 'Linux_ZeroDay' + operatingSystem: 'Linux' + rebootSetting: 'IfRequired' + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Other' + 'Security' + ] + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + variables: [ + { + description: 'TestStringDescription' + name: 'TestString' + value: '\'TestString\'' + } + { + description: 'TestIntegerDescription' + name: 'TestInteger' + value: '500' + } + { + description: 'TestBooleanDescription' + name: 'TestBoolean' + value: 'false' + } + { + description: 'TestDateTimeDescription' + name: 'TestDateTime' + value: '\'\\/Date(1637934042656)\\/\'' + } + { + description: 'TestEncryptedDescription' + name: 'TestEncryptedVariable' + value: '\'TestEncryptedValue\'' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "aawaf001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "disableLocalAuth": { + "value": true + }, + "gallerySolutions": { + "value": [ + { + "name": "", + "plan": { + "product": "OMSGallery/Updates" + } + } + ] + }, + "jobSchedules": { + "value": [ + { + "runbookName": "TestRunbook", + "scheduleName": "TestSchedule" + } + ] + }, + "linkedWorkspaceResourceId": { + "value": "" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "" + ] + } + }, + "modules": { + "value": [ + { + "name": "PSWindowsUpdate", + "uri": "https://www.powershellgallery.com/api/v2/package", + "version": "latest" + } + ] + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "Webhook", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "DSCAndHybridWorker", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + ] + }, + "runbooks": { + "value": [ + { + "description": "Test runbook", + "name": "TestRunbook", + "type": "PowerShell", + "uri": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.automation/101-automation/scripts/AzureAutomationTutorial.ps1", + "version": "1.0.0.0" + } + ] + }, + "schedules": { + "value": [ + { + "advancedSchedule": {}, + "expiryTime": "9999-12-31T13:00", + "frequency": "Hour", + "interval": 12, + "name": "TestSchedule", + "startTime": "", + "timeZone": "Europe/Berlin" + } + ] + }, + "softwareUpdateConfigurations": { + "value": [ + { + "excludeUpdates": [ + "123456" + ], + "frequency": "Month", + "includeUpdates": [ + "654321" + ], + "interval": 1, + "maintenanceWindow": "PT4H", + "monthlyOccurrences": [ + { + "day": "Friday", + "occurrence": 3 + } + ], + "name": "Windows_ZeroDay", + "operatingSystem": "Windows", + "rebootSetting": "IfRequired", + "scopeByTags": { + "Update": [ + "Automatic-Wave1" + ] + }, + "startTime": "22:00", + "updateClassifications": [ + "Critical", + "Definition", + "FeaturePack", + "Security", + "ServicePack", + "Tools", + "UpdateRollup", + "Updates" + ] + }, + { + "excludeUpdates": [ + "icacls" + ], + "frequency": "OneTime", + "includeUpdates": [ + "kernel" + ], + "maintenanceWindow": "PT4H", + "name": "Linux_ZeroDay", + "operatingSystem": "Linux", + "rebootSetting": "IfRequired", + "startTime": "22:00", + "updateClassifications": [ + "Critical", + "Other", + "Security" + ] + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "variables": { + "value": [ + { + "description": "TestStringDescription", + "name": "TestString", + "value": "\"TestString\"" + }, + { + "description": "TestIntegerDescription", + "name": "TestInteger", + "value": "500" + }, + { + "description": "TestBooleanDescription", + "name": "TestBoolean", + "value": "false" + }, + { + "description": "TestDateTimeDescription", + "name": "TestDateTime", + "value": "\"\\/Date(1637934042656)\\/\"" + }, + { + "description": "TestEncryptedDescription", + "name": "TestEncryptedVariable", + "value": "\"TestEncryptedValue\"" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/automation/automation-account:' + +// Required parameters +param name = 'aawaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = true +param gallerySolutions = [ + { + name: '' + plan: { + product: 'OMSGallery/Updates' + } + } +] +param jobSchedules = [ + { + runbookName: 'TestRunbook' + scheduleName: 'TestSchedule' + } +] +param linkedWorkspaceResourceId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param modules = [ + { + name: 'PSWindowsUpdate' + uri: 'https://www.powershellgallery.com/api/v2/package' + version: 'latest' + } +] +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Webhook' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'DSCAndHybridWorker' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param runbooks = [ + { + description: 'Test runbook' + name: 'TestRunbook' + type: 'PowerShell' + uri: 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.automation/101-automation/scripts/AzureAutomationTutorial.ps1' + version: '1.0.0.0' + } +] +param schedules = [ + { + advancedSchedule: {} + expiryTime: '9999-12-31T13:00' + frequency: 'Hour' + interval: 12 + name: 'TestSchedule' + startTime: '' + timeZone: 'Europe/Berlin' + } +] +param softwareUpdateConfigurations = [ + { + excludeUpdates: [ + '123456' + ] + frequency: 'Month' + includeUpdates: [ + '654321' + ] + interval: 1 + maintenanceWindow: 'PT4H' + monthlyOccurrences: [ + { + day: 'Friday' + occurrence: 3 + } + ] + name: 'Windows_ZeroDay' + operatingSystem: 'Windows' + rebootSetting: 'IfRequired' + scopeByTags: { + Update: [ + 'Automatic-Wave1' + ] + } + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Definition' + 'FeaturePack' + 'Security' + 'ServicePack' + 'Tools' + 'UpdateRollup' + 'Updates' + ] + } + { + excludeUpdates: [ + 'icacls' + ] + frequency: 'OneTime' + includeUpdates: [ + 'kernel' + ] + maintenanceWindow: 'PT4H' + name: 'Linux_ZeroDay' + operatingSystem: 'Linux' + rebootSetting: 'IfRequired' + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Other' + 'Security' + ] + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param variables = [ + { + description: 'TestStringDescription' + name: 'TestString' + value: '\'TestString\'' + } + { + description: 'TestIntegerDescription' + name: 'TestInteger' + value: '500' + } + { + description: 'TestBooleanDescription' + name: 'TestBoolean' + value: 'false' + } + { + description: 'TestDateTimeDescription' + name: 'TestDateTime' + value: '\'\\/Date(1637934042656)\\/\'' + } + { + description: 'TestEncryptedDescription' + name: 'TestEncryptedVariable' + value: '\'TestEncryptedValue\'' + } +] +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Automation Account. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`credentials`](#parameter-credentials) | array | List of credentials to be created in the automation account. | +| [`customerManagedKey`](#parameter-customermanagedkey) | object | The customer managed key definition. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`disableLocalAuth`](#parameter-disablelocalauth) | bool | Disable local authentication profile used within the resource. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`gallerySolutions`](#parameter-gallerysolutions) | array | List of gallerySolutions to be created in the linked log analytics workspace. | +| [`jobSchedules`](#parameter-jobschedules) | array | List of jobSchedules to be created in the automation account. | +| [`linkedWorkspaceResourceId`](#parameter-linkedworkspaceresourceid) | string | ID of the log analytics workspace to be linked to the deployed automation account. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`modules`](#parameter-modules) | array | List of modules to be created in the automation account. | +| [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`runbooks`](#parameter-runbooks) | array | List of runbooks to be created in the automation account. | +| [`schedules`](#parameter-schedules) | array | List of schedules to be created in the automation account. | +| [`skuName`](#parameter-skuname) | string | SKU name of the account. | +| [`softwareUpdateConfigurations`](#parameter-softwareupdateconfigurations) | array | List of softwareUpdateConfigurations to be created in the automation account. | +| [`tags`](#parameter-tags) | object | Tags of the Automation Account resource. | +| [`variables`](#parameter-variables) | array | List of variables to be created in the automation account. | + +### Parameter: `name` + +Name of the Automation Account. + +- Required: Yes +- Type: string + +### Parameter: `credentials` + +List of credentials to be created in the automation account. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-credentialsname) | string | Name of the Automation Account credential. | +| [`password`](#parameter-credentialspassword) | securestring | Password of the credential. | +| [`userName`](#parameter-credentialsusername) | string | The user name associated to the credential. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-credentialsdescription) | string | Description of the credential. | + +### Parameter: `credentials.name` + +Name of the Automation Account credential. + +- Required: Yes +- Type: string + +### Parameter: `credentials.password` + +Password of the credential. + +- Required: Yes +- Type: securestring + +### Parameter: `credentials.userName` + +The user name associated to the credential. + +- Required: Yes +- Type: string + +### Parameter: `credentials.description` + +Description of the credential. + +- Required: No +- Type: string + +### Parameter: `customerManagedKey` + +The customer managed key definition. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyName`](#parameter-customermanagedkeykeyname) | string | The name of the customer managed key to use for encryption. | +| [`keyVaultResourceId`](#parameter-customermanagedkeykeyvaultresourceid) | string | The resource ID of a key vault to reference a customer managed key for encryption from. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVersion`](#parameter-customermanagedkeykeyversion) | string | The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time. | +| [`userAssignedIdentityResourceId`](#parameter-customermanagedkeyuserassignedidentityresourceid) | string | User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use. | + +### Parameter: `customerManagedKey.keyName` + +The name of the customer managed key to use for encryption. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKey.keyVaultResourceId` + +The resource ID of a key vault to reference a customer managed key for encryption from. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKey.keyVersion` + +The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time. + +- Required: No +- Type: string + +### Parameter: `customerManagedKey.userAssignedIdentityResourceId` + +User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of the diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of the diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `disableLocalAuth` + +Disable local authentication profile used within the resource. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `gallerySolutions` + +List of gallerySolutions to be created in the linked log analytics workspace. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-gallerysolutionsname) | string | Name of the solution.

For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.

For solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.

The solution type is case-sensitive. | +| [`plan`](#parameter-gallerysolutionsplan) | object | Plan for solution object supported by the OperationsManagement resource provider. | + +### Parameter: `gallerySolutions.name` + +Name of the solution.

For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.

For solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.

The solution type is case-sensitive. + +- Required: Yes +- Type: string + +### Parameter: `gallerySolutions.plan` + +Plan for solution object supported by the OperationsManagement resource provider. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`product`](#parameter-gallerysolutionsplanproduct) | string | The product name of the deployed solution.

For Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.

For a third party solution, it can be anything.

This is case sensitive. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-gallerysolutionsplanname) | string | Name of the solution to be created.

For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.

For solutions authored by third parties, it can be anything.

The solution type is case-sensitive.

If not provided, the value of the `name` parameter will be used. | +| [`publisher`](#parameter-gallerysolutionsplanpublisher) | string | The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value. | + +### Parameter: `gallerySolutions.plan.product` + +The product name of the deployed solution.

For Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.

For a third party solution, it can be anything.

This is case sensitive. + +- Required: Yes +- Type: string + +### Parameter: `gallerySolutions.plan.name` + +Name of the solution to be created.

For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.

For solutions authored by third parties, it can be anything.

The solution type is case-sensitive.

If not provided, the value of the `name` parameter will be used. + +- Required: No +- Type: string + +### Parameter: `gallerySolutions.plan.publisher` + +The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value. + +- Required: No +- Type: string + +### Parameter: `jobSchedules` + +List of jobSchedules to be created in the automation account. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `linkedWorkspaceResourceId` + +ID of the log analytics workspace to be linked to the deployed automation account. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. + +- Required: No +- Type: array + +### Parameter: `modules` + +List of modules to be created in the automation account. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `privateEndpoints` + +Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file" for a Storage Account's Private Endpoints. | +| [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationSecurityGroupResourceIds`](#parameter-privateendpointsapplicationsecuritygroupresourceids) | array | Application security groups in which the private endpoint IP configuration is included. | +| [`customDnsConfigs`](#parameter-privateendpointscustomdnsconfigs) | array | Custom DNS configurations. | +| [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | +| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | +| [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | +| [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | +| [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | +| [`privateDnsZoneGroup`](#parameter-privateendpointsprivatednszonegroup) | object | The private DNS zone group to configure for the private endpoint. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | +| [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | + +### Parameter: `privateEndpoints.service` + +The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file" for a Storage Account's Private Endpoints. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.subnetResourceId` + +Resource ID of the subnet where the endpoint needs to be created. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.applicationSecurityGroupResourceIds` + +Application security groups in which the private endpoint IP configuration is included. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs` + +Custom DNS configurations. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | FQDN that resolves to private endpoint IP address. | + +### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +A list of private IP addresses of the private endpoint. + +- Required: Yes +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +FQDN that resolves to private endpoint IP address. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.customNetworkInterfaceName` + +The custom name of the network interface attached to the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.ipConfigurations` + +A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsipconfigurationsname) | string | The name of the resource that is unique within a resource group. | +| [`properties`](#parameter-privateendpointsipconfigurationsproperties) | object | Properties of private endpoint IP configurations. | + +### Parameter: `privateEndpoints.ipConfigurations.name` + +The name of the resource that is unique within a resource group. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties` + +Properties of private endpoint IP configurations. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private IP address obtained from the private endpoint's subnet. | + +### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` + +The ID of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.memberName` + +The member name of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` + +A private IP address obtained from the private endpoint's subnet. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.location` + +The location to deploy the private endpoint to. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.lock` + +Specify the type of lock. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-privateendpointslockkind) | string | Specify the type of lock. | +| [`name`](#parameter-privateendpointslockname) | string | Specify the name of lock. | + +### Parameter: `privateEndpoints.lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `privateEndpoints.lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.manualConnectionRequestMessage` + +A message passed to the owner of the remote resource with the manual connection request. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.name` + +The name of the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup` + +The private DNS zone group to configure for the private endpoint. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneGroupConfigs`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigs) | array | The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the Private DNS Zone Group. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs` + +The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneResourceId`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsprivatednszoneresourceid) | string | The resource id of the private DNS zone. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsname) | string | The name of the private DNS Zone Group config. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.privateDnsZoneResourceId` + +The resource id of the private DNS zone. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.name` + +The name of the private DNS Zone Group config. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.name` + +The name of the Private DNS Zone Group. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.resourceGroupName` + +Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-privateendpointsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-privateendpointsroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-privateendpointsroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-privateendpointsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-privateendpointsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-privateendpointsroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-privateendpointsroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-privateendpointsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `privateEndpoints.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `privateEndpoints.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `privateEndpoints.tags` + +Tags to be applied on all resources/resource groups in this deployment. + +- Required: No +- Type: object + +### Parameter: `publicNetworkAccess` + +Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Automation Contributor'` + - `'Automation Job Operator'` + - `'Automation Operator'` + - `'Automation Runbook Operator'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `runbooks` + +List of runbooks to be created in the automation account. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `schedules` + +List of schedules to be created in the automation account. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `skuName` + +SKU name of the account. + +- Required: No +- Type: string +- Default: `'Basic'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Free' + ] + ``` + +### Parameter: `softwareUpdateConfigurations` + +List of softwareUpdateConfigurations to be created in the automation account. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `tags` + +Tags of the Automation Account resource. + +- Required: No +- Type: object + +### Parameter: `variables` + +List of variables to be created in the automation account. + +- Required: No +- Type: array +- Default: `[]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed automation account. | +| `privateEndpoints` | array | The private endpoints of the automation account. | +| `resourceGroupName` | string | The resource group of the deployed automation account. | +| `resourceId` | string | The resource ID of the deployed automation account. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/private-endpoint:0.7.1` | Remote reference | +| `br/public:avm/res/operations-management/solution:0.3.0` | Remote reference | +| `br/public:avm/utl/types/avm-common-types:0.4.0` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/automation/automation-account/credential/README.md b/avm/1.1.0/res/automation/automation-account/credential/README.md new file mode 100644 index 000000000..98579563f --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/credential/README.md @@ -0,0 +1,80 @@ +# Automation Account Credential `[Microsoft.Automation/automationAccounts/credentials]` + +This module deploys Azure Automation Account Credential. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Automation/automationAccounts/credentials` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2023-11-01/automationAccounts/credentials) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Automation Account credential. | +| [`password`](#parameter-password) | securestring | Password of the credential. | +| [`userName`](#parameter-username) | string | The user name associated to the credential. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`automationAccountName`](#parameter-automationaccountname) | string | The name of the parent Automation Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | Description of the credential. | + +### Parameter: `name` + +Name of the Automation Account credential. + +- Required: Yes +- Type: string + +### Parameter: `password` + +Password of the credential. + +- Required: Yes +- Type: securestring + +### Parameter: `userName` + +The user name associated to the credential. + +- Required: Yes +- Type: string + +### Parameter: `automationAccountName` + +The name of the parent Automation Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `description` + +Description of the credential. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the credential associated to the automation account. | +| `resourceGroupName` | string | The resource group of the deployed credential. | +| `resourceId` | string | The resource Id of the credential associated to the automation account. | diff --git a/avm/1.1.0/res/automation/automation-account/credential/main.bicep b/avm/1.1.0/res/automation/automation-account/credential/main.bicep new file mode 100644 index 000000000..b888a7be7 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/credential/main.bicep @@ -0,0 +1,41 @@ +metadata name = 'Automation Account Credential' +metadata description = 'This module deploys Azure Automation Account Credential.' + +@sys.description('Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment.') +param automationAccountName string + +@sys.description('Required. Name of the Automation Account credential.') +param name string + +@sys.description('Required. The user name associated to the credential.') +param userName string + +@sys.description('Required. Password of the credential.') +@secure() +param password string + +@sys.description('Optional. Description of the credential.') +param description string? + +resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' existing = { + name: automationAccountName +} + +resource credential 'Microsoft.Automation/automationAccounts/credentials@2023-11-01' = { + name: name + parent: automationAccount + properties: { + password: password + userName: userName + description: description ?? '' + } +} + +@sys.description('The resource Id of the credential associated to the automation account.') +output resourceId string = credential.id + +@sys.description('The name of the credential associated to the automation account.') +output name string = credential.name + +@sys.description('The resource group of the deployed credential.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/automation/automation-account/credential/main.json b/avm/1.1.0/res/automation/automation-account/credential/main.json new file mode 100644 index 000000000..b3c932b29 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/credential/main.json @@ -0,0 +1,88 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10206419659334193725" + }, + "name": "Automation Account Credential", + "description": "This module deploys Azure Automation Account Credential." + }, + "parameters": { + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Automation Account credential." + } + }, + "userName": { + "type": "string", + "metadata": { + "description": "Required. The user name associated to the credential." + } + }, + "password": { + "type": "securestring", + "metadata": { + "description": "Required. Password of the credential." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the credential." + } + } + }, + "resources": { + "automationAccount": { + "existing": true, + "type": "Microsoft.Automation/automationAccounts", + "apiVersion": "2022-08-08", + "name": "[parameters('automationAccountName')]" + }, + "credential": { + "type": "Microsoft.Automation/automationAccounts/credentials", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "properties": { + "password": "[parameters('password')]", + "userName": "[parameters('userName')]", + "description": "[coalesce(parameters('description'), '')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource Id of the credential associated to the automation account." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/credentials', parameters('automationAccountName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the credential associated to the automation account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed credential." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/automation/automation-account/job-schedule/README.md b/avm/1.1.0/res/automation/automation-account/job-schedule/README.md new file mode 100644 index 000000000..32748da4c --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/job-schedule/README.md @@ -0,0 +1,96 @@ +# Automation Account Job Schedules `[Microsoft.Automation/automationAccounts/jobSchedules]` + +This module deploys an Azure Automation Account Job Schedule. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Automation/automationAccounts/jobSchedules` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/jobSchedules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`runbookName`](#parameter-runbookname) | string | The runbook property associated with the entity. | +| [`scheduleName`](#parameter-schedulename) | string | The schedule property associated with the entity. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`automationAccountName`](#parameter-automationaccountname) | string | The name of the parent Automation Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`parameters`](#parameter-parameters) | object | List of job properties. | +| [`runOn`](#parameter-runon) | string | The hybrid worker group that the scheduled job should run on. | + +**Generated parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Automation Account job schedule. Must be a GUID and is autogenerated. No need to provide this value. | + +### Parameter: `runbookName` + +The runbook property associated with the entity. + +- Required: Yes +- Type: string + +### Parameter: `scheduleName` + +The schedule property associated with the entity. + +- Required: Yes +- Type: string + +### Parameter: `automationAccountName` + +The name of the parent Automation Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `parameters` + +List of job properties. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `runOn` + +The hybrid worker group that the scheduled job should run on. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `name` + +Name of the Automation Account job schedule. Must be a GUID and is autogenerated. No need to provide this value. + +- Required: No +- Type: string +- Default: `[newGuid()]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed job schedule. | +| `resourceGroupName` | string | The resource group of the deployed job schedule. | +| `resourceId` | string | The resource ID of the deployed job schedule. | diff --git a/avm/1.1.0/res/automation/automation-account/job-schedule/main.bicep b/avm/1.1.0/res/automation/automation-account/job-schedule/main.bicep new file mode 100644 index 000000000..0257601b9 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/job-schedule/main.bicep @@ -0,0 +1,50 @@ +metadata name = 'Automation Account Job Schedules' +metadata description = 'This module deploys an Azure Automation Account Job Schedule.' + +@description('Generated. Name of the Automation Account job schedule. Must be a GUID and is autogenerated. No need to provide this value.') +param name string = newGuid() + +@description('Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment.') +param automationAccountName string + +@description('Required. The runbook property associated with the entity.') +param runbookName string + +@description('Required. The schedule property associated with the entity.') +param scheduleName string + +@description('Optional. List of job properties.') +param parameters object = {} + +@description('Optional. The hybrid worker group that the scheduled job should run on.') +param runOn string = '' + +resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' existing = { + name: automationAccountName +} + +resource jobSchedule 'Microsoft.Automation/automationAccounts/jobSchedules@2022-08-08' = { + // For each job schedule deployed with an ARM template, the GUID must be unique. Even if you're rescheduling an existing schedule, you'll need to change the GUID. This applies even if you've previously deleted an existing job schedule that was created with the same template. Reusing the same GUID results in a failed deployment. + #disable-next-line use-stable-resource-identifiers + name: name + parent: automationAccount + properties: { + parameters: parameters + runbook: { + name: runbookName + } + runOn: !empty(runOn) ? runOn : null + schedule: { + name: scheduleName + } + } +} + +@description('The name of the deployed job schedule.') +output name string = jobSchedule.name + +@description('The resource ID of the deployed job schedule.') +output resourceId string = jobSchedule.id + +@description('The resource group of the deployed job schedule.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/automation/automation-account/job-schedule/main.json b/avm/1.1.0/res/automation/automation-account/job-schedule/main.json new file mode 100644 index 000000000..006aded51 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/job-schedule/main.json @@ -0,0 +1,94 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "4203011213224324137" + }, + "name": "Automation Account Job Schedules", + "description": "This module deploys an Azure Automation Account Job Schedule." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[newGuid()]", + "metadata": { + "description": "Generated. Name of the Automation Account job schedule. Must be a GUID and is autogenerated. No need to provide this value." + } + }, + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "runbookName": { + "type": "string", + "metadata": { + "description": "Required. The runbook property associated with the entity." + } + }, + "scheduleName": { + "type": "string", + "metadata": { + "description": "Required. The schedule property associated with the entity." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. List of job properties." + } + }, + "runOn": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The hybrid worker group that the scheduled job should run on." + } + } + }, + "resources": [ + { + "type": "Microsoft.Automation/automationAccounts/jobSchedules", + "apiVersion": "2022-08-08", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "properties": { + "parameters": "[parameters('parameters')]", + "runbook": { + "name": "[parameters('runbookName')]" + }, + "runOn": "[if(not(empty(parameters('runOn'))), parameters('runOn'), null())]", + "schedule": { + "name": "[parameters('scheduleName')]" + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed job schedule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed job schedule." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/jobSchedules', parameters('automationAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed job schedule." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/automation/automation-account/main.bicep b/avm/1.1.0/res/automation/automation-account/main.bicep new file mode 100644 index 000000000..b496d1179 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/main.bicep @@ -0,0 +1,564 @@ +metadata name = 'Automation Accounts' +metadata description = 'This module deploys an Azure Automation Account.' + +@description('Required. Name of the Automation Account.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. SKU name of the account.') +@allowed([ + 'Free' + 'Basic' +]) +param skuName string = 'Basic' + +import { customerManagedKeyType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' +@description('Optional. The customer managed key definition.') +param customerManagedKey customerManagedKeyType? + +@description('Optional. List of credentials to be created in the automation account.') +param credentials credentialType[]? + +@description('Optional. List of modules to be created in the automation account.') +param modules array = [] + +@description('Optional. List of runbooks to be created in the automation account.') +param runbooks array = [] + +@description('Optional. List of schedules to be created in the automation account.') +param schedules array = [] + +@description('Optional. List of jobSchedules to be created in the automation account.') +param jobSchedules array = [] + +@description('Optional. List of variables to be created in the automation account.') +param variables array = [] + +@description('Optional. ID of the log analytics workspace to be linked to the deployed automation account.') +param linkedWorkspaceResourceId string = '' + +@description('Optional. List of gallerySolutions to be created in the linked log analytics workspace.') +param gallerySolutions gallerySolutionType[]? + +@description('Optional. List of softwareUpdateConfigurations to be created in the automation account.') +param softwareUpdateConfigurations array = [] + +@description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set.') +@allowed([ + '' + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string = '' + +@description('Optional. Disable local authentication profile used within the resource.') +param disableLocalAuth bool = true + +import { privateEndpointMultiServiceType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointMultiServiceType[]? + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +import { managedIdentityAllType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentityAllType? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the Automation Account resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +var builtInRoleNames = { + 'Automation Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f353d9bd-d4a6-484e-a77a-8050b599b867' + ) + 'Automation Job Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4fe576fe-1146-4730-92eb-48519fa6bf9f' + ) + 'Automation Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'd3881f73-407a-4167-8283-e981cbba0404' + ) + 'Automation Runbook Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '5fb5aef8-1081-4b8e-bb16-9d5d0385bab5' + ) + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.automation-automationaccount.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource cMKKeyVault 'Microsoft.KeyVault/vaults@2023-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId)) { + name: last(split((customerManagedKey.?keyVaultResourceId ?? 'dummyVault'), '/')) + scope: resourceGroup( + split((customerManagedKey.?keyVaultResourceId ?? '//'), '/')[2], + split((customerManagedKey.?keyVaultResourceId ?? '////'), '/')[4] + ) + + resource cMKKey 'keys@2023-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { + name: customerManagedKey.?keyName ?? 'dummyKey' + } +} + +resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = if (!empty(customerManagedKey.?userAssignedIdentityResourceId)) { + name: last(split(customerManagedKey.?userAssignedIdentityResourceId ?? 'dummyMsi', '/')) + scope: resourceGroup( + split((customerManagedKey.?userAssignedIdentityResourceId ?? '//'), '/')[2], + split((customerManagedKey.?userAssignedIdentityResourceId ?? '////'), '/')[4] + ) +} + +resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' = { + name: name + location: location + tags: tags + identity: identity + properties: { + sku: { + name: skuName + } + encryption: !empty(customerManagedKey) + ? { + keySource: 'Microsoft.Keyvault' + identity: !empty(customerManagedKey.?userAssignedIdentityResourceId) + ? { + userAssignedIdentity: cMKUserAssignedIdentity.id + } + : null + keyVaultProperties: { + keyName: customerManagedKey!.keyName + keyvaultUri: cMKKeyVault.properties.vaultUri + keyVersion: !empty(customerManagedKey.?keyVersion ?? '') + ? customerManagedKey!.keyVersion + : last(split(cMKKeyVault::cMKKey.properties.keyUriWithVersion, '/')) + } + } + : null + publicNetworkAccess: !empty(publicNetworkAccess) + ? (publicNetworkAccess == 'Disabled' ? false : true) + : (!empty(privateEndpoints) ? false : null) + disableLocalAuth: disableLocalAuth + } +} + +module automationAccount_credentials 'credential/main.bicep' = [ + for (credential, index) in (credentials ?? []): { + name: '${uniqueString(deployment().name, location)}-AutomationAccount-Credential-${index}' + params: { + automationAccountName: automationAccount.name + name: credential.name + password: credential.password + userName: credential.userName + description: credential.?description + } + } +] + +module automationAccount_modules 'module/main.bicep' = [ + for (module, index) in modules: { + name: '${uniqueString(deployment().name, location)}-AutoAccount-Module-${index}' + params: { + name: module.name + automationAccountName: automationAccount.name + version: module.version + uri: module.uri + location: location + tags: module.?tags ?? tags + } + } +] + +module automationAccount_schedules 'schedule/main.bicep' = [ + for (schedule, index) in schedules: { + name: '${uniqueString(deployment().name, location)}-AutoAccount-Schedule-${index}' + params: { + name: schedule.name + automationAccountName: automationAccount.name + advancedSchedule: schedule.?advancedSchedule + description: schedule.?description + expiryTime: schedule.?expiryTime + frequency: schedule.?frequency + interval: schedule.?interval + startTime: schedule.?startTime + timeZone: schedule.?timeZone + } + } +] + +module automationAccount_runbooks 'runbook/main.bicep' = [ + for (runbook, index) in runbooks: { + name: '${uniqueString(deployment().name, location)}-AutoAccount-Runbook-${index}' + params: { + name: runbook.name + automationAccountName: automationAccount.name + type: runbook.type + description: runbook.?description + uri: runbook.?uri + version: runbook.?version + sasTokenValidityLength: runbook.?sasTokenValidityLength + scriptStorageAccountResourceId: runbook.?scriptStorageAccountResourceId + location: location + tags: runbook.?tags ?? tags + } + } +] + +module automationAccount_jobSchedules 'job-schedule/main.bicep' = [ + for (jobSchedule, index) in jobSchedules: { + name: '${uniqueString(deployment().name, location)}-AutoAccount-JobSchedule-${index}' + params: { + automationAccountName: automationAccount.name + runbookName: jobSchedule.runbookName + scheduleName: jobSchedule.scheduleName + parameters: jobSchedule.?parameters + runOn: jobSchedule.?runOn + } + dependsOn: [ + automationAccount_schedules + automationAccount_runbooks + ] + } +] + +module automationAccount_variables 'variable/main.bicep' = [ + for (variable, index) in variables: { + name: '${uniqueString(deployment().name, location)}-AutoAccount-Variable-${index}' + params: { + automationAccountName: automationAccount.name + name: variable.name + description: variable.?description + value: variable.value + isEncrypted: variable.?isEncrypted + } + } +] + +module automationAccount_linkedService 'modules/linked-service.bicep' = if (!empty(linkedWorkspaceResourceId)) { + name: '${uniqueString(deployment().name, location)}-AutoAccount-LinkedService' + params: { + name: 'automation' + logAnalyticsWorkspaceName: last(split(linkedWorkspaceResourceId, '/'))! + resourceId: automationAccount.id + tags: tags + } + // This is to support linked services to law in different subscription and resource group than the automation account. + // The current scope is used by default if no linked service is intended to be created. + scope: resourceGroup( + (!empty(linkedWorkspaceResourceId) + ? (split((!empty(linkedWorkspaceResourceId) ? linkedWorkspaceResourceId : '//'), '/')[2]) + : subscription().subscriptionId), + !empty(linkedWorkspaceResourceId) + ? (split((!empty(linkedWorkspaceResourceId) ? linkedWorkspaceResourceId : '////'), '/')[4]) + : resourceGroup().name + ) +} + +module automationAccount_solutions 'br/public:avm/res/operations-management/solution:0.3.0' = [ + for (gallerySolution, index) in gallerySolutions ?? []: if (!empty(linkedWorkspaceResourceId)) { + name: '${uniqueString(deployment().name, location)}-AutoAccount-Solution-${index}' + params: { + name: gallerySolution.name + location: location + logAnalyticsWorkspaceName: last(split(linkedWorkspaceResourceId, '/'))! + plan: gallerySolution.plan + enableTelemetry: enableTelemetry + } + // This is to support solution to law in different subscription and resource group than the automation account. + // The current scope is used by default if no linked service is intended to be created. + scope: resourceGroup( + (!empty(linkedWorkspaceResourceId) + ? (split((!empty(linkedWorkspaceResourceId) ? linkedWorkspaceResourceId : '//'), '/')[2]) + : subscription().subscriptionId), + !empty(linkedWorkspaceResourceId) + ? (split((!empty(linkedWorkspaceResourceId) ? linkedWorkspaceResourceId : '////'), '/')[4]) + : resourceGroup().name + ) + dependsOn: [ + automationAccount_linkedService + ] + } +] + +module automationAccount_softwareUpdateConfigurations 'software-update-configuration/main.bicep' = [ + for (softwareUpdateConfiguration, index) in softwareUpdateConfigurations: { + name: '${uniqueString(deployment().name, location)}-AutoAccount-SwUpdateConfig-${index}' + params: { + name: softwareUpdateConfiguration.name + automationAccountName: automationAccount.name + frequency: softwareUpdateConfiguration.frequency + operatingSystem: softwareUpdateConfiguration.operatingSystem + rebootSetting: softwareUpdateConfiguration.rebootSetting + azureVirtualMachines: softwareUpdateConfiguration.?azureVirtualMachines + excludeUpdates: softwareUpdateConfiguration.?excludeUpdates + expiryTime: softwareUpdateConfiguration.?expiryTime + expiryTimeOffsetMinutes: softwareUpdateConfiguration.?expiryTimeOffsetMinute + includeUpdates: softwareUpdateConfiguration.?includeUpdates + interval: softwareUpdateConfiguration.?interval + isEnabled: softwareUpdateConfiguration.?isEnabled + maintenanceWindow: softwareUpdateConfiguration.?maintenanceWindow + monthDays: softwareUpdateConfiguration.?monthDays + monthlyOccurrences: softwareUpdateConfiguration.?monthlyOccurrences + nextRun: softwareUpdateConfiguration.?nextRun + nextRunOffsetMinutes: softwareUpdateConfiguration.?nextRunOffsetMinutes + nonAzureComputerNames: softwareUpdateConfiguration.?nonAzureComputerNames + nonAzureQueries: softwareUpdateConfiguration.?nonAzureQueries + postTaskParameters: softwareUpdateConfiguration.?postTaskParameters + postTaskSource: softwareUpdateConfiguration.?postTaskSource + preTaskParameters: softwareUpdateConfiguration.?preTaskParameters + preTaskSource: softwareUpdateConfiguration.?preTaskSource + scheduleDescription: softwareUpdateConfiguration.?scheduleDescription + scopeByLocations: softwareUpdateConfiguration.?scopeByLocations + scopeByResources: softwareUpdateConfiguration.?scopeByResources + scopeByTags: softwareUpdateConfiguration.?scopeByTags + scopeByTagsOperation: softwareUpdateConfiguration.?scopeByTagsOperation + startTime: softwareUpdateConfiguration.?startTime + timeZone: softwareUpdateConfiguration.?timeZone + updateClassifications: softwareUpdateConfiguration.?updateClassifications + weekDays: softwareUpdateConfiguration.?weekDays + } + dependsOn: [ + automationAccount_solutions + ] + } +] + +resource automationAccount_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: automationAccount +} + +resource automationAccount_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: automationAccount + } +] + +module automationAccount_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.7.1' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-automationAccount-PrivateEndpoint-${index}' + scope: resourceGroup(privateEndpoint.?resourceGroupName ?? '') + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(automationAccount.id, '/'))}-${privateEndpoint.service}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(automationAccount.id, '/'))}-${privateEndpoint.service}-${index}' + properties: { + privateLinkServiceId: automationAccount.id + groupIds: [ + privateEndpoint.service + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(automationAccount.id, '/'))}-${privateEndpoint.service}-${index}' + properties: { + privateLinkServiceId: automationAccount.id + groupIds: [ + privateEndpoint.service + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] + : null + subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry + location: privateEndpoint.?location ?? reference( + split(privateEndpoint.subnetResourceId, '/subnets/')[0], + '2020-06-01', + 'Full' + ).location + lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } + } +] + +resource automationAccount_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + automationAccount.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: automationAccount + } +] + +@description('The name of the deployed automation account.') +output name string = automationAccount.name + +@description('The resource ID of the deployed automation account.') +output resourceId string = automationAccount.id + +@description('The resource group of the deployed automation account.') +output resourceGroupName string = resourceGroup().name + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string? = automationAccount.?identity.?principalId + +@description('The location the resource was deployed into.') +output location string = automationAccount.location + +@description('The private endpoints of the automation account.') +output privateEndpoints array = [ + for (pe, i) in (!empty(privateEndpoints) ? array(privateEndpoints) : []): { + name: automationAccount_privateEndpoints[i].outputs.name + resourceId: automationAccount_privateEndpoints[i].outputs.resourceId + groupId: automationAccount_privateEndpoints[i].outputs.groupId + customDnsConfig: automationAccount_privateEndpoints[i].outputs.customDnsConfig + networkInterfaceIds: automationAccount_privateEndpoints[i].outputs.networkInterfaceIds + } +] + +// =============== // +// Definitions // +// =============== // + +@export() +type credentialType = { + @sys.description('Required. Name of the Automation Account credential.') + name: string + + @sys.description('Required. The user name associated to the credential.') + userName: string + + @sys.description('Required. Password of the credential.') + @secure() + password: string + + @sys.description('Optional. Description of the credential.') + description: string? +} + +import { solutionPlanType } from 'br/public:avm/res/operations-management/solution:0.3.0' + +@export() +type gallerySolutionType = { + @description('''Required. Name of the solution. + For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`. + For solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`. + The solution type is case-sensitive.''') + name: string + + @description('Required. Plan for solution object supported by the OperationsManagement resource provider.') + plan: solutionPlanType +} diff --git a/avm/1.1.0/res/automation/automation-account/main.json b/avm/1.1.0/res/automation/automation-account/main.json new file mode 100644 index 000000000..cbc86ad7f --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/main.json @@ -0,0 +1,3570 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "16427250452433742384" + }, + "name": "Automation Accounts", + "description": "This module deploys an Azure Automation Account." + }, + "definitions": { + "credentialType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Automation Account credential." + } + }, + "userName": { + "type": "string", + "metadata": { + "description": "Required. The user name associated to the credential." + } + }, + "password": { + "type": "securestring", + "metadata": { + "description": "Required. Password of the credential." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the credential." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "gallerySolutionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "privateEndpointMultiServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/operations-management/solution:0.3.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Automation Account." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Free", + "Basic" + ], + "metadata": { + "description": "Optional. SKU name of the account." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "credentials": { + "type": "array", + "items": { + "$ref": "#/definitions/credentialType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of credentials to be created in the automation account." + } + }, + "modules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of modules to be created in the automation account." + } + }, + "runbooks": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of runbooks to be created in the automation account." + } + }, + "schedules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of schedules to be created in the automation account." + } + }, + "jobSchedules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of jobSchedules to be created in the automation account." + } + }, + "variables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of variables to be created in the automation account." + } + }, + "linkedWorkspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the log analytics workspace to be linked to the deployed automation account." + } + }, + "gallerySolutions": { + "type": "array", + "items": { + "$ref": "#/definitions/gallerySolutionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of gallerySolutions to be created in the linked log analytics workspace." + } + }, + "softwareUpdateConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of softwareUpdateConfigurations to be created in the automation account." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable local authentication profile used within the resource." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointMultiServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the Automation Account resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Automation Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f353d9bd-d4a6-484e-a77a-8050b599b867')]", + "Automation Job Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4fe576fe-1146-4730-92eb-48519fa6bf9f')]", + "Automation Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd3881f73-407a-4167-8283-e981cbba0404')]", + "Automation Runbook Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5fb5aef8-1081-4b8e-bb16-9d5d0385bab5')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.automation-automationaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "automationAccount": { + "type": "Microsoft.Automation/automationAccounts", + "apiVersion": "2022-08-08", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "sku": { + "name": "[parameters('skuName')]" + }, + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.Keyvault', 'identity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), createObject('userAssignedIdentity', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/')))), null()), 'keyVaultProperties', createObject('keyName', parameters('customerManagedKey').keyName, 'keyvaultUri', reference('cMKKeyVault').vaultUri, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), if(equals(parameters('publicNetworkAccess'), 'Disabled'), false(), true()), if(not(empty(parameters('privateEndpoints'))), false(), null()))]", + "disableLocalAuth": "[parameters('disableLocalAuth')]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKKeyVault" + ] + }, + "automationAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Automation/automationAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "automationAccount" + ] + }, + "automationAccount_diagnosticSettings": { + "copy": { + "name": "automationAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Automation/automationAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "automationAccount" + ] + }, + "automationAccount_roleAssignments": { + "copy": { + "name": "automationAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Automation/automationAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Automation/automationAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "automationAccount" + ] + }, + "automationAccount_credentials": { + "copy": { + "name": "automationAccount_credentials", + "count": "[length(coalesce(parameters('credentials'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AutomationAccount-Credential-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "automationAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('credentials'), createArray())[copyIndex()].name]" + }, + "password": { + "value": "[coalesce(parameters('credentials'), createArray())[copyIndex()].password]" + }, + "userName": { + "value": "[coalesce(parameters('credentials'), createArray())[copyIndex()].userName]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('credentials'), createArray())[copyIndex()], 'description')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10206419659334193725" + }, + "name": "Automation Account Credential", + "description": "This module deploys Azure Automation Account Credential." + }, + "parameters": { + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Automation Account credential." + } + }, + "userName": { + "type": "string", + "metadata": { + "description": "Required. The user name associated to the credential." + } + }, + "password": { + "type": "securestring", + "metadata": { + "description": "Required. Password of the credential." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the credential." + } + } + }, + "resources": { + "automationAccount": { + "existing": true, + "type": "Microsoft.Automation/automationAccounts", + "apiVersion": "2022-08-08", + "name": "[parameters('automationAccountName')]" + }, + "credential": { + "type": "Microsoft.Automation/automationAccounts/credentials", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "properties": { + "password": "[parameters('password')]", + "userName": "[parameters('userName')]", + "description": "[coalesce(parameters('description'), '')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource Id of the credential associated to the automation account." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/credentials', parameters('automationAccountName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the credential associated to the automation account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed credential." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "automationAccount" + ] + }, + "automationAccount_modules": { + "copy": { + "name": "automationAccount_modules", + "count": "[length(parameters('modules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AutoAccount-Module-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('modules')[copyIndex()].name]" + }, + "automationAccountName": { + "value": "[parameters('name')]" + }, + "version": { + "value": "[parameters('modules')[copyIndex()].version]" + }, + "uri": { + "value": "[parameters('modules')[copyIndex()].uri]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('modules')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3828537230935003385" + }, + "name": "Automation Account Modules", + "description": "This module deploys an Azure Automation Account Module." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Automation Account module." + } + }, + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "uri": { + "type": "string", + "metadata": { + "description": "Required. Module package URI, e.g. https://www.powershellgallery.com/api/v2/package." + } + }, + "version": { + "type": "string", + "defaultValue": "latest", + "metadata": { + "description": "Optional. Module version or specify latest to get the latest version." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the Automation Account resource." + } + } + }, + "resources": { + "automationAccount": { + "existing": true, + "type": "Microsoft.Automation/automationAccounts", + "apiVersion": "2022-08-08", + "name": "[parameters('automationAccountName')]" + }, + "module": { + "type": "Microsoft.Automation/automationAccounts/modules", + "apiVersion": "2022-08-08", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "contentLink": { + "uri": "[if(not(equals(parameters('version'), 'latest')), format('{0}/{1}/{2}', parameters('uri'), parameters('name'), parameters('version')), format('{0}/{1}', parameters('uri'), parameters('name')))]", + "version": "[if(not(equals(parameters('version'), 'latest')), parameters('version'), null())]" + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed module." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed module." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/modules', parameters('automationAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed module." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('module', '2022-08-08', 'full').location]" + } + } + } + }, + "dependsOn": [ + "automationAccount" + ] + }, + "automationAccount_schedules": { + "copy": { + "name": "automationAccount_schedules", + "count": "[length(parameters('schedules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AutoAccount-Schedule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('schedules')[copyIndex()].name]" + }, + "automationAccountName": { + "value": "[parameters('name')]" + }, + "advancedSchedule": { + "value": "[tryGet(parameters('schedules')[copyIndex()], 'advancedSchedule')]" + }, + "description": { + "value": "[tryGet(parameters('schedules')[copyIndex()], 'description')]" + }, + "expiryTime": { + "value": "[tryGet(parameters('schedules')[copyIndex()], 'expiryTime')]" + }, + "frequency": { + "value": "[tryGet(parameters('schedules')[copyIndex()], 'frequency')]" + }, + "interval": { + "value": "[tryGet(parameters('schedules')[copyIndex()], 'interval')]" + }, + "startTime": { + "value": "[tryGet(parameters('schedules')[copyIndex()], 'startTime')]" + }, + "timeZone": { + "value": "[tryGet(parameters('schedules')[copyIndex()], 'timeZone')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "6875246782544956895" + }, + "name": "Automation Account Schedules", + "description": "This module deploys an Azure Automation Account Schedule." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Automation Account schedule." + } + }, + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "advancedSchedule": { + "type": "object", + "defaultValue": {}, + "metadata": { + "monthDays": "Days of the month that the job should execute on. Must be between 1 and 31.", + "monthlyOccurrences": "Occurrences of days within a month.", + "weekDays": "Days of the week that the job should execute on.", + "description": "Optional. The properties of the create Advanced Schedule." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the schedule." + } + }, + "expiryTime": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The end time of the schedule." + } + }, + "frequency": { + "type": "string", + "defaultValue": "OneTime", + "allowedValues": [ + "Day", + "Hour", + "Minute", + "Month", + "OneTime", + "Week" + ], + "metadata": { + "description": "Optional. The frequency of the schedule." + } + }, + "interval": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Anything." + } + }, + "startTime": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The start time of the schedule." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The time zone of the schedule." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Time used as a basis for e.g. the schedule start date." + } + } + }, + "resources": [ + { + "type": "Microsoft.Automation/automationAccounts/schedules", + "apiVersion": "2022-08-08", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "properties": { + "advancedSchedule": "[if(not(empty(parameters('advancedSchedule'))), parameters('advancedSchedule'), null())]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "expiryTime": "[if(not(empty(parameters('expiryTime'))), parameters('expiryTime'), null())]", + "frequency": "[if(not(empty(parameters('frequency'))), parameters('frequency'), 'OneTime')]", + "interval": "[if(not(equals(parameters('interval'), 0)), parameters('interval'), null())]", + "startTime": "[if(not(empty(parameters('startTime'))), parameters('startTime'), dateTimeAdd(parameters('baseTime'), 'PT15M'))]", + "timeZone": "[if(not(empty(parameters('timeZone'))), parameters('timeZone'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed schedule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed schedule." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/schedules', parameters('automationAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed schedule." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "automationAccount" + ] + }, + "automationAccount_runbooks": { + "copy": { + "name": "automationAccount_runbooks", + "count": "[length(parameters('runbooks'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AutoAccount-Runbook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('runbooks')[copyIndex()].name]" + }, + "automationAccountName": { + "value": "[parameters('name')]" + }, + "type": { + "value": "[parameters('runbooks')[copyIndex()].type]" + }, + "description": { + "value": "[tryGet(parameters('runbooks')[copyIndex()], 'description')]" + }, + "uri": { + "value": "[tryGet(parameters('runbooks')[copyIndex()], 'uri')]" + }, + "version": { + "value": "[tryGet(parameters('runbooks')[copyIndex()], 'version')]" + }, + "sasTokenValidityLength": { + "value": "[tryGet(parameters('runbooks')[copyIndex()], 'sasTokenValidityLength')]" + }, + "scriptStorageAccountResourceId": { + "value": "[tryGet(parameters('runbooks')[copyIndex()], 'scriptStorageAccountResourceId')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('runbooks')[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15686123148609089393" + }, + "name": "Automation Account Runbooks", + "description": "This module deploys an Azure Automation Account Runbook." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Automation Account runbook." + } + }, + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Graph", + "GraphPowerShell", + "GraphPowerShellWorkflow", + "PowerShell", + "PowerShell72", + "PowerShellWorkflow", + "Python2", + "Python3", + "Script" + ], + "metadata": { + "description": "Required. The type of the runbook." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the runbook." + } + }, + "uri": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The uri of the runbook content." + } + }, + "version": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The version of the runbook content." + } + }, + "scriptStorageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource Id of the runbook storage account." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Time used as a basis for e.g. the schedule start date." + } + }, + "sasTokenValidityLength": { + "type": "string", + "defaultValue": "PT8H", + "metadata": { + "description": "Optional. SAS token validity length. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the Automation Account resource." + } + } + }, + "variables": { + "accountSasProperties": { + "signedServices": "b", + "signedPermission": "r", + "signedExpiry": "[dateTimeAdd(parameters('baseTime'), parameters('sasTokenValidityLength'))]", + "signedResourceTypes": "o", + "signedProtocol": "https" + } + }, + "resources": { + "automationAccount": { + "existing": true, + "type": "Microsoft.Automation/automationAccounts", + "apiVersion": "2022-08-08", + "name": "[parameters('automationAccountName')]" + }, + "storageAccount": { + "condition": "[not(empty(parameters('scriptStorageAccountResourceId')))]", + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "subscriptionId": "[split(coalesce(parameters('scriptStorageAccountResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('scriptStorageAccountResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(parameters('scriptStorageAccountResourceId'), 'dummyVault'), '/'))]" + }, + "runbook": { + "type": "Microsoft.Automation/automationAccounts/runbooks", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "runbookType": "[parameters('type')]", + "description": "[parameters('description')]", + "publishContentLink": "[if(not(empty(parameters('uri'))), if(empty(parameters('uri')), null(), createObject('uri', if(not(empty(parameters('uri'))), if(empty(parameters('scriptStorageAccountResourceId')), parameters('uri'), format('{0}?{1}', parameters('uri'), listAccountSas(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('scriptStorageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('scriptStorageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('scriptStorageAccountResourceId'), 'dummyVault'), '/'))), '2021-04-01', variables('accountSasProperties')).accountSasToken)), null()), 'version', if(not(empty(parameters('version'))), parameters('version'), null()))), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed runbook." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed runbook." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/runbooks', parameters('automationAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed runbook." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('runbook', '2023-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "automationAccount" + ] + }, + "automationAccount_jobSchedules": { + "copy": { + "name": "automationAccount_jobSchedules", + "count": "[length(parameters('jobSchedules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AutoAccount-JobSchedule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "automationAccountName": { + "value": "[parameters('name')]" + }, + "runbookName": { + "value": "[parameters('jobSchedules')[copyIndex()].runbookName]" + }, + "scheduleName": { + "value": "[parameters('jobSchedules')[copyIndex()].scheduleName]" + }, + "parameters": { + "value": "[tryGet(parameters('jobSchedules')[copyIndex()], 'parameters')]" + }, + "runOn": { + "value": "[tryGet(parameters('jobSchedules')[copyIndex()], 'runOn')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "4203011213224324137" + }, + "name": "Automation Account Job Schedules", + "description": "This module deploys an Azure Automation Account Job Schedule." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[newGuid()]", + "metadata": { + "description": "Generated. Name of the Automation Account job schedule. Must be a GUID and is autogenerated. No need to provide this value." + } + }, + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "runbookName": { + "type": "string", + "metadata": { + "description": "Required. The runbook property associated with the entity." + } + }, + "scheduleName": { + "type": "string", + "metadata": { + "description": "Required. The schedule property associated with the entity." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. List of job properties." + } + }, + "runOn": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The hybrid worker group that the scheduled job should run on." + } + } + }, + "resources": [ + { + "type": "Microsoft.Automation/automationAccounts/jobSchedules", + "apiVersion": "2022-08-08", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "properties": { + "parameters": "[parameters('parameters')]", + "runbook": { + "name": "[parameters('runbookName')]" + }, + "runOn": "[if(not(empty(parameters('runOn'))), parameters('runOn'), null())]", + "schedule": { + "name": "[parameters('scheduleName')]" + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed job schedule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed job schedule." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/jobSchedules', parameters('automationAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed job schedule." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "automationAccount", + "automationAccount_runbooks", + "automationAccount_schedules" + ] + }, + "automationAccount_variables": { + "copy": { + "name": "automationAccount_variables", + "count": "[length(parameters('variables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AutoAccount-Variable-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "automationAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('variables')[copyIndex()].name]" + }, + "description": { + "value": "[tryGet(parameters('variables')[copyIndex()], 'description')]" + }, + "value": { + "value": "[parameters('variables')[copyIndex()].value]" + }, + "isEncrypted": { + "value": "[tryGet(parameters('variables')[copyIndex()], 'isEncrypted')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "16330558441628473023" + }, + "name": "Automation Account Variables", + "description": "This module deploys an Azure Automation Account Variable." + }, + "parameters": { + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the variable." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the variable. For security best practices, this value is always passed as a secure string as it could contain an encrypted value when the \"isEncrypted\" property is set to true." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the variable." + } + }, + "isEncrypted": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If the variable should be encrypted. For security reasons encryption of variables should be enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.Automation/automationAccounts/variables", + "apiVersion": "2022-08-08", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "isEncrypted": "[parameters('isEncrypted')]", + "value": "[parameters('value')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed variable." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed variable." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/variables', parameters('automationAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed variable." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "automationAccount" + ] + }, + "automationAccount_linkedService": { + "condition": "[not(empty(parameters('linkedWorkspaceResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AutoAccount-LinkedService', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[if(not(empty(parameters('linkedWorkspaceResourceId'))), split(if(not(empty(parameters('linkedWorkspaceResourceId'))), parameters('linkedWorkspaceResourceId'), '//'), '/')[2], subscription().subscriptionId)]", + "resourceGroup": "[if(not(empty(parameters('linkedWorkspaceResourceId'))), split(if(not(empty(parameters('linkedWorkspaceResourceId'))), parameters('linkedWorkspaceResourceId'), '////'), '/')[4], resourceGroup().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "automation" + }, + "logAnalyticsWorkspaceName": { + "value": "[last(split(parameters('linkedWorkspaceResourceId'), '/'))]" + }, + "resourceId": { + "value": "[resourceId('Microsoft.Automation/automationAccounts', parameters('name'))]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "11223130094132311066" + }, + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Required. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + } + }, + "writeAccessResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedService": { + "type": "Microsoft.OperationalInsights/workspaces/linkedServices", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resourceId": "[parameters('resourceId')]", + "writeAccessResourceId": "[if(empty(parameters('writeAccessResourceId')), null(), parameters('writeAccessResourceId'))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked service." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked service is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "automationAccount" + ] + }, + "automationAccount_solutions": { + "copy": { + "name": "automationAccount_solutions", + "count": "[length(coalesce(parameters('gallerySolutions'), createArray()))]" + }, + "condition": "[not(empty(parameters('linkedWorkspaceResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AutoAccount-Solution-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[if(not(empty(parameters('linkedWorkspaceResourceId'))), split(if(not(empty(parameters('linkedWorkspaceResourceId'))), parameters('linkedWorkspaceResourceId'), '//'), '/')[2], subscription().subscriptionId)]", + "resourceGroup": "[if(not(empty(parameters('linkedWorkspaceResourceId'))), split(if(not(empty(parameters('linkedWorkspaceResourceId'))), parameters('linkedWorkspaceResourceId'), '////'), '/')[4], resourceGroup().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[last(split(parameters('linkedWorkspaceResourceId'), '/'))]" + }, + "plan": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].plan]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "1867653058254938383" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.3.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2021-06-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "solution": { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", + "promotionCode": "", + "product": "[parameters('plan').product]", + "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the solution is deployed." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('solution', '2015-11-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "automationAccount_linkedService" + ] + }, + "automationAccount_softwareUpdateConfigurations": { + "copy": { + "name": "automationAccount_softwareUpdateConfigurations", + "count": "[length(parameters('softwareUpdateConfigurations'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AutoAccount-SwUpdateConfig-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('softwareUpdateConfigurations')[copyIndex()].name]" + }, + "automationAccountName": { + "value": "[parameters('name')]" + }, + "frequency": { + "value": "[parameters('softwareUpdateConfigurations')[copyIndex()].frequency]" + }, + "operatingSystem": { + "value": "[parameters('softwareUpdateConfigurations')[copyIndex()].operatingSystem]" + }, + "rebootSetting": { + "value": "[parameters('softwareUpdateConfigurations')[copyIndex()].rebootSetting]" + }, + "azureVirtualMachines": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'azureVirtualMachines')]" + }, + "excludeUpdates": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'excludeUpdates')]" + }, + "expiryTime": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'expiryTime')]" + }, + "expiryTimeOffsetMinutes": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'expiryTimeOffsetMinute')]" + }, + "includeUpdates": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'includeUpdates')]" + }, + "interval": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'interval')]" + }, + "isEnabled": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'isEnabled')]" + }, + "maintenanceWindow": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'maintenanceWindow')]" + }, + "monthDays": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'monthDays')]" + }, + "monthlyOccurrences": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'monthlyOccurrences')]" + }, + "nextRun": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'nextRun')]" + }, + "nextRunOffsetMinutes": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'nextRunOffsetMinutes')]" + }, + "nonAzureComputerNames": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'nonAzureComputerNames')]" + }, + "nonAzureQueries": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'nonAzureQueries')]" + }, + "postTaskParameters": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'postTaskParameters')]" + }, + "postTaskSource": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'postTaskSource')]" + }, + "preTaskParameters": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'preTaskParameters')]" + }, + "preTaskSource": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'preTaskSource')]" + }, + "scheduleDescription": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'scheduleDescription')]" + }, + "scopeByLocations": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'scopeByLocations')]" + }, + "scopeByResources": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'scopeByResources')]" + }, + "scopeByTags": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'scopeByTags')]" + }, + "scopeByTagsOperation": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'scopeByTagsOperation')]" + }, + "startTime": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'startTime')]" + }, + "timeZone": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'timeZone')]" + }, + "updateClassifications": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'updateClassifications')]" + }, + "weekDays": { + "value": "[tryGet(parameters('softwareUpdateConfigurations')[copyIndex()], 'weekDays')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "18142998771588913270" + }, + "name": "Automation Account Software Update Configurations", + "description": "This module deploys an Azure Automation Account Software Update Configuration." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Deployment schedule." + } + }, + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "operatingSystem": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. The operating system to be configured by the deployment schedule." + } + }, + "rebootSetting": { + "type": "string", + "allowedValues": [ + "IfRequired", + "Never", + "RebootOnly", + "Always" + ], + "metadata": { + "description": "Required. Reboot setting for the deployment schedule." + } + }, + "frequency": { + "type": "string", + "allowedValues": [ + "OneTime", + "Hour", + "Day", + "Week", + "Month" + ], + "metadata": { + "description": "Required. The frequency of the deployment schedule. When using 'Hour', 'Day', 'Week' or 'Month', an interval needs to be provided." + } + }, + "maintenanceWindow": { + "type": "string", + "defaultValue": "PT2H", + "metadata": { + "description": "Optional. Maximum time allowed for the deployment schedule to run. Duration needs to be specified using the format PT[n]H[n]M[n]S as per ISO8601." + } + }, + "updateClassifications": { + "type": "array", + "defaultValue": [ + "Critical", + "Security" + ], + "allowedValues": [ + "Critical", + "Security", + "UpdateRollup", + "FeaturePack", + "ServicePack", + "Definition", + "Tools", + "Updates", + "Other" + ], + "metadata": { + "description": "Optional. Update classification included in the deployment schedule." + } + }, + "excludeUpdates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. KB numbers or Linux packages excluded in the deployment schedule." + } + }, + "includeUpdates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. KB numbers or Linux packages included in the deployment schedule." + } + }, + "scopeByResources": { + "type": "array", + "defaultValue": [ + "[subscription().id]" + ], + "metadata": { + "description": "Optional. Specify the resources to scope the deployment schedule to." + } + }, + "scopeByTags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Specify tags to which to scope the deployment schedule to." + } + }, + "scopeByTagsOperation": { + "type": "string", + "defaultValue": "All", + "allowedValues": [ + "All", + "Any" + ], + "metadata": { + "description": "Optional. Enables the scopeByTags to require All (Tag A and Tag B) or Any (Tag A or Tag B)." + } + }, + "scopeByLocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specify locations to which to scope the deployment schedule to." + } + }, + "preTaskParameters": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Parameters provided to the task running before the deployment schedule." + } + }, + "preTaskSource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source of the task running before the deployment schedule." + } + }, + "postTaskParameters": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Parameters provided to the task running after the deployment schedule." + } + }, + "postTaskSource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source of the task running after the deployment schedule." + } + }, + "interval": { + "type": "int", + "defaultValue": 1, + "maxValue": 100, + "metadata": { + "description": "Optional. The interval of the frequency for the deployment schedule. 1 Hour is every hour, 2 Day is every second day, etc." + } + }, + "isEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables the deployment schedule." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "UTC", + "metadata": { + "description": "Optional. Time zone for the deployment schedule. IANA ID or a Windows Time Zone ID." + } + }, + "nonAzureQueries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of functions from a Log Analytics workspace, used to scope the deployment schedule." + } + }, + "azureVirtualMachines": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of azure resource IDs for azure virtual machines in scope for the deployment schedule." + } + }, + "nonAzureComputerNames": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of names of non-azure machines in scope for the deployment schedule." + } + }, + "weekDays": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "allowedValues": [ + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday" + ], + "metadata": { + "description": "Optional. Required when used with frequency 'Week'. Specified the day of the week to run the deployment schedule." + } + }, + "monthDays": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "allowedValues": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31 + ], + "metadata": { + "description": "Optional. Can be used with frequency 'Month'. Provides the specific days of the month to run the deployment schedule." + } + }, + "monthlyOccurrences": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Can be used with frequency 'Month'. Provides the pattern/cadence for running the deployment schedule in a month. Takes objects formed like this {occurance(int),day(string)}. Day is the name of the day to run the deployment schedule, the occurance specifies which occurance of that day to run the deployment schedule." + } + }, + "startTime": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The start time of the deployment schedule in ISO 8601 format. To specify a specific time use YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00. For schedules where we want to start the deployment as soon as possible, specify the time segment only in 24 hour format, HH:MM, 22:00." + } + }, + "expiryTime": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The end time of the deployment schedule in ISO 8601 format. YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00." + } + }, + "expiryTimeOffsetMinutes": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The expiry time's offset in minutes." + } + }, + "nextRun": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The next time the deployment schedule runs in ISO 8601 format. YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00." + } + }, + "nextRunOffsetMinutes": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The next run's offset in minutes." + } + }, + "scheduleDescription": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The schedules description." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Do not touch. Is used to provide the base time for time comparison for startTime. If startTime is specified in HH:MM format, baseTime is used to check if the provided startTime has passed, adding one day before setting the deployment schedule." + } + } + }, + "variables": { + "updateClassificationsVar": "[replace(replace(replace(replace(string(parameters('updateClassifications')), ',', ', '), '[', ''), ']', ''), '\"', '')]" + }, + "resources": { + "automationAccount": { + "existing": true, + "type": "Microsoft.Automation/automationAccounts", + "apiVersion": "2022-08-08", + "name": "[parameters('automationAccountName')]" + }, + "softwareUpdateConfiguration": { + "type": "Microsoft.Automation/automationAccounts/softwareUpdateConfigurations", + "apiVersion": "2019-06-01", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "properties": { + "updateConfiguration": { + "operatingSystem": "[parameters('operatingSystem')]", + "duration": "[parameters('maintenanceWindow')]", + "linux": "[if(equals(parameters('operatingSystem'), 'Linux'), createObject('excludedPackageNameMasks', parameters('excludeUpdates'), 'includedPackageNameMasks', parameters('includeUpdates'), 'includedPackageClassifications', variables('updateClassificationsVar'), 'rebootSetting', parameters('rebootSetting')), null())]", + "windows": "[if(equals(parameters('operatingSystem'), 'Windows'), createObject('excludedKbNumbers', parameters('excludeUpdates'), 'includedKbNumbers', parameters('includeUpdates'), 'includedUpdateClassifications', variables('updateClassificationsVar'), 'rebootSetting', parameters('rebootSetting')), null())]", + "targets": { + "azureQueries": [ + { + "scope": "[parameters('scopeByResources')]", + "tagSettings": { + "tags": "[parameters('scopeByTags')]", + "filterOperator": "[parameters('scopeByTagsOperation')]" + }, + "locations": "[parameters('scopeByLocations')]" + } + ], + "nonAzureQueries": "[parameters('nonAzureQueries')]" + }, + "azureVirtualMachines": "[parameters('azureVirtualMachines')]", + "nonAzureComputerNames": "[parameters('nonAzureComputerNames')]" + }, + "tasks": { + "preTask": { + "parameters": "[parameters('preTaskParameters')]", + "source": "[parameters('preTaskSource')]" + }, + "postTask": { + "parameters": "[parameters('postTaskParameters')]", + "source": "[parameters('postTaskSource')]" + } + }, + "scheduleInfo": { + "interval": "[parameters('interval')]", + "frequency": "[parameters('frequency')]", + "isEnabled": "[parameters('isEnabled')]", + "timeZone": "[parameters('timeZone')]", + "advancedSchedule": { + "weekDays": "[parameters('weekDays')]", + "monthDays": "[parameters('monthDays')]", + "monthlyOccurrences": "[parameters('monthlyOccurrences')]" + }, + "startTime": "[if(empty(parameters('startTime')), dateTimeAdd(parameters('baseTime'), 'PT10M'), parameters('startTime'))]", + "expiryTime": "[parameters('expiryTime')]", + "expiryTimeOffsetMinutes": "[parameters('expiryTimeOffsetMinutes')]", + "nextRun": "[parameters('nextRun')]", + "nextRunOffsetMinutes": "[parameters('nextRunOffsetMinutes')]", + "description": "[parameters('scheduleDescription')]" + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed softwareUpdateConfiguration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed softwareUpdateConfiguration." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/softwareUpdateConfigurations', parameters('automationAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed softwareUpdateConfiguration." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "automationAccount", + "automationAccount_solutions" + ] + }, + "automationAccount_privateEndpoints": { + "copy": { + "name": "automationAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-automationAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Automation/automationAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Automation/automationAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Automation/automationAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Automation/automationAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Automation/automationAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "1277254088602407590" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + } + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5805178546717255803" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" + }, + "customDnsConfig": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceIds": { + "type": "array", + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + }, + "value": "[reference('privateEndpoint').networkInterfaces]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(and(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds', 0), ''), if(and(not(empty(reference('privateEndpoint').privateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds', 0), ''), ''))]" + } + } + } + }, + "dependsOn": [ + "automationAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed automation account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed automation account." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed automation account." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('automationAccount', '2022-08-08', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('automationAccount', '2022-08-08', 'full').location]" + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the automation account." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", + "input": { + "name": "[reference(format('automationAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('automationAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('automationAccount_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('automationAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('automationAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/automation/automation-account/module/README.md b/avm/1.1.0/res/automation/automation-account/module/README.md new file mode 100644 index 000000000..764da5c88 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/module/README.md @@ -0,0 +1,91 @@ +# Automation Account Modules `[Microsoft.Automation/automationAccounts/modules]` + +This module deploys an Azure Automation Account Module. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Automation/automationAccounts/modules` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/modules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Automation Account module. | +| [`uri`](#parameter-uri) | string | Module package URI, e.g. https://www.powershellgallery.com/api/v2/package. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`automationAccountName`](#parameter-automationaccountname) | string | The name of the parent Automation Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`tags`](#parameter-tags) | object | Tags of the Automation Account resource. | +| [`version`](#parameter-version) | string | Module version or specify latest to get the latest version. | + +### Parameter: `name` + +Name of the Automation Account module. + +- Required: Yes +- Type: string + +### Parameter: `uri` + +Module package URI, e.g. https://www.powershellgallery.com/api/v2/package. + +- Required: Yes +- Type: string + +### Parameter: `automationAccountName` + +The name of the parent Automation Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `tags` + +Tags of the Automation Account resource. + +- Required: No +- Type: object + +### Parameter: `version` + +Module version or specify latest to get the latest version. + +- Required: No +- Type: string +- Default: `'latest'` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed module. | +| `resourceGroupName` | string | The resource group of the deployed module. | +| `resourceId` | string | The resource ID of the deployed module. | diff --git a/avm/1.1.0/res/automation/automation-account/module/main.bicep b/avm/1.1.0/res/automation/automation-account/module/main.bicep new file mode 100644 index 000000000..16907803c --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/module/main.bicep @@ -0,0 +1,49 @@ +metadata name = 'Automation Account Modules' +metadata description = 'This module deploys an Azure Automation Account Module.' + +@description('Required. Name of the Automation Account module.') +param name string + +@description('Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment.') +param automationAccountName string + +@description('Required. Module package URI, e.g. https://www.powershellgallery.com/api/v2/package.') +param uri string + +@description('Optional. Module version or specify latest to get the latest version.') +param version string = 'latest' + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the Automation Account resource.') +param tags object? + +resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' existing = { + name: automationAccountName +} + +resource module 'Microsoft.Automation/automationAccounts/modules@2022-08-08' = { + name: name + parent: automationAccount + location: location + tags: tags + properties: { + contentLink: { + uri: version != 'latest' ? '${uri}/${name}/${version}' : '${uri}/${name}' + version: version != 'latest' ? version : null + } + } +} + +@description('The name of the deployed module.') +output name string = module.name + +@description('The resource ID of the deployed module.') +output resourceId string = module.id + +@description('The resource group of the deployed module.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = module.location diff --git a/avm/1.1.0/res/automation/automation-account/module/main.json b/avm/1.1.0/res/automation/automation-account/module/main.json new file mode 100644 index 000000000..1e22a6eab --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/module/main.json @@ -0,0 +1,106 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3828537230935003385" + }, + "name": "Automation Account Modules", + "description": "This module deploys an Azure Automation Account Module." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Automation Account module." + } + }, + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "uri": { + "type": "string", + "metadata": { + "description": "Required. Module package URI, e.g. https://www.powershellgallery.com/api/v2/package." + } + }, + "version": { + "type": "string", + "defaultValue": "latest", + "metadata": { + "description": "Optional. Module version or specify latest to get the latest version." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the Automation Account resource." + } + } + }, + "resources": { + "automationAccount": { + "existing": true, + "type": "Microsoft.Automation/automationAccounts", + "apiVersion": "2022-08-08", + "name": "[parameters('automationAccountName')]" + }, + "module": { + "type": "Microsoft.Automation/automationAccounts/modules", + "apiVersion": "2022-08-08", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "contentLink": { + "uri": "[if(not(equals(parameters('version'), 'latest')), format('{0}/{1}/{2}', parameters('uri'), parameters('name'), parameters('version')), format('{0}/{1}', parameters('uri'), parameters('name')))]", + "version": "[if(not(equals(parameters('version'), 'latest')), parameters('version'), null())]" + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed module." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed module." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/modules', parameters('automationAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed module." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('module', '2022-08-08', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/automation/automation-account/modules/linked-service.bicep b/avm/1.1.0/res/automation/automation-account/modules/linked-service.bicep new file mode 100644 index 000000000..a21d0d10d --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/modules/linked-service.bicep @@ -0,0 +1,40 @@ +metadata name = 'Log Analytics Workspace Linked Services' +metadata description = 'This module deploys a Log Analytics Workspace Linked Service.' + +@description('Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment.') +param logAnalyticsWorkspaceName string + +@description('Required. Name of the link.') +param name string + +@description('Required. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access.') +param resourceId string = '' + +@description('Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access.') +param writeAccessResourceId string = '' + +@description('Optional. Tags to configure in the resource.') +param tags object? + +resource workspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = { + name: logAnalyticsWorkspaceName +} + +resource linkedService 'Microsoft.OperationalInsights/workspaces/linkedServices@2020-08-01' = { + name: name + parent: workspace + tags: tags + properties: { + resourceId: resourceId + writeAccessResourceId: empty(writeAccessResourceId) ? null : writeAccessResourceId + } +} + +@description('The name of the deployed linked service.') +output name string = linkedService.name + +@description('The resource ID of the deployed linked service.') +output resourceId string = linkedService.id + +@description('The resource group where the linked service is deployed.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/automation/automation-account/runbook/README.md b/avm/1.1.0/res/automation/automation-account/runbook/README.md new file mode 100644 index 000000000..c0a611954 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/runbook/README.md @@ -0,0 +1,154 @@ +# Automation Account Runbooks `[Microsoft.Automation/automationAccounts/runbooks]` + +This module deploys an Azure Automation Account Runbook. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Automation/automationAccounts/runbooks` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2023-11-01/automationAccounts/runbooks) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Automation Account runbook. | +| [`type`](#parameter-type) | string | The type of the runbook. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`automationAccountName`](#parameter-automationaccountname) | string | The name of the parent Automation Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | The description of the runbook. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`sasTokenValidityLength`](#parameter-sastokenvaliditylength) | string | SAS token validity length. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours. | +| [`scriptStorageAccountResourceId`](#parameter-scriptstorageaccountresourceid) | string | Resource Id of the runbook storage account. | +| [`tags`](#parameter-tags) | object | Tags of the Automation Account resource. | +| [`uri`](#parameter-uri) | string | The uri of the runbook content. | +| [`version`](#parameter-version) | string | The version of the runbook content. | + +**Generated parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`baseTime`](#parameter-basetime) | string | Time used as a basis for e.g. the schedule start date. | + +### Parameter: `name` + +Name of the Automation Account runbook. + +- Required: Yes +- Type: string + +### Parameter: `type` + +The type of the runbook. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Graph' + 'GraphPowerShell' + 'GraphPowerShellWorkflow' + 'PowerShell' + 'PowerShell72' + 'PowerShellWorkflow' + 'Python2' + 'Python3' + 'Script' + ] + ``` + +### Parameter: `automationAccountName` + +The name of the parent Automation Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `description` + +The description of the runbook. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `sasTokenValidityLength` + +SAS token validity length. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours. + +- Required: No +- Type: string +- Default: `'PT8H'` + +### Parameter: `scriptStorageAccountResourceId` + +Resource Id of the runbook storage account. + +- Required: No +- Type: string + +### Parameter: `tags` + +Tags of the Automation Account resource. + +- Required: No +- Type: object + +### Parameter: `uri` + +The uri of the runbook content. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `version` + +The version of the runbook content. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `baseTime` + +Time used as a basis for e.g. the schedule start date. + +- Required: No +- Type: string +- Default: `[utcNow('u')]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed runbook. | +| `resourceGroupName` | string | The resource group of the deployed runbook. | +| `resourceId` | string | The resource ID of the deployed runbook. | diff --git a/avm/1.1.0/res/automation/automation-account/runbook/main.bicep b/avm/1.1.0/res/automation/automation-account/runbook/main.bicep new file mode 100644 index 000000000..485ef7982 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/runbook/main.bicep @@ -0,0 +1,101 @@ +metadata name = 'Automation Account Runbooks' +metadata description = 'This module deploys an Azure Automation Account Runbook.' + +@sys.description('Required. Name of the Automation Account runbook.') +param name string + +@sys.description('Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment.') +param automationAccountName string + +@allowed([ + 'Graph' + 'GraphPowerShell' + 'GraphPowerShellWorkflow' + 'PowerShell' + 'PowerShell72' + 'PowerShellWorkflow' + 'Python2' + 'Python3' + 'Script' +]) +@sys.description('Required. The type of the runbook.') +param type string + +@sys.description('Optional. The description of the runbook.') +param description string = '' + +@sys.description('Optional. The uri of the runbook content.') +param uri string = '' + +@sys.description('Optional. The version of the runbook content.') +param version string = '' + +@sys.description('Optional. Resource Id of the runbook storage account.') +param scriptStorageAccountResourceId string? + +@sys.description('Generated. Time used as a basis for e.g. the schedule start date.') +param baseTime string = utcNow('u') + +@sys.description('Optional. SAS token validity length. Usage: \'PT8H\' - valid for 8 hours; \'P5D\' - valid for 5 days; \'P1Y\' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours.') +param sasTokenValidityLength string = 'PT8H' + +@sys.description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@sys.description('Optional. Tags of the Automation Account resource.') +param tags object? + +var accountSasProperties = { + signedServices: 'b' + signedPermission: 'r' + signedExpiry: dateTimeAdd(baseTime, sasTokenValidityLength) + signedResourceTypes: 'o' + signedProtocol: 'https' +} + +resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' existing = { + name: automationAccountName +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' existing = if (!empty(scriptStorageAccountResourceId)) { + name: last(split((scriptStorageAccountResourceId ?? 'dummyVault'), '/')) + scope: resourceGroup( + split((scriptStorageAccountResourceId ?? '//'), '/')[2], + split((scriptStorageAccountResourceId ?? '////'), '/')[4] + ) +} + +var publishContentLink = empty(uri) + ? null + : { + uri: !empty(uri) + ? (empty(scriptStorageAccountResourceId) + ? uri + : '${uri}?${storageAccount.listAccountSas('2021-04-01', accountSasProperties).accountSasToken}') + : null + version: !empty(version) ? version : null + } + +resource runbook 'Microsoft.Automation/automationAccounts/runbooks@2023-11-01' = { + name: name + parent: automationAccount + location: location + tags: tags + properties: { + runbookType: type + description: description + publishContentLink: !empty(uri) ? publishContentLink : null + } +} + +@sys.description('The name of the deployed runbook.') +output name string = runbook.name + +@sys.description('The resource ID of the deployed runbook.') +output resourceId string = runbook.id + +@sys.description('The resource group of the deployed runbook.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The location the resource was deployed into.') +output location string = runbook.location diff --git a/avm/1.1.0/res/automation/automation-account/runbook/main.json b/avm/1.1.0/res/automation/automation-account/runbook/main.json new file mode 100644 index 000000000..60bd89d98 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/runbook/main.json @@ -0,0 +1,169 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15686123148609089393" + }, + "name": "Automation Account Runbooks", + "description": "This module deploys an Azure Automation Account Runbook." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Automation Account runbook." + } + }, + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Graph", + "GraphPowerShell", + "GraphPowerShellWorkflow", + "PowerShell", + "PowerShell72", + "PowerShellWorkflow", + "Python2", + "Python3", + "Script" + ], + "metadata": { + "description": "Required. The type of the runbook." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the runbook." + } + }, + "uri": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The uri of the runbook content." + } + }, + "version": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The version of the runbook content." + } + }, + "scriptStorageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource Id of the runbook storage account." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Time used as a basis for e.g. the schedule start date." + } + }, + "sasTokenValidityLength": { + "type": "string", + "defaultValue": "PT8H", + "metadata": { + "description": "Optional. SAS token validity length. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the Automation Account resource." + } + } + }, + "variables": { + "accountSasProperties": { + "signedServices": "b", + "signedPermission": "r", + "signedExpiry": "[dateTimeAdd(parameters('baseTime'), parameters('sasTokenValidityLength'))]", + "signedResourceTypes": "o", + "signedProtocol": "https" + } + }, + "resources": { + "automationAccount": { + "existing": true, + "type": "Microsoft.Automation/automationAccounts", + "apiVersion": "2022-08-08", + "name": "[parameters('automationAccountName')]" + }, + "storageAccount": { + "condition": "[not(empty(parameters('scriptStorageAccountResourceId')))]", + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "subscriptionId": "[split(coalesce(parameters('scriptStorageAccountResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('scriptStorageAccountResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(parameters('scriptStorageAccountResourceId'), 'dummyVault'), '/'))]" + }, + "runbook": { + "type": "Microsoft.Automation/automationAccounts/runbooks", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "runbookType": "[parameters('type')]", + "description": "[parameters('description')]", + "publishContentLink": "[if(not(empty(parameters('uri'))), if(empty(parameters('uri')), null(), createObject('uri', if(not(empty(parameters('uri'))), if(empty(parameters('scriptStorageAccountResourceId')), parameters('uri'), format('{0}?{1}', parameters('uri'), listAccountSas(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('scriptStorageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('scriptStorageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('scriptStorageAccountResourceId'), 'dummyVault'), '/'))), '2021-04-01', variables('accountSasProperties')).accountSasToken)), null()), 'version', if(not(empty(parameters('version'))), parameters('version'), null()))), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed runbook." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed runbook." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/runbooks', parameters('automationAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed runbook." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('runbook', '2023-11-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/automation/automation-account/schedule/README.md b/avm/1.1.0/res/automation/automation-account/schedule/README.md new file mode 100644 index 000000000..f849132a0 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/schedule/README.md @@ -0,0 +1,144 @@ +# Automation Account Schedules `[Microsoft.Automation/automationAccounts/schedules]` + +This module deploys an Azure Automation Account Schedule. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Automation/automationAccounts/schedules` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/schedules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Automation Account schedule. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`automationAccountName`](#parameter-automationaccountname) | string | The name of the parent Automation Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`advancedSchedule`](#parameter-advancedschedule) | object | The properties of the create Advanced Schedule. | +| [`description`](#parameter-description) | string | The description of the schedule. | +| [`expiryTime`](#parameter-expirytime) | string | The end time of the schedule. | +| [`frequency`](#parameter-frequency) | string | The frequency of the schedule. | +| [`interval`](#parameter-interval) | int | Anything. | +| [`startTime`](#parameter-starttime) | string | The start time of the schedule. | +| [`timeZone`](#parameter-timezone) | string | The time zone of the schedule. | + +**Generated parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`baseTime`](#parameter-basetime) | string | Time used as a basis for e.g. the schedule start date. | + +### Parameter: `name` + +Name of the Automation Account schedule. + +- Required: Yes +- Type: string + +### Parameter: `automationAccountName` + +The name of the parent Automation Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `advancedSchedule` + +The properties of the create Advanced Schedule. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `description` + +The description of the schedule. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `expiryTime` + +The end time of the schedule. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `frequency` + +The frequency of the schedule. + +- Required: No +- Type: string +- Default: `'OneTime'` +- Allowed: + ```Bicep + [ + 'Day' + 'Hour' + 'Minute' + 'Month' + 'OneTime' + 'Week' + ] + ``` + +### Parameter: `interval` + +Anything. + +- Required: No +- Type: int +- Default: `0` + +### Parameter: `startTime` + +The start time of the schedule. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `timeZone` + +The time zone of the schedule. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `baseTime` + +Time used as a basis for e.g. the schedule start date. + +- Required: No +- Type: string +- Default: `[utcNow('u')]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed schedule. | +| `resourceGroupName` | string | The resource group of the deployed schedule. | +| `resourceId` | string | The resource ID of the deployed schedule. | diff --git a/avm/1.1.0/res/automation/automation-account/schedule/main.bicep b/avm/1.1.0/res/automation/automation-account/schedule/main.bicep new file mode 100644 index 000000000..64cc62ccc --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/schedule/main.bicep @@ -0,0 +1,72 @@ +metadata name = 'Automation Account Schedules' +metadata description = 'This module deploys an Azure Automation Account Schedule.' + +@sys.description('Required. Name of the Automation Account schedule.') +param name string + +@sys.description('Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment.') +param automationAccountName string + +@sys.description('Optional. The properties of the create Advanced Schedule.') +@metadata({ + monthDays: 'Days of the month that the job should execute on. Must be between 1 and 31.' + monthlyOccurrences: 'Occurrences of days within a month.' + weekDays: 'Days of the week that the job should execute on.' +}) +param advancedSchedule object = {} + +@sys.description('Optional. The description of the schedule.') +param description string = '' + +@sys.description('Optional. The end time of the schedule.') +param expiryTime string = '' + +@allowed([ + 'Day' + 'Hour' + 'Minute' + 'Month' + 'OneTime' + 'Week' +]) +@sys.description('Optional. The frequency of the schedule.') +param frequency string = 'OneTime' + +@sys.description('Optional. Anything.') +param interval int = 0 + +@sys.description('Optional. The start time of the schedule.') +param startTime string = '' + +@sys.description('Optional. The time zone of the schedule.') +param timeZone string = '' + +@sys.description('Generated. Time used as a basis for e.g. the schedule start date.') +param baseTime string = utcNow('u') + +resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' existing = { + name: automationAccountName +} + +resource schedule 'Microsoft.Automation/automationAccounts/schedules@2022-08-08' = { + name: name + parent: automationAccount + properties: { + advancedSchedule: !empty(advancedSchedule) ? advancedSchedule : null + description: !empty(description) ? description : null + expiryTime: !empty(expiryTime) ? expiryTime : null + frequency: !empty(frequency) ? frequency : 'OneTime' + interval: (interval != 0) ? interval : null + startTime: !empty(startTime) ? startTime : dateTimeAdd(baseTime, 'PT15M') + timeZone: !empty(timeZone) ? timeZone : null + } +} + +@sys.description('The name of the deployed schedule.') +output name string = schedule.name + +@sys.description('The resource ID of the deployed schedule.') +output resourceId string = schedule.id + +@sys.description('The resource group of the deployed schedule.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/automation/automation-account/schedule/main.json b/avm/1.1.0/res/automation/automation-account/schedule/main.json new file mode 100644 index 000000000..6673a1a20 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/schedule/main.json @@ -0,0 +1,133 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "6875246782544956895" + }, + "name": "Automation Account Schedules", + "description": "This module deploys an Azure Automation Account Schedule." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Automation Account schedule." + } + }, + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "advancedSchedule": { + "type": "object", + "defaultValue": {}, + "metadata": { + "monthDays": "Days of the month that the job should execute on. Must be between 1 and 31.", + "monthlyOccurrences": "Occurrences of days within a month.", + "weekDays": "Days of the week that the job should execute on.", + "description": "Optional. The properties of the create Advanced Schedule." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the schedule." + } + }, + "expiryTime": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The end time of the schedule." + } + }, + "frequency": { + "type": "string", + "defaultValue": "OneTime", + "allowedValues": [ + "Day", + "Hour", + "Minute", + "Month", + "OneTime", + "Week" + ], + "metadata": { + "description": "Optional. The frequency of the schedule." + } + }, + "interval": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Anything." + } + }, + "startTime": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The start time of the schedule." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The time zone of the schedule." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Time used as a basis for e.g. the schedule start date." + } + } + }, + "resources": [ + { + "type": "Microsoft.Automation/automationAccounts/schedules", + "apiVersion": "2022-08-08", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "properties": { + "advancedSchedule": "[if(not(empty(parameters('advancedSchedule'))), parameters('advancedSchedule'), null())]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "expiryTime": "[if(not(empty(parameters('expiryTime'))), parameters('expiryTime'), null())]", + "frequency": "[if(not(empty(parameters('frequency'))), parameters('frequency'), 'OneTime')]", + "interval": "[if(not(equals(parameters('interval'), 0)), parameters('interval'), null())]", + "startTime": "[if(not(empty(parameters('startTime'))), parameters('startTime'), dateTimeAdd(parameters('baseTime'), 'PT15M'))]", + "timeZone": "[if(not(empty(parameters('timeZone'))), parameters('timeZone'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed schedule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed schedule." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/schedules', parameters('automationAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed schedule." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/automation/automation-account/software-update-configuration/README.md b/avm/1.1.0/res/automation/automation-account/software-update-configuration/README.md new file mode 100644 index 000000000..ac288c5f9 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/software-update-configuration/README.md @@ -0,0 +1,459 @@ +# Automation Account Software Update Configurations `[Microsoft.Automation/automationAccounts/softwareUpdateConfigurations]` + +This module deploys an Azure Automation Account Software Update Configuration. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Automation/automationAccounts/softwareUpdateConfigurations` | [2019-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2019-06-01/automationAccounts/softwareUpdateConfigurations) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`frequency`](#parameter-frequency) | string | The frequency of the deployment schedule. When using 'Hour', 'Day', 'Week' or 'Month', an interval needs to be provided. | +| [`name`](#parameter-name) | string | The name of the Deployment schedule. | +| [`operatingSystem`](#parameter-operatingsystem) | string | The operating system to be configured by the deployment schedule. | +| [`rebootSetting`](#parameter-rebootsetting) | string | Reboot setting for the deployment schedule. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`automationAccountName`](#parameter-automationaccountname) | string | The name of the parent Automation Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`azureVirtualMachines`](#parameter-azurevirtualmachines) | array | List of azure resource IDs for azure virtual machines in scope for the deployment schedule. | +| [`excludeUpdates`](#parameter-excludeupdates) | array | KB numbers or Linux packages excluded in the deployment schedule. | +| [`expiryTime`](#parameter-expirytime) | string | The end time of the deployment schedule in ISO 8601 format. YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00. | +| [`expiryTimeOffsetMinutes`](#parameter-expirytimeoffsetminutes) | int | The expiry time's offset in minutes. | +| [`includeUpdates`](#parameter-includeupdates) | array | KB numbers or Linux packages included in the deployment schedule. | +| [`interval`](#parameter-interval) | int | The interval of the frequency for the deployment schedule. 1 Hour is every hour, 2 Day is every second day, etc. | +| [`isEnabled`](#parameter-isenabled) | bool | Enables the deployment schedule. | +| [`maintenanceWindow`](#parameter-maintenancewindow) | string | Maximum time allowed for the deployment schedule to run. Duration needs to be specified using the format PT[n]H[n]M[n]S as per ISO8601. | +| [`monthDays`](#parameter-monthdays) | array | Can be used with frequency 'Month'. Provides the specific days of the month to run the deployment schedule. | +| [`monthlyOccurrences`](#parameter-monthlyoccurrences) | array | Can be used with frequency 'Month'. Provides the pattern/cadence for running the deployment schedule in a month. Takes objects formed like this {occurance(int),day(string)}. Day is the name of the day to run the deployment schedule, the occurance specifies which occurance of that day to run the deployment schedule. | +| [`nextRun`](#parameter-nextrun) | string | The next time the deployment schedule runs in ISO 8601 format. YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00. | +| [`nextRunOffsetMinutes`](#parameter-nextrunoffsetminutes) | int | The next run's offset in minutes. | +| [`nonAzureComputerNames`](#parameter-nonazurecomputernames) | array | List of names of non-azure machines in scope for the deployment schedule. | +| [`nonAzureQueries`](#parameter-nonazurequeries) | array | Array of functions from a Log Analytics workspace, used to scope the deployment schedule. | +| [`postTaskParameters`](#parameter-posttaskparameters) | object | Parameters provided to the task running after the deployment schedule. | +| [`postTaskSource`](#parameter-posttasksource) | string | The source of the task running after the deployment schedule. | +| [`preTaskParameters`](#parameter-pretaskparameters) | object | Parameters provided to the task running before the deployment schedule. | +| [`preTaskSource`](#parameter-pretasksource) | string | The source of the task running before the deployment schedule. | +| [`scheduleDescription`](#parameter-scheduledescription) | string | The schedules description. | +| [`scopeByLocations`](#parameter-scopebylocations) | array | Specify locations to which to scope the deployment schedule to. | +| [`scopeByResources`](#parameter-scopebyresources) | array | Specify the resources to scope the deployment schedule to. | +| [`scopeByTags`](#parameter-scopebytags) | object | Specify tags to which to scope the deployment schedule to. | +| [`scopeByTagsOperation`](#parameter-scopebytagsoperation) | string | Enables the scopeByTags to require All (Tag A and Tag B) or Any (Tag A or Tag B). | +| [`startTime`](#parameter-starttime) | string | The start time of the deployment schedule in ISO 8601 format. To specify a specific time use YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00. For schedules where we want to start the deployment as soon as possible, specify the time segment only in 24 hour format, HH:MM, 22:00. | +| [`timeZone`](#parameter-timezone) | string | Time zone for the deployment schedule. IANA ID or a Windows Time Zone ID. | +| [`updateClassifications`](#parameter-updateclassifications) | array | Update classification included in the deployment schedule. | +| [`weekDays`](#parameter-weekdays) | array | Required when used with frequency 'Week'. Specified the day of the week to run the deployment schedule. | + +**Generated parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`baseTime`](#parameter-basetime) | string | Do not touch. Is used to provide the base time for time comparison for startTime. If startTime is specified in HH:MM format, baseTime is used to check if the provided startTime has passed, adding one day before setting the deployment schedule. | + +### Parameter: `frequency` + +The frequency of the deployment schedule. When using 'Hour', 'Day', 'Week' or 'Month', an interval needs to be provided. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Day' + 'Hour' + 'Month' + 'OneTime' + 'Week' + ] + ``` + +### Parameter: `name` + +The name of the Deployment schedule. + +- Required: Yes +- Type: string + +### Parameter: `operatingSystem` + +The operating system to be configured by the deployment schedule. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `rebootSetting` + +Reboot setting for the deployment schedule. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Always' + 'IfRequired' + 'Never' + 'RebootOnly' + ] + ``` + +### Parameter: `automationAccountName` + +The name of the parent Automation Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `azureVirtualMachines` + +List of azure resource IDs for azure virtual machines in scope for the deployment schedule. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `excludeUpdates` + +KB numbers or Linux packages excluded in the deployment schedule. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `expiryTime` + +The end time of the deployment schedule in ISO 8601 format. YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `expiryTimeOffsetMinutes` + +The expiry time's offset in minutes. + +- Required: No +- Type: int +- Default: `0` + +### Parameter: `includeUpdates` + +KB numbers or Linux packages included in the deployment schedule. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `interval` + +The interval of the frequency for the deployment schedule. 1 Hour is every hour, 2 Day is every second day, etc. + +- Required: No +- Type: int +- Default: `1` +- MaxValue: 100 + +### Parameter: `isEnabled` + +Enables the deployment schedule. + +- Required: No +- Type: bool +- Default: `True` +- MaxValue: 100 + +### Parameter: `maintenanceWindow` + +Maximum time allowed for the deployment schedule to run. Duration needs to be specified using the format PT[n]H[n]M[n]S as per ISO8601. + +- Required: No +- Type: string +- Default: `'PT2H'` +- MaxValue: 100 + +### Parameter: `monthDays` + +Can be used with frequency 'Month'. Provides the specific days of the month to run the deployment schedule. + +- Required: No +- Type: array +- Allowed: + ```Bicep + [ + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + ] + ``` +- MaxValue: 100 + +### Parameter: `monthlyOccurrences` + +Can be used with frequency 'Month'. Provides the pattern/cadence for running the deployment schedule in a month. Takes objects formed like this {occurance(int),day(string)}. Day is the name of the day to run the deployment schedule, the occurance specifies which occurance of that day to run the deployment schedule. + +- Required: No +- Type: array +- MaxValue: 100 + +### Parameter: `nextRun` + +The next time the deployment schedule runs in ISO 8601 format. YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00. + +- Required: No +- Type: string +- Default: `''` +- MaxValue: 100 + +### Parameter: `nextRunOffsetMinutes` + +The next run's offset in minutes. + +- Required: No +- Type: int +- Default: `0` +- MaxValue: 100 + +### Parameter: `nonAzureComputerNames` + +List of names of non-azure machines in scope for the deployment schedule. + +- Required: No +- Type: array +- Default: `[]` +- MaxValue: 100 + +### Parameter: `nonAzureQueries` + +Array of functions from a Log Analytics workspace, used to scope the deployment schedule. + +- Required: No +- Type: array +- Default: `[]` +- MaxValue: 100 + +### Parameter: `postTaskParameters` + +Parameters provided to the task running after the deployment schedule. + +- Required: No +- Type: object +- MaxValue: 100 + +### Parameter: `postTaskSource` + +The source of the task running after the deployment schedule. + +- Required: No +- Type: string +- MaxValue: 100 + +### Parameter: `preTaskParameters` + +Parameters provided to the task running before the deployment schedule. + +- Required: No +- Type: object +- MaxValue: 100 + +### Parameter: `preTaskSource` + +The source of the task running before the deployment schedule. + +- Required: No +- Type: string +- MaxValue: 100 + +### Parameter: `scheduleDescription` + +The schedules description. + +- Required: No +- Type: string +- Default: `''` +- MaxValue: 100 + +### Parameter: `scopeByLocations` + +Specify locations to which to scope the deployment schedule to. + +- Required: No +- Type: array +- Default: `[]` +- MaxValue: 100 + +### Parameter: `scopeByResources` + +Specify the resources to scope the deployment schedule to. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + '[subscription().id]' + ] + ``` +- MaxValue: 100 + +### Parameter: `scopeByTags` + +Specify tags to which to scope the deployment schedule to. + +- Required: No +- Type: object +- Default: `{}` +- MaxValue: 100 + +### Parameter: `scopeByTagsOperation` + +Enables the scopeByTags to require All (Tag A and Tag B) or Any (Tag A or Tag B). + +- Required: No +- Type: string +- Default: `'All'` +- Allowed: + ```Bicep + [ + 'All' + 'Any' + ] + ``` +- MaxValue: 100 + +### Parameter: `startTime` + +The start time of the deployment schedule in ISO 8601 format. To specify a specific time use YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00. For schedules where we want to start the deployment as soon as possible, specify the time segment only in 24 hour format, HH:MM, 22:00. + +- Required: No +- Type: string +- Default: `''` +- MaxValue: 100 + +### Parameter: `timeZone` + +Time zone for the deployment schedule. IANA ID or a Windows Time Zone ID. + +- Required: No +- Type: string +- Default: `'UTC'` +- MaxValue: 100 + +### Parameter: `updateClassifications` + +Update classification included in the deployment schedule. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + 'Critical' + 'Security' + ] + ``` +- Allowed: + ```Bicep + [ + 'Critical' + 'Definition' + 'FeaturePack' + 'Other' + 'Security' + 'ServicePack' + 'Tools' + 'UpdateRollup' + 'Updates' + ] + ``` +- MaxValue: 100 + +### Parameter: `weekDays` + +Required when used with frequency 'Week'. Specified the day of the week to run the deployment schedule. + +- Required: No +- Type: array +- Allowed: + ```Bicep + [ + 'Friday' + 'Monday' + 'Saturday' + 'Sunday' + 'Thursday' + 'Tuesday' + 'Wednesday' + ] + ``` +- MaxValue: 100 + +### Parameter: `baseTime` + +Do not touch. Is used to provide the base time for time comparison for startTime. If startTime is specified in HH:MM format, baseTime is used to check if the provided startTime has passed, adding one day before setting the deployment schedule. + +- Required: No +- Type: string +- Default: `[utcNow('u')]` +- MaxValue: 100 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed softwareUpdateConfiguration. | +| `resourceGroupName` | string | The resource group of the deployed softwareUpdateConfiguration. | +| `resourceId` | string | The resource ID of the deployed softwareUpdateConfiguration. | diff --git a/avm/1.1.0/res/automation/automation-account/software-update-configuration/main.bicep b/avm/1.1.0/res/automation/automation-account/software-update-configuration/main.bicep new file mode 100644 index 000000000..73e135882 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/software-update-configuration/main.bicep @@ -0,0 +1,269 @@ +metadata name = 'Automation Account Software Update Configurations' +metadata description = 'This module deploys an Azure Automation Account Software Update Configuration.' + +@description('Required. The name of the Deployment schedule.') +param name string + +@description('Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment.') +param automationAccountName string + +@description('Required. The operating system to be configured by the deployment schedule.') +@allowed([ + 'Windows' + 'Linux' +]) +param operatingSystem string + +@description('Required. Reboot setting for the deployment schedule.') +@allowed([ + 'IfRequired' + 'Never' + 'RebootOnly' + 'Always' +]) +param rebootSetting string + +@description('Required. The frequency of the deployment schedule. When using \'Hour\', \'Day\', \'Week\' or \'Month\', an interval needs to be provided.') +@allowed([ + 'OneTime' + 'Hour' + 'Day' + 'Week' + 'Month' +]) +param frequency string + +@description('Optional. Maximum time allowed for the deployment schedule to run. Duration needs to be specified using the format PT[n]H[n]M[n]S as per ISO8601.') +param maintenanceWindow string = 'PT2H' + +@description('Optional. Update classification included in the deployment schedule.') +@allowed([ + 'Critical' + 'Security' + 'UpdateRollup' + 'FeaturePack' + 'ServicePack' + 'Definition' + 'Tools' + 'Updates' + 'Other' +]) +param updateClassifications array = [ + 'Critical' + 'Security' +] + +@description('Optional. KB numbers or Linux packages excluded in the deployment schedule.') +param excludeUpdates array = [] + +@description('Optional. KB numbers or Linux packages included in the deployment schedule.') +param includeUpdates array = [] + +@description('Optional. Specify the resources to scope the deployment schedule to.') +param scopeByResources array = [ + subscription().id +] + +@description('Optional. Specify tags to which to scope the deployment schedule to.') +param scopeByTags object = {} + +@description('Optional. Enables the scopeByTags to require All (Tag A and Tag B) or Any (Tag A or Tag B).') +@allowed([ + 'All' + 'Any' +]) +param scopeByTagsOperation string = 'All' + +@description('Optional. Specify locations to which to scope the deployment schedule to.') +param scopeByLocations array = [] + +@description('Optional. Parameters provided to the task running before the deployment schedule.') +param preTaskParameters object? + +@description('Optional. The source of the task running before the deployment schedule.') +param preTaskSource string? + +@description('Optional. Parameters provided to the task running after the deployment schedule.') +param postTaskParameters object? + +@description('Optional. The source of the task running after the deployment schedule.') +param postTaskSource string? + +@description('Optional. The interval of the frequency for the deployment schedule. 1 Hour is every hour, 2 Day is every second day, etc.') +@maxValue(100) +param interval int = 1 + +@description('Optional. Enables the deployment schedule.') +param isEnabled bool = true + +@description('Optional. Time zone for the deployment schedule. IANA ID or a Windows Time Zone ID.') +param timeZone string = 'UTC' + +@description('Optional. Array of functions from a Log Analytics workspace, used to scope the deployment schedule.') +param nonAzureQueries array = [] + +@description('Optional. List of azure resource IDs for azure virtual machines in scope for the deployment schedule.') +param azureVirtualMachines array = [] + +@description('Optional. List of names of non-azure machines in scope for the deployment schedule.') +param nonAzureComputerNames array = [] + +@description('Optional. Required when used with frequency \'Week\'. Specified the day of the week to run the deployment schedule.') +@allowed([ + 'Monday' + 'Tuesday' + 'Wednesday' + 'Thursday' + 'Friday' + 'Saturday' + 'Sunday' +]) +param weekDays string[]? + +@description('Optional. Can be used with frequency \'Month\'. Provides the specific days of the month to run the deployment schedule.') +@allowed([ + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 +]) +param monthDays int[]? + +@description('Optional. Can be used with frequency \'Month\'. Provides the pattern/cadence for running the deployment schedule in a month. Takes objects formed like this {occurance(int),day(string)}. Day is the name of the day to run the deployment schedule, the occurance specifies which occurance of that day to run the deployment schedule.') +param monthlyOccurrences array? + +@description('Optional. The start time of the deployment schedule in ISO 8601 format. To specify a specific time use YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00. For schedules where we want to start the deployment as soon as possible, specify the time segment only in 24 hour format, HH:MM, 22:00.') +param startTime string = '' + +@description('Optional. The end time of the deployment schedule in ISO 8601 format. YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00.') +param expiryTime string = '' + +@description('Optional. The expiry time\'s offset in minutes.') +param expiryTimeOffsetMinutes int = 0 + +@description('Optional. The next time the deployment schedule runs in ISO 8601 format. YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00.') +param nextRun string = '' + +@description('Optional. The next run\'s offset in minutes.') +param nextRunOffsetMinutes int = 0 + +@description('Optional. The schedules description.') +param scheduleDescription string = '' + +@description('Generated. Do not touch. Is used to provide the base time for time comparison for startTime. If startTime is specified in HH:MM format, baseTime is used to check if the provided startTime has passed, adding one day before setting the deployment schedule.') +param baseTime string = utcNow('u') + +var updateClassificationsVar = replace( + replace(replace(replace(string(updateClassifications), ',', ', '), '[', ''), ']', ''), + '"', + '' +) + +resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' existing = { + name: automationAccountName +} + +resource softwareUpdateConfiguration 'Microsoft.Automation/automationAccounts/softwareUpdateConfigurations@2019-06-01' = { + name: name + parent: automationAccount + properties: { + updateConfiguration: { + operatingSystem: operatingSystem + duration: maintenanceWindow + linux: ((operatingSystem == 'Linux') + ? { + excludedPackageNameMasks: excludeUpdates + includedPackageNameMasks: includeUpdates + includedPackageClassifications: updateClassificationsVar + rebootSetting: rebootSetting + } + : null) + windows: ((operatingSystem == 'Windows') + ? { + excludedKbNumbers: excludeUpdates + includedKbNumbers: includeUpdates + includedUpdateClassifications: updateClassificationsVar + rebootSetting: rebootSetting + } + : null) + targets: { + azureQueries: [ + { + scope: scopeByResources + tagSettings: { + tags: scopeByTags + filterOperator: scopeByTagsOperation + } + locations: scopeByLocations + } + ] + nonAzureQueries: nonAzureQueries + } + azureVirtualMachines: azureVirtualMachines + nonAzureComputerNames: nonAzureComputerNames + } + tasks: { + preTask: { + parameters: preTaskParameters + source: preTaskSource + } + postTask: { + parameters: postTaskParameters + source: postTaskSource + } + } + scheduleInfo: { + interval: interval + frequency: frequency + isEnabled: isEnabled + timeZone: timeZone + advancedSchedule: { + weekDays: weekDays + monthDays: monthDays + monthlyOccurrences: monthlyOccurrences + } + startTime: (empty(startTime) ? dateTimeAdd(baseTime, 'PT10M') : startTime) + expiryTime: expiryTime + expiryTimeOffsetMinutes: expiryTimeOffsetMinutes + nextRun: nextRun + nextRunOffsetMinutes: nextRunOffsetMinutes + description: scheduleDescription + } + } +} + +@description('The name of the deployed softwareUpdateConfiguration.') +output name string = softwareUpdateConfiguration.name + +@description('The resource ID of the deployed softwareUpdateConfiguration.') +output resourceId string = softwareUpdateConfiguration.id + +@description('The resource group of the deployed softwareUpdateConfiguration.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/automation/automation-account/software-update-configuration/main.json b/avm/1.1.0/res/automation/automation-account/software-update-configuration/main.json new file mode 100644 index 000000000..ebabcc056 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/software-update-configuration/main.json @@ -0,0 +1,417 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "18142998771588913270" + }, + "name": "Automation Account Software Update Configurations", + "description": "This module deploys an Azure Automation Account Software Update Configuration." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Deployment schedule." + } + }, + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "operatingSystem": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. The operating system to be configured by the deployment schedule." + } + }, + "rebootSetting": { + "type": "string", + "allowedValues": [ + "IfRequired", + "Never", + "RebootOnly", + "Always" + ], + "metadata": { + "description": "Required. Reboot setting for the deployment schedule." + } + }, + "frequency": { + "type": "string", + "allowedValues": [ + "OneTime", + "Hour", + "Day", + "Week", + "Month" + ], + "metadata": { + "description": "Required. The frequency of the deployment schedule. When using 'Hour', 'Day', 'Week' or 'Month', an interval needs to be provided." + } + }, + "maintenanceWindow": { + "type": "string", + "defaultValue": "PT2H", + "metadata": { + "description": "Optional. Maximum time allowed for the deployment schedule to run. Duration needs to be specified using the format PT[n]H[n]M[n]S as per ISO8601." + } + }, + "updateClassifications": { + "type": "array", + "defaultValue": [ + "Critical", + "Security" + ], + "allowedValues": [ + "Critical", + "Security", + "UpdateRollup", + "FeaturePack", + "ServicePack", + "Definition", + "Tools", + "Updates", + "Other" + ], + "metadata": { + "description": "Optional. Update classification included in the deployment schedule." + } + }, + "excludeUpdates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. KB numbers or Linux packages excluded in the deployment schedule." + } + }, + "includeUpdates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. KB numbers or Linux packages included in the deployment schedule." + } + }, + "scopeByResources": { + "type": "array", + "defaultValue": [ + "[subscription().id]" + ], + "metadata": { + "description": "Optional. Specify the resources to scope the deployment schedule to." + } + }, + "scopeByTags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Specify tags to which to scope the deployment schedule to." + } + }, + "scopeByTagsOperation": { + "type": "string", + "defaultValue": "All", + "allowedValues": [ + "All", + "Any" + ], + "metadata": { + "description": "Optional. Enables the scopeByTags to require All (Tag A and Tag B) or Any (Tag A or Tag B)." + } + }, + "scopeByLocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specify locations to which to scope the deployment schedule to." + } + }, + "preTaskParameters": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Parameters provided to the task running before the deployment schedule." + } + }, + "preTaskSource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source of the task running before the deployment schedule." + } + }, + "postTaskParameters": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Parameters provided to the task running after the deployment schedule." + } + }, + "postTaskSource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source of the task running after the deployment schedule." + } + }, + "interval": { + "type": "int", + "defaultValue": 1, + "maxValue": 100, + "metadata": { + "description": "Optional. The interval of the frequency for the deployment schedule. 1 Hour is every hour, 2 Day is every second day, etc." + } + }, + "isEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables the deployment schedule." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "UTC", + "metadata": { + "description": "Optional. Time zone for the deployment schedule. IANA ID or a Windows Time Zone ID." + } + }, + "nonAzureQueries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of functions from a Log Analytics workspace, used to scope the deployment schedule." + } + }, + "azureVirtualMachines": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of azure resource IDs for azure virtual machines in scope for the deployment schedule." + } + }, + "nonAzureComputerNames": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of names of non-azure machines in scope for the deployment schedule." + } + }, + "weekDays": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "allowedValues": [ + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday" + ], + "metadata": { + "description": "Optional. Required when used with frequency 'Week'. Specified the day of the week to run the deployment schedule." + } + }, + "monthDays": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "allowedValues": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31 + ], + "metadata": { + "description": "Optional. Can be used with frequency 'Month'. Provides the specific days of the month to run the deployment schedule." + } + }, + "monthlyOccurrences": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Can be used with frequency 'Month'. Provides the pattern/cadence for running the deployment schedule in a month. Takes objects formed like this {occurance(int),day(string)}. Day is the name of the day to run the deployment schedule, the occurance specifies which occurance of that day to run the deployment schedule." + } + }, + "startTime": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The start time of the deployment schedule in ISO 8601 format. To specify a specific time use YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00. For schedules where we want to start the deployment as soon as possible, specify the time segment only in 24 hour format, HH:MM, 22:00." + } + }, + "expiryTime": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The end time of the deployment schedule in ISO 8601 format. YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00." + } + }, + "expiryTimeOffsetMinutes": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The expiry time's offset in minutes." + } + }, + "nextRun": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The next time the deployment schedule runs in ISO 8601 format. YYYY-MM-DDTHH:MM:SS, 2021-12-31T23:00:00." + } + }, + "nextRunOffsetMinutes": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The next run's offset in minutes." + } + }, + "scheduleDescription": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The schedules description." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Do not touch. Is used to provide the base time for time comparison for startTime. If startTime is specified in HH:MM format, baseTime is used to check if the provided startTime has passed, adding one day before setting the deployment schedule." + } + } + }, + "variables": { + "updateClassificationsVar": "[replace(replace(replace(replace(string(parameters('updateClassifications')), ',', ', '), '[', ''), ']', ''), '\"', '')]" + }, + "resources": { + "automationAccount": { + "existing": true, + "type": "Microsoft.Automation/automationAccounts", + "apiVersion": "2022-08-08", + "name": "[parameters('automationAccountName')]" + }, + "softwareUpdateConfiguration": { + "type": "Microsoft.Automation/automationAccounts/softwareUpdateConfigurations", + "apiVersion": "2019-06-01", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "properties": { + "updateConfiguration": { + "operatingSystem": "[parameters('operatingSystem')]", + "duration": "[parameters('maintenanceWindow')]", + "linux": "[if(equals(parameters('operatingSystem'), 'Linux'), createObject('excludedPackageNameMasks', parameters('excludeUpdates'), 'includedPackageNameMasks', parameters('includeUpdates'), 'includedPackageClassifications', variables('updateClassificationsVar'), 'rebootSetting', parameters('rebootSetting')), null())]", + "windows": "[if(equals(parameters('operatingSystem'), 'Windows'), createObject('excludedKbNumbers', parameters('excludeUpdates'), 'includedKbNumbers', parameters('includeUpdates'), 'includedUpdateClassifications', variables('updateClassificationsVar'), 'rebootSetting', parameters('rebootSetting')), null())]", + "targets": { + "azureQueries": [ + { + "scope": "[parameters('scopeByResources')]", + "tagSettings": { + "tags": "[parameters('scopeByTags')]", + "filterOperator": "[parameters('scopeByTagsOperation')]" + }, + "locations": "[parameters('scopeByLocations')]" + } + ], + "nonAzureQueries": "[parameters('nonAzureQueries')]" + }, + "azureVirtualMachines": "[parameters('azureVirtualMachines')]", + "nonAzureComputerNames": "[parameters('nonAzureComputerNames')]" + }, + "tasks": { + "preTask": { + "parameters": "[parameters('preTaskParameters')]", + "source": "[parameters('preTaskSource')]" + }, + "postTask": { + "parameters": "[parameters('postTaskParameters')]", + "source": "[parameters('postTaskSource')]" + } + }, + "scheduleInfo": { + "interval": "[parameters('interval')]", + "frequency": "[parameters('frequency')]", + "isEnabled": "[parameters('isEnabled')]", + "timeZone": "[parameters('timeZone')]", + "advancedSchedule": { + "weekDays": "[parameters('weekDays')]", + "monthDays": "[parameters('monthDays')]", + "monthlyOccurrences": "[parameters('monthlyOccurrences')]" + }, + "startTime": "[if(empty(parameters('startTime')), dateTimeAdd(parameters('baseTime'), 'PT10M'), parameters('startTime'))]", + "expiryTime": "[parameters('expiryTime')]", + "expiryTimeOffsetMinutes": "[parameters('expiryTimeOffsetMinutes')]", + "nextRun": "[parameters('nextRun')]", + "nextRunOffsetMinutes": "[parameters('nextRunOffsetMinutes')]", + "description": "[parameters('scheduleDescription')]" + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed softwareUpdateConfiguration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed softwareUpdateConfiguration." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/softwareUpdateConfigurations', parameters('automationAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed softwareUpdateConfiguration." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/automation/automation-account/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/automation/automation-account/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..80a79d90f --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-automation.account-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'aamin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/automation/automation-account/tests/e2e/encr/dependencies.bicep b/avm/1.1.0/res/automation/automation-account/tests/e2e/encr/dependencies.bicep new file mode 100644 index 000000000..859e78741 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/tests/e2e/encr/dependencies.bicep @@ -0,0 +1,61 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-Key-Reader-RoleAssignment') + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The name of the Key Vault Encryption Key.') +output keyVaultEncryptionKeyName string = keyVault::key.name + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/avm/1.1.0/res/automation/automation-account/tests/e2e/encr/main.test.bicep b/avm/1.1.0/res/automation/automation-account/tests/e2e/encr/main.test.bicep new file mode 100644 index 000000000..c43435d4a --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/tests/e2e/encr/main.test.bicep @@ -0,0 +1,75 @@ +targetScope = 'subscription' + +metadata name = 'Using encryption with Customer-Managed-Key' +metadata description = 'This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-automation.account-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'aaencr' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + customerManagedKey: { + keyName: nestedDependencies.outputs.keyVaultEncryptionKeyName + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + userAssignedIdentityResourceId: nestedDependencies.outputs.managedIdentityResourceId + } + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + location: resourceLocation + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/automation/automation-account/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/automation/automation-account/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..403211cdb --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/tests/e2e/max/dependencies.bicep @@ -0,0 +1,81 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 0) + } + } + { + name: 'custom-private-subnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 1) + } + } + { + name: 'custom-private-subnet-2' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 2) + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.azure-automation.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network Default Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the 2nd created Virtual Network Subnet.') +output customSubnet1ResourceId string = virtualNetwork.properties.subnets[1].id + +@description('The resource ID of the 3rd created Virtual Network Subnet.') +output customSubnet2ResourceId string = virtualNetwork.properties.subnets[2].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/1.1.0/res/automation/automation-account/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/automation/automation-account/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..9fdf9f5cd --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/tests/e2e/max/main.test.bicep @@ -0,0 +1,314 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-automation.account-${serviceShort}-rg' + +// Enforce uksouth to avoid restrictions around zone redundancy in certain regions +#disable-next-line no-hardcoded-location +var enforcedLocation = 'westeurope' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'aamax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: enforcedLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: enforcedLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + diagnosticSettings: [ + { + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + gallerySolutions: [ + { + name: 'Updates(${last(split(diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId, '/'))})' + plan: { + product: 'OMSGallery/Updates' + publisher: 'Microsoft' + } + } + ] + jobSchedules: [ + { + runbookName: 'TestRunbook' + scheduleName: 'TestSchedule' + } + ] + credentials: [ + { + name: 'Credential01' + description: 'Description of Credential01' + userName: 'userName01' + password: password + } + { + name: 'Credential02' + userName: 'username02' + password: password + } + ] + disableLocalAuth: true + linkedWorkspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + location: enforcedLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + modules: [ + { + name: 'PSWindowsUpdate' + uri: 'https://www.powershellgallery.com/api/v2/package' + version: 'latest' + } + ] + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + service: 'Webhook' + subnetResourceId: nestedDependencies.outputs.customSubnet1ResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + service: 'Webhook' + subnetResourceId: nestedDependencies.outputs.customSubnet2ResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + service: 'DSCAndHybridWorker' + subnetResourceId: nestedDependencies.outputs.customSubnet1ResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + roleAssignments: [ + { + name: 'de334944-f952-4273-8ab3-bd523380034c' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + runbooks: [ + { + description: 'Test runbook' + name: 'TestRunbook' + type: 'PowerShell' + uri: 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.automation/101-automation/scripts/AzureAutomationTutorial.ps1' + version: '1.0.0.0' + } + ] + schedules: [ + { + advancedSchedule: {} + expiryTime: '9999-12-31T13:00' + frequency: 'Hour' + interval: 12 + name: 'TestSchedule' + startTime: '' + timeZone: 'Europe/Berlin' + } + ] + softwareUpdateConfigurations: [ + { + excludeUpdates: [ + '123456' + ] + frequency: 'Month' + includeUpdates: [ + '654321' + ] + interval: 1 + maintenanceWindow: 'PT4H' + monthlyOccurrences: [ + { + day: 'Friday' + occurrence: 3 + } + ] + name: 'Windows_ZeroDay' + operatingSystem: 'Windows' + rebootSetting: 'IfRequired' + scopeByTags: { + Update: [ + 'Automatic-Wave1' + ] + } + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Definition' + 'FeaturePack' + 'Security' + 'ServicePack' + 'Tools' + 'UpdateRollup' + 'Updates' + ] + } + { + excludeUpdates: [ + 'icacls' + ] + frequency: 'OneTime' + includeUpdates: [ + 'kernel' + ] + maintenanceWindow: 'PT4H' + name: 'Linux_ZeroDay' + operatingSystem: 'Linux' + rebootSetting: 'IfRequired' + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Other' + 'Security' + ] + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + variables: [ + { + description: 'TestStringDescription' + name: 'TestString' + value: '\'TestString\'' + } + { + description: 'TestIntegerDescription' + name: 'TestInteger' + value: '500' + } + { + description: 'TestBooleanDescription' + name: 'TestBoolean' + value: 'false' + } + { + description: 'TestDateTimeDescription' + isEncrypted: false + name: 'TestDateTime' + value: '\'\\/Date(1637934042656)\\/\'' + } + { + description: 'TestEncryptedDescription' + name: 'TestEncryptedVariable' + value: '\'TestEncryptedValue\'' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/1.1.0/res/automation/automation-account/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/automation/automation-account/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..77af000af --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,63 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.azure-automation.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/1.1.0/res/automation/automation-account/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/automation/automation-account/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..c5ae757c3 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,260 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-automation.account-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'aawaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + diagnosticSettings: [ + { + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + gallerySolutions: [ + { + name: 'Updates(${last(split(diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId, '/'))})' + plan: { + product: 'OMSGallery/Updates' + } + } + ] + jobSchedules: [ + { + runbookName: 'TestRunbook' + scheduleName: 'TestSchedule' + } + ] + disableLocalAuth: true + linkedWorkspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + modules: [ + { + name: 'PSWindowsUpdate' + uri: 'https://www.powershellgallery.com/api/v2/package' + version: 'latest' + } + ] + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + service: 'Webhook' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + service: 'DSCAndHybridWorker' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + runbooks: [ + { + description: 'Test runbook' + name: 'TestRunbook' + type: 'PowerShell' + uri: 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.automation/101-automation/scripts/AzureAutomationTutorial.ps1' + version: '1.0.0.0' + } + ] + schedules: [ + { + advancedSchedule: {} + expiryTime: '9999-12-31T13:00' + frequency: 'Hour' + interval: 12 + name: 'TestSchedule' + startTime: '' + timeZone: 'Europe/Berlin' + } + ] + softwareUpdateConfigurations: [ + { + excludeUpdates: [ + '123456' + ] + frequency: 'Month' + includeUpdates: [ + '654321' + ] + interval: 1 + maintenanceWindow: 'PT4H' + monthlyOccurrences: [ + { + day: 'Friday' + occurrence: 3 + } + ] + name: 'Windows_ZeroDay' + operatingSystem: 'Windows' + rebootSetting: 'IfRequired' + scopeByTags: { + Update: [ + 'Automatic-Wave1' + ] + } + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Definition' + 'FeaturePack' + 'Security' + 'ServicePack' + 'Tools' + 'UpdateRollup' + 'Updates' + ] + } + { + excludeUpdates: [ + 'icacls' + ] + frequency: 'OneTime' + includeUpdates: [ + 'kernel' + ] + maintenanceWindow: 'PT4H' + name: 'Linux_ZeroDay' + operatingSystem: 'Linux' + rebootSetting: 'IfRequired' + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Other' + 'Security' + ] + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + variables: [ + { + description: 'TestStringDescription' + name: 'TestString' + value: '\'TestString\'' + } + { + description: 'TestIntegerDescription' + name: 'TestInteger' + value: '500' + } + { + description: 'TestBooleanDescription' + name: 'TestBoolean' + value: 'false' + } + { + description: 'TestDateTimeDescription' + name: 'TestDateTime' + value: '\'\\/Date(1637934042656)\\/\'' + } + { + description: 'TestEncryptedDescription' + name: 'TestEncryptedVariable' + value: '\'TestEncryptedValue\'' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/1.1.0/res/automation/automation-account/variable/README.md b/avm/1.1.0/res/automation/automation-account/variable/README.md new file mode 100644 index 000000000..3c1b6ca2c --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/variable/README.md @@ -0,0 +1,82 @@ +# Automation Account Variables `[Microsoft.Automation/automationAccounts/variables]` + +This module deploys an Azure Automation Account Variable. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Automation/automationAccounts/variables` | [2022-08-08](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automation/2022-08-08/automationAccounts/variables) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the variable. | +| [`value`](#parameter-value) | securestring | The value of the variable. For security best practices, this value is always passed as a secure string as it could contain an encrypted value when the "isEncrypted" property is set to true. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`automationAccountName`](#parameter-automationaccountname) | string | The name of the parent Automation Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | The description of the variable. | +| [`isEncrypted`](#parameter-isencrypted) | bool | If the variable should be encrypted. For security reasons encryption of variables should be enabled. | + +### Parameter: `name` + +The name of the variable. + +- Required: Yes +- Type: string + +### Parameter: `value` + +The value of the variable. For security best practices, this value is always passed as a secure string as it could contain an encrypted value when the "isEncrypted" property is set to true. + +- Required: Yes +- Type: securestring + +### Parameter: `automationAccountName` + +The name of the parent Automation Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `description` + +The description of the variable. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `isEncrypted` + +If the variable should be encrypted. For security reasons encryption of variables should be enabled. + +- Required: No +- Type: bool +- Default: `True` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed variable. | +| `resourceGroupName` | string | The resource group of the deployed variable. | +| `resourceId` | string | The resource ID of the deployed variable. | diff --git a/avm/1.1.0/res/automation/automation-account/variable/main.bicep b/avm/1.1.0/res/automation/automation-account/variable/main.bicep new file mode 100644 index 000000000..5872eb7c6 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/variable/main.bicep @@ -0,0 +1,41 @@ +metadata name = 'Automation Account Variables' +metadata description = 'This module deploys an Azure Automation Account Variable.' + +@sys.description('Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment.') +param automationAccountName string + +@sys.description('Required. The name of the variable.') +param name string + +@secure() +@sys.description('Required. The value of the variable. For security best practices, this value is always passed as a secure string as it could contain an encrypted value when the "isEncrypted" property is set to true.') +param value string + +@sys.description('Optional. The description of the variable.') +param description string = '' + +@sys.description('Optional. If the variable should be encrypted. For security reasons encryption of variables should be enabled.') +param isEncrypted bool = true + +resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' existing = { + name: automationAccountName +} + +resource variable 'Microsoft.Automation/automationAccounts/variables@2022-08-08' = { + name: name + parent: automationAccount + properties: { + description: description + isEncrypted: isEncrypted + value: value + } +} + +@sys.description('The name of the deployed variable.') +output name string = variable.name + +@sys.description('The resource ID of the deployed variable.') +output resourceId string = variable.id + +@sys.description('The resource group of the deployed variable.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/automation/automation-account/variable/main.json b/avm/1.1.0/res/automation/automation-account/variable/main.json new file mode 100644 index 000000000..3f80fee68 --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/variable/main.json @@ -0,0 +1,82 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "16330558441628473023" + }, + "name": "Automation Account Variables", + "description": "This module deploys an Azure Automation Account Variable." + }, + "parameters": { + "automationAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Automation Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the variable." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the variable. For security best practices, this value is always passed as a secure string as it could contain an encrypted value when the \"isEncrypted\" property is set to true." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the variable." + } + }, + "isEncrypted": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If the variable should be encrypted. For security reasons encryption of variables should be enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.Automation/automationAccounts/variables", + "apiVersion": "2022-08-08", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "isEncrypted": "[parameters('isEncrypted')]", + "value": "[parameters('value')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed variable." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed variable." + }, + "value": "[resourceId('Microsoft.Automation/automationAccounts/variables', parameters('automationAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed variable." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/automation/automation-account/version.json b/avm/1.1.0/res/automation/automation-account/version.json new file mode 100644 index 000000000..6a120cace --- /dev/null +++ b/avm/1.1.0/res/automation/automation-account/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.11", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/availability-set/README.md b/avm/1.1.0/res/compute/availability-set/README.md new file mode 100644 index 000000000..e6ce73d26 --- /dev/null +++ b/avm/1.1.0/res/compute/availability-set/README.md @@ -0,0 +1,594 @@ +# Availability Sets `[Microsoft.Compute/availabilitySets]` + +This module deploys an Availability Set. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Compute/availabilitySets` | [2023-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-03-01/availabilitySets) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/compute/availability-set:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module availabilitySet 'br/public:avm/res/compute/availability-set:' = { + name: 'availabilitySetDeployment' + params: { + // Required parameters + name: 'casmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "casmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/availability-set:' + +// Required parameters +param name = 'casmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module availabilitySet 'br/public:avm/res/compute/availability-set:' = { + name: 'availabilitySetDeployment' + params: { + // Required parameters + name: 'casmax001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + proximityPlacementGroupResourceId: '' + roleAssignments: [ + { + name: 'd9d13442-232d-4861-9ab9-bad5e90c4f71' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "casmax001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "proximityPlacementGroupResourceId": { + "value": "" + }, + "roleAssignments": { + "value": [ + { + "name": "d9d13442-232d-4861-9ab9-bad5e90c4f71", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/availability-set:' + +// Required parameters +param name = 'casmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param proximityPlacementGroupResourceId = '' +param roleAssignments = [ + { + name: 'd9d13442-232d-4861-9ab9-bad5e90c4f71' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module availabilitySet 'br/public:avm/res/compute/availability-set:' = { + name: 'availabilitySetDeployment' + params: { + // Required parameters + name: 'caswaf001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + proximityPlacementGroupResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "caswaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "proximityPlacementGroupResourceId": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/availability-set:' + +// Required parameters +param name = 'caswaf001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param proximityPlacementGroupResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the availability set that is being created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Resource location. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`platformFaultDomainCount`](#parameter-platformfaultdomaincount) | int | The number of fault domains to use. | +| [`platformUpdateDomainCount`](#parameter-platformupdatedomaincount) | int | The number of update domains to use. | +| [`proximityPlacementGroupResourceId`](#parameter-proximityplacementgroupresourceid) | string | Resource ID of a proximity placement group. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`skuName`](#parameter-skuname) | string | SKU of the availability set.

- Use 'Aligned' for virtual machines with managed disks.

- Use 'Classic' for virtual machines with unmanaged disks. | +| [`tags`](#parameter-tags) | object | Tags of the availability set resource. | + +### Parameter: `name` + +The name of the availability set that is being created. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Resource location. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `platformFaultDomainCount` + +The number of fault domains to use. + +- Required: No +- Type: int +- Default: `2` + +### Parameter: `platformUpdateDomainCount` + +The number of update domains to use. + +- Required: No +- Type: int +- Default: `5` + +### Parameter: `proximityPlacementGroupResourceId` + +Resource ID of a proximity placement group. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Virtual Machine Administrator Login'` + - `'Virtual Machine Contributor'` + - `'Virtual Machine Data Access Administrator (preview)'` + - `'Virtual Machine User Login'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `skuName` + +SKU of the availability set.

- Use 'Aligned' for virtual machines with managed disks.

- Use 'Classic' for virtual machines with unmanaged disks. + +- Required: No +- Type: string +- Default: `'Aligned'` + +### Parameter: `tags` + +Tags of the availability set resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the availability set. | +| `resourceGroupName` | string | The resource group the availability set was deployed into. | +| `resourceId` | string | The resource ID of the availability set. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/compute/availability-set/main.bicep b/avm/1.1.0/res/compute/availability-set/main.bicep new file mode 100644 index 000000000..2a2eb8296 --- /dev/null +++ b/avm/1.1.0/res/compute/availability-set/main.bicep @@ -0,0 +1,187 @@ +metadata name = 'Availability Sets' +metadata description = 'This module deploys an Availability Set.' + +@description('Required. The name of the availability set that is being created.') +param name string + +@description('Optional. The number of fault domains to use.') +param platformFaultDomainCount int = 2 + +@description('Optional. The number of update domains to use.') +param platformUpdateDomainCount int = 5 + +@description('Optional. SKU of the availability set.

- Use \'Aligned\' for virtual machines with managed disks.

- Use \'Classic\' for virtual machines with unmanaged disks.') +param skuName string = 'Aligned' + +@description('Optional. Resource ID of a proximity placement group.') +param proximityPlacementGroupResourceId string = '' + +@description('Optional. Resource location.') +param location string = resourceGroup().location + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the availability set resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) + 'Virtual Machine Administrator Login': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '1c0163c0-47e6-4577-8991-ea5c82e286e4' + ) + 'Virtual Machine Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '9980e02c-c2be-4d73-94e8-173b1dc7cf3c' + ) + 'Virtual Machine Data Access Administrator (preview)': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '66f75aeb-eabe-4b70-9f1e-c350c4c9ad04' + ) + 'Virtual Machine User Login': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'fb879df8-f326-4884-b1cf-06f3ad86be52' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.compute-availabilityset.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource availabilitySet 'Microsoft.Compute/availabilitySets@2023-03-01' = { + name: name + location: location + tags: tags + properties: { + platformFaultDomainCount: platformFaultDomainCount + platformUpdateDomainCount: platformUpdateDomainCount + proximityPlacementGroup: !empty(proximityPlacementGroupResourceId) + ? { + id: proximityPlacementGroupResourceId + } + : null + } + sku: { + name: skuName + } +} + +resource availabilitySet_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: availabilitySet +} + +resource availabilitySet_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(availabilitySet.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: availabilitySet + } +] + +@description('The name of the availability set.') +output name string = availabilitySet.name + +@description('The resource ID of the availability set.') +output resourceId string = availabilitySet.id + +@description('The resource group the availability set was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = availabilitySet.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/compute/availability-set/main.json b/avm/1.1.0/res/compute/availability-set/main.json new file mode 100644 index 000000000..9f0b6bd63 --- /dev/null +++ b/avm/1.1.0/res/compute/availability-set/main.json @@ -0,0 +1,306 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "7948129872833564934" + }, + "name": "Availability Sets", + "description": "This module deploys an Availability Set." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the availability set that is being created." + } + }, + "platformFaultDomainCount": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Optional. The number of fault domains to use." + } + }, + "platformUpdateDomainCount": { + "type": "int", + "defaultValue": 5, + "metadata": { + "description": "Optional. The number of update domains to use." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Aligned", + "metadata": { + "description": "Optional. SKU of the availability set.

- Use 'Aligned' for virtual machines with managed disks.

- Use 'Classic' for virtual machines with unmanaged disks." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a proximity placement group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Resource location." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the availability set resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", + "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", + "Virtual Machine Data Access Administrator (preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '66f75aeb-eabe-4b70-9f1e-c350c4c9ad04')]", + "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.compute-availabilityset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "availabilitySet": { + "type": "Microsoft.Compute/availabilitySets", + "apiVersion": "2023-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "platformFaultDomainCount": "[parameters('platformFaultDomainCount')]", + "platformUpdateDomainCount": "[parameters('platformUpdateDomainCount')]", + "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]" + }, + "sku": { + "name": "[parameters('skuName')]" + } + }, + "availabilitySet_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Compute/availabilitySets/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "availabilitySet" + ] + }, + "availabilitySet_roleAssignments": { + "copy": { + "name": "availabilitySet_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/availabilitySets/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/availabilitySets', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "availabilitySet" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the availability set." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the availability set." + }, + "value": "[resourceId('Microsoft.Compute/availabilitySets', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the availability set was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('availabilitySet', '2023-03-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/availability-set/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/compute/availability-set/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..35b2cca18 --- /dev/null +++ b/avm/1.1.0/res/compute/availability-set/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.availabilitysets-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'casmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/compute/availability-set/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/compute/availability-set/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..5ac87aacb --- /dev/null +++ b/avm/1.1.0/res/compute/availability-set/tests/e2e/max/dependencies.bicep @@ -0,0 +1,24 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Proximity Placement Group to create.') +param proximityPlacementGroupName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource proximityPlacementGroup 'Microsoft.Compute/proximityPlacementGroups@2022-03-01' = { + name: proximityPlacementGroupName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Proximity Placement Group.') +output proximityPlacementGroupResourceId string = proximityPlacementGroup.id diff --git a/avm/1.1.0/res/compute/availability-set/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/compute/availability-set/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..beeb54bb3 --- /dev/null +++ b/avm/1.1.0/res/compute/availability-set/tests/e2e/max/main.test.bicep @@ -0,0 +1,90 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.availabilitysets-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'casmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + proximityPlacementGroupName: 'dep-${namePrefix}-ppg-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + proximityPlacementGroupResourceId: nestedDependencies.outputs.proximityPlacementGroupResourceId + roleAssignments: [ + { + name: 'd9d13442-232d-4861-9ab9-bad5e90c4f71' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/compute/availability-set/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/compute/availability-set/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..db26ceda3 --- /dev/null +++ b/avm/1.1.0/res/compute/availability-set/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Proximity Placement Group to create.') +param proximityPlacementGroupName string + +resource proximityPlacementGroup 'Microsoft.Compute/proximityPlacementGroups@2022-03-01' = { + name: proximityPlacementGroupName + location: location +} + +@description('The resource ID of the created Proximity Placement Group.') +output proximityPlacementGroupResourceId string = proximityPlacementGroup.id diff --git a/avm/1.1.0/res/compute/availability-set/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/compute/availability-set/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..3fa0902e0 --- /dev/null +++ b/avm/1.1.0/res/compute/availability-set/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,67 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.availabilitysets-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'caswaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + proximityPlacementGroupName: 'dep-${namePrefix}-ppg-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + proximityPlacementGroupResourceId: nestedDependencies.outputs.proximityPlacementGroupResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/compute/availability-set/version.json b/avm/1.1.0/res/compute/availability-set/version.json new file mode 100644 index 000000000..1c035df49 --- /dev/null +++ b/avm/1.1.0/res/compute/availability-set/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.2", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/disk-encryption-set/README.md b/avm/1.1.0/res/compute/disk-encryption-set/README.md new file mode 100644 index 000000000..aac430126 --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/README.md @@ -0,0 +1,862 @@ +# Disk Encryption Sets `[Microsoft.Compute/diskEncryptionSets]` + +This module deploys a Disk Encryption Set. The module will attempt to set permissions on the provided Key Vault for any used user-assigned identity. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Compute/diskEncryptionSets` | [2023-10-02](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-10-02/diskEncryptionSets) | +| `Microsoft.KeyVault/vaults/accessPolicies` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/accessPolicies) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/compute/disk-encryption-set:`. + +- [Using Key Vault with the Access Policy permission model](#example-1-using-key-vault-with-the-access-policy-permission-model) +- [Using only defaults](#example-2-using-only-defaults) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [WAF-aligned](#example-4-waf-aligned) + +### Example 1: _Using Key Vault with the Access Policy permission model_ + +This instance uses a Key Vault with the Access Policy permission model. If no permissions on the Key Vault are set, the module attempts to add the permissions for you. + + +
+ +via Bicep module + +```bicep +module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set:' = { + name: 'diskEncryptionSetDeployment' + params: { + // Required parameters + keyName: '' + keyVaultResourceId: '' + name: 'cdesap001' + // Non-required parameters + location: '' + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "keyName": { + "value": "" + }, + "keyVaultResourceId": { + "value": "" + }, + "name": { + "value": "cdesap001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "" + ] + } + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk-encryption-set:' + +// Required parameters +param keyName = '' +param keyVaultResourceId = '' +param name = 'cdesap001' +// Non-required parameters +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 2: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set:' = { + name: 'diskEncryptionSetDeployment' + params: { + // Required parameters + keyName: '' + keyVaultResourceId: '' + name: 'cdesmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "keyName": { + "value": "" + }, + "keyVaultResourceId": { + "value": "" + }, + "name": { + "value": "cdesmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk-encryption-set:' + +// Required parameters +param keyName = '' +param keyVaultResourceId = '' +param name = 'cdesmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 3: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set:' = { + name: 'diskEncryptionSetDeployment' + params: { + // Required parameters + keyName: '' + keyVaultResourceId: '' + name: 'cdesmax001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + roleAssignments: [ + { + name: 'c331c327-6458-473a-9398-95b382c6f04f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "keyName": { + "value": "" + }, + "keyVaultResourceId": { + "value": "" + }, + "name": { + "value": "cdesmax001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "roleAssignments": { + "value": [ + { + "name": "c331c327-6458-473a-9398-95b382c6f04f", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk-encryption-set:' + +// Required parameters +param keyName = '' +param keyVaultResourceId = '' +param name = 'cdesmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: 'c331c327-6458-473a-9398-95b382c6f04f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 4: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set:' = { + name: 'diskEncryptionSetDeployment' + params: { + // Required parameters + keyName: '' + keyVaultResourceId: '' + name: 'cdeswaf001' + // Non-required parameters + location: '' + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "keyName": { + "value": "" + }, + "keyVaultResourceId": { + "value": "" + }, + "name": { + "value": "cdeswaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk-encryption-set:' + +// Required parameters +param keyName = '' +param keyVaultResourceId = '' +param name = 'cdeswaf001' +// Non-required parameters +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyName`](#parameter-keyname) | string | Key URL (with version) pointing to a key or secret in KeyVault. | +| [`keyVaultResourceId`](#parameter-keyvaultresourceid) | string | Resource ID of the KeyVault containing the key or secret. | +| [`name`](#parameter-name) | string | The name of the disk encryption set that is being created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`encryptionType`](#parameter-encryptiontype) | string | The type of key used to encrypt the data of the disk. For security reasons, it is recommended to set encryptionType to EncryptionAtRestWithPlatformAndCustomerKeys. | +| [`federatedClientId`](#parameter-federatedclientid) | string | Multi-tenant application client ID to access key vault in a different tenant. Setting the value to "None" will clear the property. | +| [`keyVersion`](#parameter-keyversion) | string | The version of the customer managed key to reference for encryption. If not provided, the latest key version is used. | +| [`location`](#parameter-location) | string | Resource location. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. At least one identity type is required. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`rotationToLatestKeyVersionEnabled`](#parameter-rotationtolatestkeyversionenabled) | bool | Set this flag to true to enable auto-updating of this disk encryption set to the latest key version. | +| [`tags`](#parameter-tags) | object | Tags of the disk encryption resource. | + +### Parameter: `keyName` + +Key URL (with version) pointing to a key or secret in KeyVault. + +- Required: Yes +- Type: string + +### Parameter: `keyVaultResourceId` + +Resource ID of the KeyVault containing the key or secret. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the disk encryption set that is being created. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `encryptionType` + +The type of key used to encrypt the data of the disk. For security reasons, it is recommended to set encryptionType to EncryptionAtRestWithPlatformAndCustomerKeys. + +- Required: No +- Type: string +- Default: `'EncryptionAtRestWithPlatformAndCustomerKeys'` +- Allowed: + ```Bicep + [ + 'EncryptionAtRestWithCustomerKey' + 'EncryptionAtRestWithPlatformAndCustomerKeys' + ] + ``` + +### Parameter: `federatedClientId` + +Multi-tenant application client ID to access key vault in a different tenant. Setting the value to "None" will clear the property. + +- Required: No +- Type: string +- Default: `'None'` + +### Parameter: `keyVersion` + +The version of the customer managed key to reference for encryption. If not provided, the latest key version is used. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `location` + +Resource location. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. At least one identity type is required. + +- Required: No +- Type: object +- Default: + ```Bicep + { + systemAssigned: true + } + ``` + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: No +- Type: array + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Operator for Managed Disks'` + - `'Disk Backup Reader'` + - `'Disk Pool Operator'` + - `'Disk Restore Operator'` + - `'Disk Snapshot Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `rotationToLatestKeyVersionEnabled` + +Set this flag to true to enable auto-updating of this disk encryption set to the latest key version. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `tags` + +Tags of the disk encryption resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `identities` | object | The idenities of the disk encryption set. | +| `keyVaultName` | string | The name of the key vault with the disk encryption key. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the disk encryption set. | +| `resourceGroupName` | string | The resource group the disk encryption set was deployed into. | +| `resourceId` | string | The resource ID of the disk encryption set. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/compute/disk-encryption-set/main.bicep b/avm/1.1.0/res/compute/disk-encryption-set/main.bicep new file mode 100644 index 000000000..c8a8ede4a --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/main.bicep @@ -0,0 +1,271 @@ +metadata name = 'Disk Encryption Sets' +metadata description = 'This module deploys a Disk Encryption Set. The module will attempt to set permissions on the provided Key Vault for any used user-assigned identity.' + +@description('Required. The name of the disk encryption set that is being created.') +param name string + +@description('Optional. Resource location.') +param location string = resourceGroup().location + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Required. Resource ID of the KeyVault containing the key or secret.') +param keyVaultResourceId string + +@description('Required. Key URL (with version) pointing to a key or secret in KeyVault.') +param keyName string + +@description('Optional. The version of the customer managed key to reference for encryption. If not provided, the latest key version is used.') +param keyVersion string = '' + +@description('Optional. The type of key used to encrypt the data of the disk. For security reasons, it is recommended to set encryptionType to EncryptionAtRestWithPlatformAndCustomerKeys.') +@allowed([ + 'EncryptionAtRestWithCustomerKey' + 'EncryptionAtRestWithPlatformAndCustomerKeys' +]) +param encryptionType string = 'EncryptionAtRestWithPlatformAndCustomerKeys' + +@description('Optional. Multi-tenant application client ID to access key vault in a different tenant. Setting the value to "None" will clear the property.') +param federatedClientId string = 'None' + +@description('Optional. Set this flag to true to enable auto-updating of this disk encryption set to the latest key version.') +param rotationToLatestKeyVersionEnabled bool = false + +@description('Optional. The managed identity definition for this resource. At least one identity type is required.') +param managedIdentities managedIdentitiesType = { + systemAssigned: true +} + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the disk encryption resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Data Operator for Managed Disks': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '959f8984-c045-4866-89c7-12bf9737be2e' + ) + 'Disk Backup Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24' + ) + 'Disk Pool Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '60fc6e62-5479-42d4-8bf4-67625fcc2840' + ) + 'Disk Restore Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b50d9833-a0cb-478e-945f-707fcc997c13' + ) + 'Disk Snapshot Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7efff54f-a5b4-42b5-a1c5-5411624893ce' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.compute-diskencryptionset.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2021-10-01' existing = { + name: last(split(keyVaultResourceId, '/'))! + scope: resourceGroup(split(keyVaultResourceId, '/')[2], split(keyVaultResourceId, '/')[4]) + + resource key 'keys@2021-10-01' existing = { + name: keyName + } +} + +// Note: This is only enabled for user-assigned identities as the service's system-assigned identity isn't available during its initial deployment +module keyVaultPermissions 'modules/nested_keyVaultPermissions.bicep' = [ + for (userAssignedIdentityResourceId, index) in (managedIdentities.?userAssignedResourceIds ?? []): { + name: '${uniqueString(deployment().name, location)}-DiskEncrSet-KVPermissions-${index}' + params: { + keyName: keyName + keyVaultResourceId: keyVaultResourceId + userAssignedIdentityResourceId: userAssignedIdentityResourceId + rbacAuthorizationEnabled: keyVault.properties.enableRbacAuthorization + location: location + } + scope: resourceGroup(split(keyVaultResourceId, '/')[2], split(keyVaultResourceId, '/')[4]) + } +] + +resource diskEncryptionSet 'Microsoft.Compute/diskEncryptionSets@2023-10-02' = { + name: name + location: location + tags: tags + identity: identity + properties: { + activeKey: { + sourceVault: { + id: keyVaultResourceId + } + keyUrl: !empty(keyVersion) + ? '${keyVault::key.properties.keyUri}/${keyVersion}' + : keyVault::key.properties.keyUriWithVersion + } + encryptionType: encryptionType + federatedClientId: federatedClientId + rotationToLatestKeyVersionEnabled: rotationToLatestKeyVersionEnabled + } + dependsOn: [ + keyVaultPermissions + ] +} + +resource diskEncryptionSet_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + diskEncryptionSet.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: diskEncryptionSet + } +] + +resource diskEncryptionSet_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: diskEncryptionSet +} + +@description('The resource ID of the disk encryption set.') +output resourceId string = diskEncryptionSet.id + +@description('The name of the disk encryption set.') +output name string = diskEncryptionSet.name + +@description('The resource group the disk encryption set was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string? = diskEncryptionSet.?identity.?principalId + +@description('The idenities of the disk encryption set.') +output identities object = diskEncryptionSet.identity + +@description('The name of the key vault with the disk encryption key.') +output keyVaultName string = last(split(keyVaultResourceId, '/'))! + +@description('The location the resource was deployed into.') +output location string = diskEncryptionSet.location + +// =============== // +// Definitions // +// =============== // + +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[]? +} + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/compute/disk-encryption-set/main.json b/avm/1.1.0/res/compute/disk-encryption-set/main.json new file mode 100644 index 000000000..82686b200 --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/main.json @@ -0,0 +1,745 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "9578132933341238313" + }, + "name": "Disk Encryption Sets", + "description": "This module deploys a Disk Encryption Set. The module will attempt to set permissions on the provided Key Vault for any used user-assigned identity." + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the disk encryption set that is being created." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Resource location." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the KeyVault containing the key or secret." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. Key URL (with version) pointing to a key or secret in KeyVault." + } + }, + "keyVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the latest key version is used." + } + }, + "encryptionType": { + "type": "string", + "defaultValue": "EncryptionAtRestWithPlatformAndCustomerKeys", + "allowedValues": [ + "EncryptionAtRestWithCustomerKey", + "EncryptionAtRestWithPlatformAndCustomerKeys" + ], + "metadata": { + "description": "Optional. The type of key used to encrypt the data of the disk. For security reasons, it is recommended to set encryptionType to EncryptionAtRestWithPlatformAndCustomerKeys." + } + }, + "federatedClientId": { + "type": "string", + "defaultValue": "None", + "metadata": { + "description": "Optional. Multi-tenant application client ID to access key vault in a different tenant. Setting the value to \"None\" will clear the property." + } + }, + "rotationToLatestKeyVersionEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Set this flag to true to enable auto-updating of this disk encryption set to the latest key version." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "defaultValue": { + "systemAssigned": true + }, + "metadata": { + "description": "Optional. The managed identity definition for this resource. At least one identity type is required." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the disk encryption resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", + "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", + "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", + "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", + "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "keyVault::key": { + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2021-10-01", + "subscriptionId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(parameters('keyVaultResourceId'), '/')), parameters('keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.compute-diskencryptionset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-10-01", + "subscriptionId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "name": "[last(split(parameters('keyVaultResourceId'), '/'))]" + }, + "diskEncryptionSet": { + "type": "Microsoft.Compute/diskEncryptionSets", + "apiVersion": "2023-10-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "activeKey": { + "sourceVault": { + "id": "[parameters('keyVaultResourceId')]" + }, + "keyUrl": "[if(not(empty(parameters('keyVersion'))), format('{0}/{1}', reference('keyVault::key').keyUri, parameters('keyVersion')), reference('keyVault::key').keyUriWithVersion)]" + }, + "encryptionType": "[parameters('encryptionType')]", + "federatedClientId": "[parameters('federatedClientId')]", + "rotationToLatestKeyVersionEnabled": "[parameters('rotationToLatestKeyVersionEnabled')]" + }, + "dependsOn": [ + "keyVault::key", + "keyVaultPermissions" + ] + }, + "diskEncryptionSet_roleAssignments": { + "copy": { + "name": "diskEncryptionSet_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/diskEncryptionSets/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/diskEncryptionSets', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "diskEncryptionSet" + ] + }, + "diskEncryptionSet_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Compute/diskEncryptionSets/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "diskEncryptionSet" + ] + }, + "keyVaultPermissions": { + "copy": { + "name": "keyVaultPermissions", + "count": "[length(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-DiskEncrSet-KVPermissions-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyName": { + "value": "[parameters('keyName')]" + }, + "keyVaultResourceId": { + "value": "[parameters('keyVaultResourceId')]" + }, + "userAssignedIdentityResourceId": { + "value": "[coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray())[copyIndex()]]" + }, + "rbacAuthorizationEnabled": { + "value": "[reference('keyVault').enableRbacAuthorization]" + }, + "location": { + "value": "[parameters('location')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "11508841695002099283" + } + }, + "parameters": { + "rbacAuthorizationEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Required. A boolean to specify whether or not the used Key Vault has RBAC authentication enabled or not." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resourceID of the User Assigned Identity to assign permissions to." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Resource location." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the KeyVault containing the key or secret." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. Name of the key to set the permissions for." + } + } + }, + "resources": [ + { + "condition": "[equals(parameters('rbacAuthorizationEnabled'), true())]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', last(split(parameters('keyVaultResourceId'), '/')), parameters('keyName'))]", + "name": "[guid(format('msi-{0}-{1}-{2}-Key-Reader-RoleAssignment', resourceId('Microsoft.KeyVault/vaults/keys', last(split(parameters('keyVaultResourceId'), '/')), parameters('keyName')), parameters('location'), parameters('userAssignedIdentityResourceId')))]", + "properties": { + "principalId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('userAssignedIdentityResourceId'), '/')[2], split(parameters('userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(parameters('userAssignedIdentityResourceId'), '/'))), '2023-01-31').principalId]", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "principalType": "ServicePrincipal" + } + }, + { + "condition": "[not(equals(parameters('rbacAuthorizationEnabled'), true()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-DiskEncrSet-KVAccessPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(parameters('keyVaultResourceId'), '/'))]" + }, + "accessPolicies": { + "value": [ + { + "tenantId": "[subscription().tenantId]", + "objectId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('userAssignedIdentityResourceId'), '/')[2], split(parameters('userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(parameters('userAssignedIdentityResourceId'), '/'))), '2023-01-31').principalId]", + "permissions": { + "keys": [ + "get", + "wrapKey", + "unwrapKey" + ] + } + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "14994276207531705519" + }, + "name": "Key Vault Access Policies", + "description": "This module deploys a Key Vault Access Policy." + }, + "definitions": { + "accessPoliciesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "accessPolicies": { + "$ref": "#/definitions/accessPoliciesType", + "metadata": { + "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedAccessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ] + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "policies": { + "type": "Microsoft.KeyVault/vaults/accessPolicies", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", + "properties": { + "accessPolicies": "[variables('formattedAccessPolicies')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the access policies assignment was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the access policies assignment." + }, + "value": "add" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the access policies assignment." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', parameters('keyVaultName'), 'add')]" + } + } + } + } + } + ] + } + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the disk encryption set." + }, + "value": "[resourceId('Microsoft.Compute/diskEncryptionSets', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the disk encryption set." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the disk encryption set was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('diskEncryptionSet', '2023-10-02', 'full'), 'identity'), 'principalId')]" + }, + "identities": { + "type": "object", + "metadata": { + "description": "The idenities of the disk encryption set." + }, + "value": "[reference('diskEncryptionSet', '2023-10-02', 'full').identity]" + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "The name of the key vault with the disk encryption key." + }, + "value": "[last(split(parameters('keyVaultResourceId'), '/'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('diskEncryptionSet', '2023-10-02', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/disk-encryption-set/modules/key-vault.vault.access-policy.bicep b/avm/1.1.0/res/compute/disk-encryption-set/modules/key-vault.vault.access-policy.bicep new file mode 100644 index 000000000..d25fc38ca --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/modules/key-vault.vault.access-policy.bicep @@ -0,0 +1,119 @@ +metadata name = 'Key Vault Access Policies' +metadata description = 'This module deploys a Key Vault Access Policy.' + +@description('Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment.') +param keyVaultName string + +@description('Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault\'s tenant ID.') +param accessPolicies accessPoliciesType + +var formattedAccessPolicies = [ + for accessPolicy in (accessPolicies ?? []): { + applicationId: accessPolicy.?applicationId ?? '' + objectId: accessPolicy.objectId + permissions: accessPolicy.permissions + tenantId: accessPolicy.?tenantId ?? tenant().tenantId + } +] + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +resource policies 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { + name: 'add' + parent: keyVault + properties: { + accessPolicies: formattedAccessPolicies + } +} + +@description('The name of the resource group the access policies assignment was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the access policies assignment.') +output name string = policies.name + +@description('The resource ID of the access policies assignment.') +output resourceId string = policies.id + +// ================ // +// Definitions // +// ================ // +type accessPoliciesType = { + @description('Optional. The tenant ID that is used for authenticating requests to the key vault.') + tenantId: string? + + @description('Required. The object ID of a user, service principal or security group in the tenant for the vault.') + objectId: string + + @description('Optional. Application ID of the client making request on behalf of a principal.') + applicationId: string? + + permissions: { + @description('Optional. Permissions to keys.') + keys: ( + | 'all' + | 'backup' + | 'create' + | 'decrypt' + | 'delete' + | 'encrypt' + | 'get' + | 'getrotationpolicy' + | 'import' + | 'list' + | 'purge' + | 'recover' + | 'release' + | 'restore' + | 'rotate' + | 'setrotationpolicy' + | 'sign' + | 'unwrapKey' + | 'update' + | 'verify' + | 'wrapKey')[]? + + @description('Optional. Permissions to secrets.') + secrets: ('all' | 'backup' | 'delete' | 'get' | 'list' | 'purge' | 'recover' | 'restore' | 'set')[]? + + @description('Optional. Permissions to certificates.') + certificates: ( + | 'all' + | 'backup' + | 'create' + | 'delete' + | 'deleteissuers' + | 'get' + | 'getissuers' + | 'import' + | 'list' + | 'listissuers' + | 'managecontacts' + | 'manageissuers' + | 'purge' + | 'recover' + | 'restore' + | 'setissuers' + | 'update')[]? + + @description('Optional. Permissions to storage accounts.') + storage: ( + | 'all' + | 'backup' + | 'delete' + | 'deletesas' + | 'get' + | 'getsas' + | 'list' + | 'listsas' + | 'purge' + | 'recover' + | 'regeneratekey' + | 'restore' + | 'set' + | 'setsas' + | 'update')[]? + } +}[]? diff --git a/avm/1.1.0/res/compute/disk-encryption-set/modules/nested_keyVaultPermissions.bicep b/avm/1.1.0/res/compute/disk-encryption-set/modules/nested_keyVaultPermissions.bicep new file mode 100644 index 000000000..af30f6943 --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/modules/nested_keyVaultPermissions.bicep @@ -0,0 +1,66 @@ +@description('Required. A boolean to specify whether or not the used Key Vault has RBAC authentication enabled or not.') +param rbacAuthorizationEnabled bool = true + +@description('Required. The resourceID of the User Assigned Identity to assign permissions to.') +param userAssignedIdentityResourceId string + +@description('Optional. Resource location.') +param location string = resourceGroup().location + +@description('Required. Resource ID of the KeyVault containing the key or secret.') +param keyVaultResourceId string + +@description('Required. Name of the key to set the permissions for.') +param keyName string + +resource keyVault 'Microsoft.KeyVault/vaults@2021-10-01' existing = { + name: last(split(keyVaultResourceId, '/'))! + + resource key 'keys@2021-10-01' existing = { + name: keyName + } +} + +resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = { + name: last(split(userAssignedIdentityResourceId, '/'))! + scope: resourceGroup(split(userAssignedIdentityResourceId, '/')[2], split(userAssignedIdentityResourceId, '/')[4]) + +} + +// =============== // +// Role Assignment // +// =============== // + +resource keyVaultKeyRBAC 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (rbacAuthorizationEnabled == true) { + name: guid('msi-${keyVault::key.id}-${location}-${userAssignedIdentityResourceId}-Key-Reader-RoleAssignment') + scope: keyVault::key + properties: { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424') // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +// ============= // +// Access Policy // +// ============= // + +module keyVaultAccessPolicies 'key-vault.vault.access-policy.bicep' = if (rbacAuthorizationEnabled != true) { + name: '${uniqueString(deployment().name, location)}-DiskEncrSet-KVAccessPolicies' + params: { + keyVaultName: last(split(keyVaultResourceId, '/'))! + accessPolicies: [ + { + tenantId: subscription().tenantId + objectId: userAssignedIdentity.properties.principalId + permissions: { + keys: [ + 'get' + 'wrapKey' + 'unwrapKey' + ] + } + } + ] + } +} diff --git a/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/accessPolicies/dependencies.bicep b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/accessPolicies/dependencies.bicep new file mode 100644 index 000000000..810b6e459 --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/accessPolicies/dependencies.bicep @@ -0,0 +1,51 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: false + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The name of the created encryption key.') +output keyName string = keyVault::key.name + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/accessPolicies/main.test.bicep b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/accessPolicies/main.test.bicep new file mode 100644 index 000000000..5730cc4f3 --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/accessPolicies/main.test.bicep @@ -0,0 +1,98 @@ +targetScope = 'subscription' + +metadata name = 'Using Key Vault with the Access Policy permission model' +metadata description = 'This instance uses a Key Vault with the Access Policy permission model. If no permissions on the Key Vault are set, the module attempts to add the permissions for you.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.diskencryptionsets-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cdesap' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + keyName: nestedDependencies.outputs.keyName + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..19eadf3cf --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,37 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The name of the created encryption key.') +output keyName string = keyVault::key.name diff --git a/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..26d731b9f --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,66 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.diskencryptionsets-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cdesmin' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + keyName: nestedDependencies.outputs.keyName + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + location: resourceLocation + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..bf2bbaace --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/max/dependencies.bicep @@ -0,0 +1,51 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The name of the created encryption key.') +output keyName string = keyVault::key.name + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..9adc10445 --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/max/main.test.bicep @@ -0,0 +1,103 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.diskencryptionsets-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cdesmax' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + keyName: nestedDependencies.outputs.keyName + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + roleAssignments: [ + { + name: 'c331c327-6458-473a-9398-95b382c6f04f' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..eb651cd09 --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,48 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The name of the created encryption key.') +output keyName string = keyVault::key.name + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..d0438eb91 --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,77 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.diskencryptionsets-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cdeswaf' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + keyName: nestedDependencies.outputs.keyName + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/compute/disk-encryption-set/version.json b/avm/1.1.0/res/compute/disk-encryption-set/version.json new file mode 100644 index 000000000..3f863a2be --- /dev/null +++ b/avm/1.1.0/res/compute/disk-encryption-set/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.4", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/disk/README.md b/avm/1.1.0/res/compute/disk/README.md new file mode 100644 index 000000000..cdacf8fc5 --- /dev/null +++ b/avm/1.1.0/res/compute/disk/README.md @@ -0,0 +1,1118 @@ +# Compute Disks `[Microsoft.Compute/disks]` + +This module deploys a Compute Disk + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Compute/disks` | [2023-10-02](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-10-02/disks) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/compute/disk:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using an image](#example-2-using-an-image) +- [Using an imported image](#example-3-using-an-imported-image) +- [Using large parameter set](#example-4-using-large-parameter-set) +- [WAF-aligned](#example-5-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module disk 'br/public:avm/res/compute/disk:' = { + name: 'diskDeployment' + params: { + // Required parameters + availabilityZone: 0 + name: 'cdmin001' + sku: 'Standard_LRS' + // Non-required parameters + diskSizeGB: 1 + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "availabilityZone": { + "value": 0 + }, + "name": { + "value": "cdmin001" + }, + "sku": { + "value": "Standard_LRS" + }, + // Non-required parameters + "diskSizeGB": { + "value": 1 + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk:' + +// Required parameters +param availabilityZone = 0 +param name = 'cdmin001' +param sku = 'Standard_LRS' +// Non-required parameters +param diskSizeGB = 1 +param location = '' +``` + +
+

+ +### Example 2: _Using an image_ + +This instance deploys the module with an image reference. + + +

+ +via Bicep module + +```bicep +module disk 'br/public:avm/res/compute/disk:' = { + name: 'diskDeployment' + params: { + // Required parameters + availabilityZone: 0 + name: 'cdimg001' + sku: 'Standard_LRS' + // Non-required parameters + createOption: 'FromImage' + imageReferenceId: '' + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "availabilityZone": { + "value": 0 + }, + "name": { + "value": "cdimg001" + }, + "sku": { + "value": "Standard_LRS" + }, + // Non-required parameters + "createOption": { + "value": "FromImage" + }, + "imageReferenceId": { + "value": "" + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk:' + +// Required parameters +param availabilityZone = 0 +param name = 'cdimg001' +param sku = 'Standard_LRS' +// Non-required parameters +param createOption = 'FromImage' +param imageReferenceId = '' +param location = '' +``` + +
+

+ +### Example 3: _Using an imported image_ + +This instance deploys the module with a custom image that is imported from a VHD in a storage account. + + +

+ +via Bicep module + +```bicep +module disk 'br/public:avm/res/compute/disk:' = { + name: 'diskDeployment' + params: { + // Required parameters + availabilityZone: 0 + name: 'cdimp001' + sku: 'Standard_LRS' + // Non-required parameters + createOption: 'Import' + location: '' + sourceUri: '' + storageAccountId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "availabilityZone": { + "value": 0 + }, + "name": { + "value": "cdimp001" + }, + "sku": { + "value": "Standard_LRS" + }, + // Non-required parameters + "createOption": { + "value": "Import" + }, + "location": { + "value": "" + }, + "sourceUri": { + "value": "" + }, + "storageAccountId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk:' + +// Required parameters +param availabilityZone = 0 +param name = 'cdimp001' +param sku = 'Standard_LRS' +// Non-required parameters +param createOption = 'Import' +param location = '' +param sourceUri = '' +param storageAccountId = '' +``` + +
+

+ +### Example 4: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module disk 'br/public:avm/res/compute/disk:' = { + name: 'diskDeployment' + params: { + // Required parameters + availabilityZone: 2 + name: 'cdmax001' + sku: 'Premium_LRS' + // Non-required parameters + diskIOPSReadWrite: 500 + diskMBpsReadWrite: 60 + diskSizeGB: 128 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + logicalSectorSize: 512 + osType: 'Windows' + publicNetworkAccess: 'Enabled' + roleAssignments: [ + { + name: '89cc419c-8383-461d-9a70-5cfae4045a8d' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "availabilityZone": { + "value": 2 + }, + "name": { + "value": "cdmax001" + }, + "sku": { + "value": "Premium_LRS" + }, + // Non-required parameters + "diskIOPSReadWrite": { + "value": 500 + }, + "diskMBpsReadWrite": { + "value": 60 + }, + "diskSizeGB": { + "value": 128 + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "logicalSectorSize": { + "value": 512 + }, + "osType": { + "value": "Windows" + }, + "publicNetworkAccess": { + "value": "Enabled" + }, + "roleAssignments": { + "value": [ + { + "name": "89cc419c-8383-461d-9a70-5cfae4045a8d", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk:' + +// Required parameters +param availabilityZone = 2 +param name = 'cdmax001' +param sku = 'Premium_LRS' +// Non-required parameters +param diskIOPSReadWrite = 500 +param diskMBpsReadWrite = 60 +param diskSizeGB = 128 +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param logicalSectorSize = 512 +param osType = 'Windows' +param publicNetworkAccess = 'Enabled' +param roleAssignments = [ + { + name: '89cc419c-8383-461d-9a70-5cfae4045a8d' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 5: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module disk 'br/public:avm/res/compute/disk:' = { + name: 'diskDeployment' + params: { + // Required parameters + availabilityZone: 2 + name: 'cdwaf001' + sku: 'Premium_LRS' + // Non-required parameters + diskIOPSReadWrite: 500 + diskMBpsReadWrite: 60 + diskSizeGB: 128 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + logicalSectorSize: 512 + osType: 'Windows' + publicNetworkAccess: 'Enabled' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "availabilityZone": { + "value": 2 + }, + "name": { + "value": "cdwaf001" + }, + "sku": { + "value": "Premium_LRS" + }, + // Non-required parameters + "diskIOPSReadWrite": { + "value": 500 + }, + "diskMBpsReadWrite": { + "value": 60 + }, + "diskSizeGB": { + "value": 128 + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "logicalSectorSize": { + "value": 512 + }, + "osType": { + "value": "Windows" + }, + "publicNetworkAccess": { + "value": "Enabled" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk:' + +// Required parameters +param availabilityZone = 2 +param name = 'cdwaf001' +param sku = 'Premium_LRS' +// Non-required parameters +param diskIOPSReadWrite = 500 +param diskMBpsReadWrite = 60 +param diskSizeGB = 128 +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param logicalSectorSize = 512 +param osType = 'Windows' +param publicNetworkAccess = 'Enabled' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`availabilityZone`](#parameter-availabilityzone) | int | If set to 1, 2 or 3, the availability zone is hardcoded to that value. If zero, then availability zones are not used. Note that the availability zone number here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone.To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones) and [Distribute VMs and disks across availability zones](https://learn.microsoft.com/en-us/azure/virtual-machines/disks-high-availability#distribute-vms-and-disks-across-availability-zones). | +| [`name`](#parameter-name) | string | The name of the disk that is being created. | +| [`sku`](#parameter-sku) | string | The disks sku name. Can be . | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`diskSizeGB`](#parameter-disksizegb) | int | The size of the disk to create. Required if create option is Empty. | +| [`storageAccountId`](#parameter-storageaccountid) | string | The resource ID of the storage account containing the blob to import as a disk. Required if create option is Import. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`acceleratedNetwork`](#parameter-acceleratednetwork) | bool | True if the image from which the OS disk is created supports accelerated networking. | +| [`architecture`](#parameter-architecture) | string | CPU architecture supported by an OS disk. | +| [`burstingEnabled`](#parameter-burstingenabled) | bool | Set to true to enable bursting beyond the provisioned performance target of the disk. | +| [`completionPercent`](#parameter-completionpercent) | int | Percentage complete for the background copy when a resource is created via the CopyStart operation. | +| [`createOption`](#parameter-createoption) | string | Sources of a disk creation. | +| [`diskIOPSReadWrite`](#parameter-diskiopsreadwrite) | int | The number of IOPS allowed for this disk; only settable for UltraSSD disks. | +| [`diskMBpsReadWrite`](#parameter-diskmbpsreadwrite) | int | The bandwidth allowed for this disk; only settable for UltraSSD disks. | +| [`edgeZone`](#parameter-edgezone) | string | Specifies the Edge Zone within the Azure Region where this Managed Disk should exist. Changing this forces a new Managed Disk to be created. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`hyperVGeneration`](#parameter-hypervgeneration) | string | The hypervisor generation of the Virtual Machine. Applicable to OS disks only. | +| [`imageReferenceId`](#parameter-imagereferenceid) | string | A relative uri containing either a Platform Image Repository or user image reference. | +| [`location`](#parameter-location) | string | Resource location. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`logicalSectorSize`](#parameter-logicalsectorsize) | int | Logical sector size in bytes for Ultra disks. Supported values are 512 ad 4096. | +| [`maxShares`](#parameter-maxshares) | int | The maximum number of VMs that can attach to the disk at the same time. Default value is 0. | +| [`networkAccessPolicy`](#parameter-networkaccesspolicy) | string | Policy for accessing the disk via network. | +| [`optimizedForFrequentAttach`](#parameter-optimizedforfrequentattach) | bool | Setting this property to true improves reliability and performance of data disks that are frequently (more than 5 times a day) by detached from one virtual machine and attached to another. This property should not be set for disks that are not detached and attached frequently as it causes the disks to not align with the fault domain of the virtual machine. | +| [`osType`](#parameter-ostype) | string | Sources of a disk creation. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Policy for controlling export on the disk. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`securityDataUri`](#parameter-securitydatauri) | string | If create option is ImportSecure, this is the URI of a blob to be imported into VM guest state. | +| [`sourceResourceId`](#parameter-sourceresourceid) | string | If create option is Copy, this is the ARM ID of the source snapshot or disk. | +| [`sourceUri`](#parameter-sourceuri) | string | If create option is Import, this is the URI of a blob to be imported into a managed disk. | +| [`tags`](#parameter-tags) | object | Tags of the availability set resource. | +| [`uploadSizeBytes`](#parameter-uploadsizebytes) | int | If create option is Upload, this is the size of the contents of the upload including the VHD footer. | + +### Parameter: `availabilityZone` + +If set to 1, 2 or 3, the availability zone is hardcoded to that value. If zero, then availability zones are not used. Note that the availability zone number here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone.To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones) and [Distribute VMs and disks across availability zones](https://learn.microsoft.com/en-us/azure/virtual-machines/disks-high-availability#distribute-vms-and-disks-across-availability-zones). + +- Required: Yes +- Type: int +- Allowed: + ```Bicep + [ + 0 + 1 + 2 + 3 + ] + ``` + +### Parameter: `name` + +The name of the disk that is being created. + +- Required: Yes +- Type: string + +### Parameter: `sku` + +The disks sku name. Can be . + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Premium_LRS' + 'Premium_ZRS' + 'PremiumV2_LRS' + 'Standard_LRS' + 'StandardSSD_LRS' + 'UltraSSD_LRS' + ] + ``` + +### Parameter: `diskSizeGB` + +The size of the disk to create. Required if create option is Empty. + +- Required: No +- Type: int +- Default: `0` + +### Parameter: `storageAccountId` + +The resource ID of the storage account containing the blob to import as a disk. Required if create option is Import. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `acceleratedNetwork` + +True if the image from which the OS disk is created supports accelerated networking. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `architecture` + +CPU architecture supported by an OS disk. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Arm64' + 'x64' + ] + ``` + +### Parameter: `burstingEnabled` + +Set to true to enable bursting beyond the provisioned performance target of the disk. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `completionPercent` + +Percentage complete for the background copy when a resource is created via the CopyStart operation. + +- Required: No +- Type: int +- Default: `100` + +### Parameter: `createOption` + +Sources of a disk creation. + +- Required: No +- Type: string +- Default: `'Empty'` +- Allowed: + ```Bicep + [ + 'Attach' + 'Copy' + 'CopyStart' + 'Empty' + 'FromImage' + 'Import' + 'ImportSecure' + 'Restore' + 'Upload' + 'UploadPreparedSecure' + ] + ``` + +### Parameter: `diskIOPSReadWrite` + +The number of IOPS allowed for this disk; only settable for UltraSSD disks. + +- Required: No +- Type: int +- Default: `0` + +### Parameter: `diskMBpsReadWrite` + +The bandwidth allowed for this disk; only settable for UltraSSD disks. + +- Required: No +- Type: int +- Default: `0` + +### Parameter: `edgeZone` + +Specifies the Edge Zone within the Azure Region where this Managed Disk should exist. Changing this forces a new Managed Disk to be created. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'EdgeZone' + ] + ``` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `hyperVGeneration` + +The hypervisor generation of the Virtual Machine. Applicable to OS disks only. + +- Required: No +- Type: string +- Default: `'V2'` +- Allowed: + ```Bicep + [ + 'V1' + 'V2' + ] + ``` + +### Parameter: `imageReferenceId` + +A relative uri containing either a Platform Image Repository or user image reference. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `location` + +Resource location. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `logicalSectorSize` + +Logical sector size in bytes for Ultra disks. Supported values are 512 ad 4096. + +- Required: No +- Type: int +- Default: `4096` + +### Parameter: `maxShares` + +The maximum number of VMs that can attach to the disk at the same time. Default value is 0. + +- Required: No +- Type: int +- Default: `1` + +### Parameter: `networkAccessPolicy` + +Policy for accessing the disk via network. + +- Required: No +- Type: string +- Default: `'DenyAll'` +- Allowed: + ```Bicep + [ + 'AllowAll' + 'AllowPrivate' + 'DenyAll' + ] + ``` + +### Parameter: `optimizedForFrequentAttach` + +Setting this property to true improves reliability and performance of data disks that are frequently (more than 5 times a day) by detached from one virtual machine and attached to another. This property should not be set for disks that are not detached and attached frequently as it causes the disks to not align with the fault domain of the virtual machine. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `osType` + +Sources of a disk creation. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `publicNetworkAccess` + +Policy for controlling export on the disk. + +- Required: No +- Type: string +- Default: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Operator for Managed Disks'` + - `'Disk Backup Reader'` + - `'Disk Pool Operator'` + - `'Disk Restore Operator'` + - `'Disk Snapshot Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `securityDataUri` + +If create option is ImportSecure, this is the URI of a blob to be imported into VM guest state. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `sourceResourceId` + +If create option is Copy, this is the ARM ID of the source snapshot or disk. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `sourceUri` + +If create option is Import, this is the URI of a blob to be imported into a managed disk. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `tags` + +Tags of the availability set resource. + +- Required: No +- Type: object + +### Parameter: `uploadSizeBytes` + +If create option is Upload, this is the size of the contents of the upload including the VHD footer. + +- Required: No +- Type: int +- Default: `20972032` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the disk. | +| `resourceGroupName` | string | The resource group the disk was deployed into. | +| `resourceId` | string | The resource ID of the disk. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/compute/disk/main.bicep b/avm/1.1.0/res/compute/disk/main.bicep new file mode 100644 index 000000000..00bff65b8 --- /dev/null +++ b/avm/1.1.0/res/compute/disk/main.bicep @@ -0,0 +1,335 @@ +metadata name = 'Compute Disks' +metadata description = 'This module deploys a Compute Disk' + +@description('Required. The name of the disk that is being created.') +param name string + +@description('Optional. Resource location.') +param location string = resourceGroup().location + +@allowed([ + 'Standard_LRS' + 'Premium_LRS' + 'StandardSSD_LRS' + 'UltraSSD_LRS' + 'Premium_ZRS' + 'PremiumV2_LRS' +]) +@description('Required. The disks sku name. Can be .') +param sku string + +@allowed([ + 'EdgeZone' + '' +]) +@description('Optional. Specifies the Edge Zone within the Azure Region where this Managed Disk should exist. Changing this forces a new Managed Disk to be created.') +param edgeZone string = '' + +@allowed([ + 'x64' + 'Arm64' + '' +]) +@description('Optional. CPU architecture supported by an OS disk.') +param architecture string = '' + +@description('Optional. Set to true to enable bursting beyond the provisioned performance target of the disk.') +param burstingEnabled bool = false + +@description('Optional. Percentage complete for the background copy when a resource is created via the CopyStart operation.') +param completionPercent int = 100 + +@allowed([ + 'Attach' + 'Copy' + 'CopyStart' + 'Empty' + 'FromImage' + 'Import' + 'ImportSecure' + 'Restore' + 'Upload' + 'UploadPreparedSecure' +]) +@description('Optional. Sources of a disk creation.') +param createOption string = 'Empty' + +@description('Optional. A relative uri containing either a Platform Image Repository or user image reference.') +param imageReferenceId string = '' + +@description('Optional. Logical sector size in bytes for Ultra disks. Supported values are 512 ad 4096.') +param logicalSectorSize int = 4096 + +@description('Optional. If create option is ImportSecure, this is the URI of a blob to be imported into VM guest state.') +param securityDataUri string = '' + +@description('Optional. If create option is Copy, this is the ARM ID of the source snapshot or disk.') +param sourceResourceId string = '' + +@description('Optional. If create option is Import, this is the URI of a blob to be imported into a managed disk.') +param sourceUri string = '' + +@description('Conditional. The resource ID of the storage account containing the blob to import as a disk. Required if create option is Import.') +param storageAccountId string = '' + +@description('Optional. If create option is Upload, this is the size of the contents of the upload including the VHD footer.') +param uploadSizeBytes int = 20972032 + +@description('Conditional. The size of the disk to create. Required if create option is Empty.') +param diskSizeGB int = 0 + +@description('Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks.') +param diskIOPSReadWrite int = 0 + +@description('Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks.') +param diskMBpsReadWrite int = 0 + +@allowed([ + 'V1' + 'V2' +]) +@description('Optional. The hypervisor generation of the Virtual Machine. Applicable to OS disks only.') +param hyperVGeneration string = 'V2' + +@description('Optional. The maximum number of VMs that can attach to the disk at the same time. Default value is 0.') +param maxShares int = 1 + +@allowed([ + 'AllowAll' + 'AllowPrivate' + 'DenyAll' +]) +@description('Optional. Policy for accessing the disk via network.') +param networkAccessPolicy string = 'DenyAll' + +@description('Optional. Setting this property to true improves reliability and performance of data disks that are frequently (more than 5 times a day) by detached from one virtual machine and attached to another. This property should not be set for disks that are not detached and attached frequently as it causes the disks to not align with the fault domain of the virtual machine.') +param optimizedForFrequentAttach bool = false + +@allowed([ + 'Windows' + 'Linux' + '' +]) +@description('Optional. Sources of a disk creation.') +param osType string = '' + +@allowed([ + 'Disabled' + 'Enabled' +]) +@description('Optional. Policy for controlling export on the disk.') +param publicNetworkAccess string = 'Disabled' + +@description('Optional. True if the image from which the OS disk is created supports accelerated networking.') +param acceleratedNetwork bool = false + +@description('Required. If set to 1, 2 or 3, the availability zone is hardcoded to that value. If zero, then availability zones are not used. Note that the availability zone number here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone.To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones) and [Distribute VMs and disks across availability zones](https://learn.microsoft.com/en-us/azure/virtual-machines/disks-high-availability#distribute-vms-and-disks-across-availability-zones).') +@allowed([ + 0 + 1 + 2 + 3 +]) +param availabilityZone int + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the availability set resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Data Operator for Managed Disks': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '959f8984-c045-4866-89c7-12bf9737be2e' + ) + 'Disk Backup Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24' + ) + 'Disk Pool Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '60fc6e62-5479-42d4-8bf4-67625fcc2840' + ) + 'Disk Restore Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b50d9833-a0cb-478e-945f-707fcc997c13' + ) + 'Disk Snapshot Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7efff54f-a5b4-42b5-a1c5-5411624893ce' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.compute-disk.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource disk 'Microsoft.Compute/disks@2023-10-02' = { + name: name + location: location + tags: tags + sku: { + name: sku + } + extendedLocation: !empty(edgeZone) + ? { + type: edgeZone + name: edgeZone + } + : null + properties: { + burstingEnabled: burstingEnabled + completionPercent: completionPercent + creationData: { + createOption: createOption + imageReference: createOption == 'FromImage' + ? { + id: imageReferenceId + } + : null + logicalSectorSize: contains(sku, 'Ultra') ? logicalSectorSize : null + securityDataUri: createOption == 'ImportSecure' ? securityDataUri : null + sourceResourceId: createOption == 'Copy' ? sourceResourceId : null + sourceUri: createOption == 'Import' ? sourceUri : null + storageAccountId: createOption == 'Import' ? storageAccountId : null + uploadSizeBytes: createOption == 'Upload' ? uploadSizeBytes : null + } + diskIOPSReadWrite: contains(sku, 'Ultra') ? diskIOPSReadWrite : null + diskMBpsReadWrite: contains(sku, 'Ultra') ? diskMBpsReadWrite : null + diskSizeGB: createOption == 'Empty' ? diskSizeGB : null + hyperVGeneration: !empty(osType) ? hyperVGeneration : null + maxShares: maxShares + networkAccessPolicy: networkAccessPolicy + optimizedForFrequentAttach: optimizedForFrequentAttach + osType: !empty(osType) ? osType : any(null) + publicNetworkAccess: publicNetworkAccess + supportedCapabilities: !empty(osType) + ? { + acceleratedNetwork: acceleratedNetwork + architecture: !empty(architecture) ? architecture : null + } + : {} + } + zones: availabilityZone != 0 ? array(string(availabilityZone)) : null +} + +resource disk_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: disk +} + +resource disk_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(disk.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: disk + } +] + +@description('The resource group the disk was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the disk.') +output resourceId string = disk.id + +@description('The name of the disk.') +output name string = disk.name + +@description('The location the resource was deployed into.') +output location string = disk.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/compute/disk/main.json b/avm/1.1.0/res/compute/disk/main.json new file mode 100644 index 000000000..c4af9fe76 --- /dev/null +++ b/avm/1.1.0/res/compute/disk/main.json @@ -0,0 +1,519 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3923614332201542801" + }, + "name": "Compute Disks", + "description": "This module deploys a Compute Disk" + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the disk that is being created." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Resource location." + } + }, + "sku": { + "type": "string", + "allowedValues": [ + "Standard_LRS", + "Premium_LRS", + "StandardSSD_LRS", + "UltraSSD_LRS", + "Premium_ZRS", + "PremiumV2_LRS" + ], + "metadata": { + "description": "Required. The disks sku name. Can be ." + } + }, + "edgeZone": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "EdgeZone", + "" + ], + "metadata": { + "description": "Optional. Specifies the Edge Zone within the Azure Region where this Managed Disk should exist. Changing this forces a new Managed Disk to be created." + } + }, + "architecture": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "x64", + "Arm64", + "" + ], + "metadata": { + "description": "Optional. CPU architecture supported by an OS disk." + } + }, + "burstingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Set to true to enable bursting beyond the provisioned performance target of the disk." + } + }, + "completionPercent": { + "type": "int", + "defaultValue": 100, + "metadata": { + "description": "Optional. Percentage complete for the background copy when a resource is created via the CopyStart operation." + } + }, + "createOption": { + "type": "string", + "defaultValue": "Empty", + "allowedValues": [ + "Attach", + "Copy", + "CopyStart", + "Empty", + "FromImage", + "Import", + "ImportSecure", + "Restore", + "Upload", + "UploadPreparedSecure" + ], + "metadata": { + "description": "Optional. Sources of a disk creation." + } + }, + "imageReferenceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. A relative uri containing either a Platform Image Repository or user image reference." + } + }, + "logicalSectorSize": { + "type": "int", + "defaultValue": 4096, + "metadata": { + "description": "Optional. Logical sector size in bytes for Ultra disks. Supported values are 512 ad 4096." + } + }, + "securityDataUri": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. If create option is ImportSecure, this is the URI of a blob to be imported into VM guest state." + } + }, + "sourceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. If create option is Copy, this is the ARM ID of the source snapshot or disk." + } + }, + "sourceUri": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. If create option is Import, this is the URI of a blob to be imported into a managed disk." + } + }, + "storageAccountId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. The resource ID of the storage account containing the blob to import as a disk. Required if create option is Import." + } + }, + "uploadSizeBytes": { + "type": "int", + "defaultValue": 20972032, + "metadata": { + "description": "Optional. If create option is Upload, this is the size of the contents of the upload including the VHD footer." + } + }, + "diskSizeGB": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Conditional. The size of the disk to create. Required if create option is Empty." + } + }, + "diskIOPSReadWrite": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks." + } + }, + "diskMBpsReadWrite": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks." + } + }, + "hyperVGeneration": { + "type": "string", + "defaultValue": "V2", + "allowedValues": [ + "V1", + "V2" + ], + "metadata": { + "description": "Optional. The hypervisor generation of the Virtual Machine. Applicable to OS disks only." + } + }, + "maxShares": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Optional. The maximum number of VMs that can attach to the disk at the same time. Default value is 0." + } + }, + "networkAccessPolicy": { + "type": "string", + "defaultValue": "DenyAll", + "allowedValues": [ + "AllowAll", + "AllowPrivate", + "DenyAll" + ], + "metadata": { + "description": "Optional. Policy for accessing the disk via network." + } + }, + "optimizedForFrequentAttach": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Setting this property to true improves reliability and performance of data disks that are frequently (more than 5 times a day) by detached from one virtual machine and attached to another. This property should not be set for disks that are not detached and attached frequently as it causes the disks to not align with the fault domain of the virtual machine." + } + }, + "osType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Windows", + "Linux", + "" + ], + "metadata": { + "description": "Optional. Sources of a disk creation." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Policy for controlling export on the disk." + } + }, + "acceleratedNetwork": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. True if the image from which the OS disk is created supports accelerated networking." + } + }, + "availabilityZone": { + "type": "int", + "allowedValues": [ + 0, + 1, + 2, + 3 + ], + "metadata": { + "description": "Required. If set to 1, 2 or 3, the availability zone is hardcoded to that value. If zero, then availability zones are not used. Note that the availability zone number here are the logical availability zone in your Azure subscription. Different subscriptions might have a different mapping of the physical zone and logical zone.To understand more, please refer to [Physical and logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview?tabs=azure-cli#physical-and-logical-availability-zones) and [Distribute VMs and disks across availability zones](https://learn.microsoft.com/en-us/azure/virtual-machines/disks-high-availability#distribute-vms-and-disks-across-availability-zones)." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the availability set resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", + "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", + "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", + "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", + "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.compute-disk.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "disk": { + "type": "Microsoft.Compute/disks", + "apiVersion": "2023-10-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "extendedLocation": "[if(not(empty(parameters('edgeZone'))), createObject('type', parameters('edgeZone'), 'name', parameters('edgeZone')), null())]", + "properties": { + "burstingEnabled": "[parameters('burstingEnabled')]", + "completionPercent": "[parameters('completionPercent')]", + "creationData": { + "createOption": "[parameters('createOption')]", + "imageReference": "[if(equals(parameters('createOption'), 'FromImage'), createObject('id', parameters('imageReferenceId')), null())]", + "logicalSectorSize": "[if(contains(parameters('sku'), 'Ultra'), parameters('logicalSectorSize'), null())]", + "securityDataUri": "[if(equals(parameters('createOption'), 'ImportSecure'), parameters('securityDataUri'), null())]", + "sourceResourceId": "[if(equals(parameters('createOption'), 'Copy'), parameters('sourceResourceId'), null())]", + "sourceUri": "[if(equals(parameters('createOption'), 'Import'), parameters('sourceUri'), null())]", + "storageAccountId": "[if(equals(parameters('createOption'), 'Import'), parameters('storageAccountId'), null())]", + "uploadSizeBytes": "[if(equals(parameters('createOption'), 'Upload'), parameters('uploadSizeBytes'), null())]" + }, + "diskIOPSReadWrite": "[if(contains(parameters('sku'), 'Ultra'), parameters('diskIOPSReadWrite'), null())]", + "diskMBpsReadWrite": "[if(contains(parameters('sku'), 'Ultra'), parameters('diskMBpsReadWrite'), null())]", + "diskSizeGB": "[if(equals(parameters('createOption'), 'Empty'), parameters('diskSizeGB'), null())]", + "hyperVGeneration": "[if(not(empty(parameters('osType'))), parameters('hyperVGeneration'), null())]", + "maxShares": "[parameters('maxShares')]", + "networkAccessPolicy": "[parameters('networkAccessPolicy')]", + "optimizedForFrequentAttach": "[parameters('optimizedForFrequentAttach')]", + "osType": "[if(not(empty(parameters('osType'))), parameters('osType'), null())]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "supportedCapabilities": "[if(not(empty(parameters('osType'))), createObject('acceleratedNetwork', parameters('acceleratedNetwork'), 'architecture', if(not(empty(parameters('architecture'))), parameters('architecture'), null())), createObject())]" + }, + "zones": "[if(not(equals(parameters('availabilityZone'), 0)), array(string(parameters('availabilityZone'))), null())]" + }, + "disk_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Compute/disks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "disk" + ] + }, + "disk_roleAssignments": { + "copy": { + "name": "disk_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/disks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/disks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "disk" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the disk was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the disk." + }, + "value": "[resourceId('Microsoft.Compute/disks', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the disk." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('disk', '2023-10-02', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/disk/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/compute/disk/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..719807deb --- /dev/null +++ b/avm/1.1.0/res/compute/disk/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,50 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.disk-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cdmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}-${serviceShort}001' + location: resourceLocation + sku: 'Standard_LRS' + availabilityZone: 0 + diskSizeGB: 1 + } + } +] diff --git a/avm/1.1.0/res/compute/disk/tests/e2e/image/dependencies.bicep b/avm/1.1.0/res/compute/disk/tests/e2e/image/dependencies.bicep new file mode 100644 index 000000000..2c8183e72 --- /dev/null +++ b/avm/1.1.0/res/compute/disk/tests/e2e/image/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created managed identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/compute/disk/tests/e2e/image/main.test.bicep b/avm/1.1.0/res/compute/disk/tests/e2e/image/main.test.bicep new file mode 100644 index 000000000..968fa356b --- /dev/null +++ b/avm/1.1.0/res/compute/disk/tests/e2e/image/main.test.bicep @@ -0,0 +1,60 @@ +targetScope = 'subscription' + +metadata name = 'Using an image' +metadata description = 'This instance deploys the module with an image reference.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.disks-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cdimg' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}-${serviceShort}001' + location: resourceLocation + sku: 'Standard_LRS' + availabilityZone: 0 + createOption: 'FromImage' + imageReferenceId: '${subscription().id}/Providers/Microsoft.Compute/Locations/westeurope/Publishers/MicrosoftWindowsServer/ArtifactTypes/VMImage/Offers/WindowsServer/Skus/2022-datacenter-azure-edition/Versions/20348.2340.240303' + } + } +] diff --git a/avm/1.1.0/res/compute/disk/tests/e2e/import/dependencies.bicep b/avm/1.1.0/res/compute/disk/tests/e2e/import/dependencies.bicep new file mode 100644 index 000000000..108455ddc --- /dev/null +++ b/avm/1.1.0/res/compute/disk/tests/e2e/import/dependencies.bicep @@ -0,0 +1,152 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create and to copy the VHD into.') +param storageAccountName string + +@description('Required. The name prefix of the Image Template to create.') +param imageTemplateName string + +@description('Generated. Do not provide a value! This date value is used to generate a unique image template name.') +param baseTime string = utcNow('yyyy-MM-dd-HH-mm-ss') + +@description('Required. The name of the Deployment Script to create for triggering the image creation.') +param triggerImageDeploymentScriptName string + +@description('Required. The name of the Deployment Script to copy the VHD to a destination storage account.') +param copyVhdDeploymentScriptName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: storageAccountName + location: location + kind: 'StorageV2' + sku: { + name: 'Standard_LRS' + } + properties: { + allowBlobPublicAccess: false + } + resource blobServices 'blobServices@2022-09-01' = { + name: 'default' + resource container 'containers@2022-09-01' = { + name: 'vhds' + properties: { + publicAccess: 'None' + } + } + } +} + +module roleAssignment 'dependencies_rbac.bicep' = { + name: '${deployment().name}-MSI-roleAssignment' + scope: subscription() + params: { + managedIdentityPrincipalId: managedIdentity.properties.principalId + managedIdentityResourceId: managedIdentity.id + } +} + +// Deploy image template +resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2022-02-14' = { + name: imageTemplateName + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + buildTimeoutInMinutes: 0 + vmProfile: { + vmSize: 'Standard_D2s_v3' + osDiskSizeGB: 127 + } + source: { + type: 'PlatformImage' + publisher: 'MicrosoftWindowsDesktop' + offer: 'Windows-11' + sku: 'win11-21h2-avd' + version: 'latest' + } + distribute: [ + { + type: 'VHD' + runOutputName: '${imageTemplateName}-VHD' + artifactTags: {} + } + ] + customize: [ + { + restartTimeout: '30m' + type: 'WindowsRestart' + } + ] + } +} + +// Trigger VHD creation +resource triggerImageDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: triggerImageDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '11.5' + retentionInterval: 'P1D' + arguments: '-ImageTemplateName \\"${imageTemplate.name}\\" -ImageTemplateResourceGroup \\"${resourceGroup().name}\\"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Start-ImageTemplate.ps1') + cleanupPreference: 'OnSuccess' + forceUpdateTag: baseTime + } + dependsOn: [ + roleAssignment + ] +} + +// Copy VHD to destination storage account +resource copyVhdDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: copyVhdDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '11.5' + retentionInterval: 'P1D' + arguments: '-ImageTemplateName \\"${imageTemplate.name}\\" -ImageTemplateResourceGroup \\"${resourceGroup().name}\\" -DestinationStorageAccountName \\"${storageAccount.name}\\" -VhdName \\"${imageTemplateName}\\" -WaitForComplete' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Copy-VhdToStorageAccount.ps1') + cleanupPreference: 'OnSuccess' + forceUpdateTag: baseTime + } + dependsOn: [triggerImageDeploymentScript] +} + +@description('The URI of the created VHD.') +output vhdUri string = 'https://${storageAccount.name}.blob.${environment().suffixes.storage}/vhds/${imageTemplateName}.vhd' + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/avm/1.1.0/res/compute/disk/tests/e2e/import/dependencies_rbac.bicep b/avm/1.1.0/res/compute/disk/tests/e2e/import/dependencies_rbac.bicep new file mode 100644 index 000000000..f28142392 --- /dev/null +++ b/avm/1.1.0/res/compute/disk/tests/e2e/import/dependencies_rbac.bicep @@ -0,0 +1,19 @@ +targetScope = 'subscription' + +@description('Required. The resource ID of the created Managed Identity.') +param managedIdentityResourceId string + +@description('Required. The principal ID of the created Managed Identity.') +param managedIdentityPrincipalId string + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().subscriptionId, 'Contributor', managedIdentityResourceId) + properties: { + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalId: managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } +} diff --git a/avm/1.1.0/res/compute/disk/tests/e2e/import/main.test.bicep b/avm/1.1.0/res/compute/disk/tests/e2e/import/main.test.bicep new file mode 100644 index 000000000..79fe97f09 --- /dev/null +++ b/avm/1.1.0/res/compute/disk/tests/e2e/import/main.test.bicep @@ -0,0 +1,68 @@ +targetScope = 'subscription' + +metadata name = 'Using an imported image' +metadata description = 'This instance deploys the module with a custom image that is imported from a VHD in a storage account.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.disks-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cdimp' + +@description('Generated. Do not provide a value! This date value is used to generate a unique image template name as the resource is not idempotent.') +param uniqueBaseTime string = utcNow('yyyy-MM-dd-HH-mm-ss') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + storageAccountName: 'dep${namePrefix}sa${serviceShort}01' + imageTemplateName: 'dep-${namePrefix}-imgt-${serviceShort}-${uniqueString(uniqueBaseTime)}' + triggerImageDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}-triggerImageTemplate' + copyVhdDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}-copyVhdToStorage' + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}-${serviceShort}001' + location: resourceLocation + sku: 'Standard_LRS' + availabilityZone: 0 + createOption: 'Import' + sourceUri: nestedDependencies.outputs.vhdUri + storageAccountId: nestedDependencies.outputs.storageAccountResourceId + } + } +] diff --git a/avm/1.1.0/res/compute/disk/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/compute/disk/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..2c8183e72 --- /dev/null +++ b/avm/1.1.0/res/compute/disk/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created managed identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/compute/disk/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/compute/disk/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..ac334cb1e --- /dev/null +++ b/avm/1.1.0/res/compute/disk/tests/e2e/max/main.test.bicep @@ -0,0 +1,95 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.disks-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cdmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}-${serviceShort}001' + location: resourceLocation + sku: 'Premium_LRS' + availabilityZone: 2 + diskIOPSReadWrite: 500 + diskMBpsReadWrite: 60 + diskSizeGB: 128 + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + logicalSectorSize: 512 + osType: 'Windows' + publicNetworkAccess: 'Enabled' + roleAssignments: [ + { + name: '89cc419c-8383-461d-9a70-5cfae4045a8d' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/compute/disk/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/compute/disk/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..52e752175 --- /dev/null +++ b/avm/1.1.0/res/compute/disk/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,64 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.disks-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cdwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}-${serviceShort}001' + location: resourceLocation + sku: 'Premium_LRS' + availabilityZone: 2 + diskIOPSReadWrite: 500 + diskMBpsReadWrite: 60 + diskSizeGB: 128 + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + logicalSectorSize: 512 + osType: 'Windows' + publicNetworkAccess: 'Enabled' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/compute/disk/version.json b/avm/1.1.0/res/compute/disk/version.json new file mode 100644 index 000000000..3f863a2be --- /dev/null +++ b/avm/1.1.0/res/compute/disk/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.4", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/gallery/README.md b/avm/1.1.0/res/compute/gallery/README.md new file mode 100644 index 000000000..9427470e2 --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/README.md @@ -0,0 +1,1830 @@ +# Azure Compute Galleries `[Microsoft.Compute/galleries]` + +This module deploys an Azure Compute Gallery (formerly known as Shared Image Gallery). + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Compute/galleries` | [2024-03-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-03-03/galleries) | +| `Microsoft.Compute/galleries/applications` | [2024-03-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-03-03/galleries/applications) | +| `Microsoft.Compute/galleries/images` | [2024-03-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-03-03/galleries/images) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/compute/gallery:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module gallery 'br/public:avm/res/compute/gallery:' = { + name: 'galleryDeployment' + params: { + // Required parameters + name: 'cgmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "cgmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/gallery:' + +// Required parameters +param name = 'cgmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module gallery 'br/public:avm/res/compute/gallery:' = { + name: 'galleryDeployment' + params: { + // Required parameters + name: 'cgmax001' + // Non-required parameters + applications: [ + { + name: 'cgmax-appd-001' + supportedOSType: 'Linux' + } + { + name: 'cgmax-appd-002' + roleAssignments: [ + { + name: '4ef8d3d3-54be-4522-92c3-284977292d87' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + supportedOSType: 'Windows' + } + ] + description: 'This is a test deployment.' + images: [ + { + allowUpdateImage: true + architecture: 'x64' + description: 'testDescription' + endOfLife: '2033-01-01' + eula: 'test Eula' + excludedDiskTypes: [ + 'Standard_LRS' + ] + hyperVGeneration: 'V1' + identifier: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + } + name: 'az-imgd-ws-001' + osState: 'Generalized' + osType: 'Windows' + privacyStatementUri: 'https://testPrivacyStatementUri.com' + purchasePlan: { + name: 'testPlanName1' + product: 'testProduct1' + publisher: 'testPublisher1' + } + releaseNoteUri: 'https://testReleaseNoteUri.com' + } + { + allowUpdateImage: false + hyperVGeneration: 'V2' + identifier: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition-hibernate' + } + isAcceleratedNetworkSupported: false + isHibernateSupported: true + memory: { + max: 16 + min: 4 + } + name: 'az-imgd-ws-002' + osState: 'Generalized' + osType: 'Windows' + vCPUs: { + max: 8 + min: 2 + } + } + { + hyperVGeneration: 'V2' + identifier: { + offer: 'WindowsDesktop' + publisher: 'MicrosoftWindowsDesktop' + sku: 'Win11-21H2' + } + memory: { + max: 16 + min: 4 + } + name: 'az-imgd-wdtl-003' + osState: 'Generalized' + osType: 'Windows' + purchasePlan: { + name: 'testPlanName' + product: 'testProduct' + publisher: 'testPublisher' + } + securityType: 'Standard' + vCPUs: { + max: 8 + min: 2 + } + } + { + diskControllerType: 'SCSI' + hyperVGeneration: 'V2' + identifier: { + offer: '0001-com-ubuntu-minimal-focal' + publisher: 'canonical' + sku: '22_04-lts-gen2' + } + isAcceleratedNetworkSupported: false + memory: { + max: 32 + min: 4 + } + name: 'az-imgd-us-004' + osState: 'Generalized' + osType: 'Linux' + vCPUs: { + max: 4 + min: 1 + } + } + { + diskControllerType: 'SCSI, NVMe' + hyperVGeneration: 'V2' + identifier: { + offer: '0001-com-ubuntu-minimal-focal' + publisher: 'canonical' + sku: '20_04-lts-gen2' + } + isAcceleratedNetworkSupported: true + memory: { + max: 32 + min: 4 + } + name: 'az-imgd-us-005' + osState: 'Generalized' + osType: 'Linux' + vCPUs: { + max: 4 + min: 1 + } + } + { + architecture: 'x64' + description: 'testDescription' + endOfLife: '2033-01-01' + eula: 'test Eula' + excludedDiskTypes: [ + 'Standard_LRS' + ] + hyperVGeneration: 'V2' + identifier: { + offer: '0001-com-ubuntu-server-focal' + publisher: 'canonical' + sku: '20_04-lts-gen2' + } + isAcceleratedNetworkSupported: false + isHibernateSupported: true + memory: { + max: 32 + min: 4 + } + name: 'az-imgd-us-006' + osState: 'Generalized' + osType: 'Linux' + privacyStatementUri: 'https://testPrivacyStatementUri.com' + purchasePlan: { + name: 'testPlanName' + product: 'testProduct' + publisher: 'testPublisher' + } + releaseNoteUri: 'https://testReleaseNoteUri.com' + securityType: 'TrustedLaunch' + vCPUs: { + max: 4 + min: 1 + } + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '3bd58a78-108d-4f87-b404-0a03e49303d8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "cgmax001" + }, + // Non-required parameters + "applications": { + "value": [ + { + "name": "cgmax-appd-001", + "supportedOSType": "Linux" + }, + { + "name": "cgmax-appd-002", + "roleAssignments": [ + { + "name": "4ef8d3d3-54be-4522-92c3-284977292d87", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "supportedOSType": "Windows" + } + ] + }, + "description": { + "value": "This is a test deployment." + }, + "images": { + "value": [ + { + "allowUpdateImage": true, + "architecture": "x64", + "description": "testDescription", + "endOfLife": "2033-01-01", + "eula": "test Eula", + "excludedDiskTypes": [ + "Standard_LRS" + ], + "hyperVGeneration": "V1", + "identifier": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition" + }, + "name": "az-imgd-ws-001", + "osState": "Generalized", + "osType": "Windows", + "privacyStatementUri": "https://testPrivacyStatementUri.com", + "purchasePlan": { + "name": "testPlanName1", + "product": "testProduct1", + "publisher": "testPublisher1" + }, + "releaseNoteUri": "https://testReleaseNoteUri.com" + }, + { + "allowUpdateImage": false, + "hyperVGeneration": "V2", + "identifier": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition-hibernate" + }, + "isAcceleratedNetworkSupported": false, + "isHibernateSupported": true, + "memory": { + "max": 16, + "min": 4 + }, + "name": "az-imgd-ws-002", + "osState": "Generalized", + "osType": "Windows", + "vCPUs": { + "max": 8, + "min": 2 + } + }, + { + "hyperVGeneration": "V2", + "identifier": { + "offer": "WindowsDesktop", + "publisher": "MicrosoftWindowsDesktop", + "sku": "Win11-21H2" + }, + "memory": { + "max": 16, + "min": 4 + }, + "name": "az-imgd-wdtl-003", + "osState": "Generalized", + "osType": "Windows", + "purchasePlan": { + "name": "testPlanName", + "product": "testProduct", + "publisher": "testPublisher" + }, + "securityType": "Standard", + "vCPUs": { + "max": 8, + "min": 2 + } + }, + { + "diskControllerType": "SCSI", + "hyperVGeneration": "V2", + "identifier": { + "offer": "0001-com-ubuntu-minimal-focal", + "publisher": "canonical", + "sku": "22_04-lts-gen2" + }, + "isAcceleratedNetworkSupported": false, + "memory": { + "max": 32, + "min": 4 + }, + "name": "az-imgd-us-004", + "osState": "Generalized", + "osType": "Linux", + "vCPUs": { + "max": 4, + "min": 1 + } + }, + { + "diskControllerType": "SCSI, NVMe", + "hyperVGeneration": "V2", + "identifier": { + "offer": "0001-com-ubuntu-minimal-focal", + "publisher": "canonical", + "sku": "20_04-lts-gen2" + }, + "isAcceleratedNetworkSupported": true, + "memory": { + "max": 32, + "min": 4 + }, + "name": "az-imgd-us-005", + "osState": "Generalized", + "osType": "Linux", + "vCPUs": { + "max": 4, + "min": 1 + } + }, + { + "architecture": "x64", + "description": "testDescription", + "endOfLife": "2033-01-01", + "eula": "test Eula", + "excludedDiskTypes": [ + "Standard_LRS" + ], + "hyperVGeneration": "V2", + "identifier": { + "offer": "0001-com-ubuntu-server-focal", + "publisher": "canonical", + "sku": "20_04-lts-gen2" + }, + "isAcceleratedNetworkSupported": false, + "isHibernateSupported": true, + "memory": { + "max": 32, + "min": 4 + }, + "name": "az-imgd-us-006", + "osState": "Generalized", + "osType": "Linux", + "privacyStatementUri": "https://testPrivacyStatementUri.com", + "purchasePlan": { + "name": "testPlanName", + "product": "testProduct", + "publisher": "testPublisher" + }, + "releaseNoteUri": "https://testReleaseNoteUri.com", + "securityType": "TrustedLaunch", + "vCPUs": { + "max": 4, + "min": 1 + } + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "3bd58a78-108d-4f87-b404-0a03e49303d8", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/gallery:' + +// Required parameters +param name = 'cgmax001' +// Non-required parameters +param applications = [ + { + name: 'cgmax-appd-001' + supportedOSType: 'Linux' + } + { + name: 'cgmax-appd-002' + roleAssignments: [ + { + name: '4ef8d3d3-54be-4522-92c3-284977292d87' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + supportedOSType: 'Windows' + } +] +param description = 'This is a test deployment.' +param images = [ + { + allowUpdateImage: true + architecture: 'x64' + description: 'testDescription' + endOfLife: '2033-01-01' + eula: 'test Eula' + excludedDiskTypes: [ + 'Standard_LRS' + ] + hyperVGeneration: 'V1' + identifier: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + } + name: 'az-imgd-ws-001' + osState: 'Generalized' + osType: 'Windows' + privacyStatementUri: 'https://testPrivacyStatementUri.com' + purchasePlan: { + name: 'testPlanName1' + product: 'testProduct1' + publisher: 'testPublisher1' + } + releaseNoteUri: 'https://testReleaseNoteUri.com' + } + { + allowUpdateImage: false + hyperVGeneration: 'V2' + identifier: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition-hibernate' + } + isAcceleratedNetworkSupported: false + isHibernateSupported: true + memory: { + max: 16 + min: 4 + } + name: 'az-imgd-ws-002' + osState: 'Generalized' + osType: 'Windows' + vCPUs: { + max: 8 + min: 2 + } + } + { + hyperVGeneration: 'V2' + identifier: { + offer: 'WindowsDesktop' + publisher: 'MicrosoftWindowsDesktop' + sku: 'Win11-21H2' + } + memory: { + max: 16 + min: 4 + } + name: 'az-imgd-wdtl-003' + osState: 'Generalized' + osType: 'Windows' + purchasePlan: { + name: 'testPlanName' + product: 'testProduct' + publisher: 'testPublisher' + } + securityType: 'Standard' + vCPUs: { + max: 8 + min: 2 + } + } + { + diskControllerType: 'SCSI' + hyperVGeneration: 'V2' + identifier: { + offer: '0001-com-ubuntu-minimal-focal' + publisher: 'canonical' + sku: '22_04-lts-gen2' + } + isAcceleratedNetworkSupported: false + memory: { + max: 32 + min: 4 + } + name: 'az-imgd-us-004' + osState: 'Generalized' + osType: 'Linux' + vCPUs: { + max: 4 + min: 1 + } + } + { + diskControllerType: 'SCSI, NVMe' + hyperVGeneration: 'V2' + identifier: { + offer: '0001-com-ubuntu-minimal-focal' + publisher: 'canonical' + sku: '20_04-lts-gen2' + } + isAcceleratedNetworkSupported: true + memory: { + max: 32 + min: 4 + } + name: 'az-imgd-us-005' + osState: 'Generalized' + osType: 'Linux' + vCPUs: { + max: 4 + min: 1 + } + } + { + architecture: 'x64' + description: 'testDescription' + endOfLife: '2033-01-01' + eula: 'test Eula' + excludedDiskTypes: [ + 'Standard_LRS' + ] + hyperVGeneration: 'V2' + identifier: { + offer: '0001-com-ubuntu-server-focal' + publisher: 'canonical' + sku: '20_04-lts-gen2' + } + isAcceleratedNetworkSupported: false + isHibernateSupported: true + memory: { + max: 32 + min: 4 + } + name: 'az-imgd-us-006' + osState: 'Generalized' + osType: 'Linux' + privacyStatementUri: 'https://testPrivacyStatementUri.com' + purchasePlan: { + name: 'testPlanName' + product: 'testProduct' + publisher: 'testPublisher' + } + releaseNoteUri: 'https://testReleaseNoteUri.com' + securityType: 'TrustedLaunch' + vCPUs: { + max: 4 + min: 1 + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '3bd58a78-108d-4f87-b404-0a03e49303d8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module gallery 'br/public:avm/res/compute/gallery:' = { + name: 'galleryDeployment' + params: { + // Required parameters + name: 'cgwaf001' + // Non-required parameters + applications: [ + { + name: 'cgwaf-appd-001' + supportedOSType: 'Windows' + } + ] + images: [ + { + identifier: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + } + name: 'az-imgd-ws-001' + osState: 'Generalized' + osType: 'Windows' + } + ] + location: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "cgwaf001" + }, + // Non-required parameters + "applications": { + "value": [ + { + "name": "cgwaf-appd-001", + "supportedOSType": "Windows" + } + ] + }, + "images": { + "value": [ + { + "identifier": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition" + }, + "name": "az-imgd-ws-001", + "osState": "Generalized", + "osType": "Windows" + } + ] + }, + "location": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/gallery:' + +// Required parameters +param name = 'cgwaf001' +// Non-required parameters +param applications = [ + { + name: 'cgwaf-appd-001' + supportedOSType: 'Windows' + } +] +param images = [ + { + identifier: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + } + name: 'az-imgd-ws-001' + osState: 'Generalized' + osType: 'Windows' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Azure Compute Gallery. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applications`](#parameter-applications) | array | Applications to create. | +| [`description`](#parameter-description) | string | Description of the Azure Shared Image Gallery. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`images`](#parameter-images) | array | Images to create. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`sharingProfile`](#parameter-sharingprofile) | object | Profile for gallery sharing to subscription or tenant. | +| [`softDeletePolicy`](#parameter-softdeletepolicy) | object | Soft deletion policy of the gallery. | +| [`tags`](#parameter-tags) | object | Tags for all resources. | + +### Parameter: `name` + +Name of the Azure Compute Gallery. + +- Required: Yes +- Type: string + +### Parameter: `applications` + +Applications to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-applicationsname) | string | Name of the application definition. | +| [`supportedOSType`](#parameter-applicationssupportedostype) | string | The OS type of the application. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`customActions`](#parameter-applicationscustomactions) | array | A list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application. | +| [`description`](#parameter-applicationsdescription) | string | The description of this gallery application definition resource. This property is updatable. | +| [`endOfLifeDate`](#parameter-applicationsendoflifedate) | string | The end of life date of the gallery application definition. This property can be used for decommissioning purposes. This property is updatable. | +| [`eula`](#parameter-applicationseula) | string | The Eula agreement for the gallery application definition. | +| [`privacyStatementUri`](#parameter-applicationsprivacystatementuri) | string | The privacy statement uri. | +| [`releaseNoteUri`](#parameter-applicationsreleasenoteuri) | string | The release note uri. Has to be a valid URL. | +| [`roleAssignments`](#parameter-applicationsroleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-applicationstags) | object | Tags for all resources. | + +### Parameter: `applications.name` + +Name of the application definition. + +- Required: Yes +- Type: string + +### Parameter: `applications.supportedOSType` + +The OS type of the application. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `applications.customActions` + +A list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-applicationscustomactionsname) | string | The name of the custom action. Must be unique within the Gallery Application Version. | +| [`script`](#parameter-applicationscustomactionsscript) | string | The script to run when executing this custom action. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-applicationscustomactionsdescription) | string | Description to help the users understand what this custom action does. | +| [`parameters`](#parameter-applicationscustomactionsparameters) | array | The parameters that this custom action uses. | + +### Parameter: `applications.customActions.name` + +The name of the custom action. Must be unique within the Gallery Application Version. + +- Required: Yes +- Type: string + +### Parameter: `applications.customActions.script` + +The script to run when executing this custom action. + +- Required: Yes +- Type: string + +### Parameter: `applications.customActions.description` + +Description to help the users understand what this custom action does. + +- Required: No +- Type: string + +### Parameter: `applications.customActions.parameters` + +The parameters that this custom action uses. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-applicationscustomactionsparametersname) | string | The name of the parameter. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`defaultValue`](#parameter-applicationscustomactionsparametersdefaultvalue) | string | The default value of the parameter. Only applies to string types. | +| [`description`](#parameter-applicationscustomactionsparametersdescription) | string | A description to help users understand what this parameter means. | +| [`required`](#parameter-applicationscustomactionsparametersrequired) | bool | Indicates whether this parameter must be passed when running the custom action. | +| [`type`](#parameter-applicationscustomactionsparameterstype) | string | Specifies the type of the custom action parameter. | + +### Parameter: `applications.customActions.parameters.name` + +The name of the parameter. + +- Required: Yes +- Type: string + +### Parameter: `applications.customActions.parameters.defaultValue` + +The default value of the parameter. Only applies to string types. + +- Required: No +- Type: string + +### Parameter: `applications.customActions.parameters.description` + +A description to help users understand what this parameter means. + +- Required: No +- Type: string + +### Parameter: `applications.customActions.parameters.required` + +Indicates whether this parameter must be passed when running the custom action. + +- Required: No +- Type: bool + +### Parameter: `applications.customActions.parameters.type` + +Specifies the type of the custom action parameter. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'ConfigurationDataBlob' + 'LogOutputBlob' + 'String' + ] + ``` + +### Parameter: `applications.description` + +The description of this gallery application definition resource. This property is updatable. + +- Required: No +- Type: string + +### Parameter: `applications.endOfLifeDate` + +The end of life date of the gallery application definition. This property can be used for decommissioning purposes. This property is updatable. + +- Required: No +- Type: string + +### Parameter: `applications.eula` + +The Eula agreement for the gallery application definition. + +- Required: No +- Type: string + +### Parameter: `applications.privacyStatementUri` + +The privacy statement uri. + +- Required: No +- Type: string + +### Parameter: `applications.releaseNoteUri` + +The release note uri. Has to be a valid URL. + +- Required: No +- Type: string + +### Parameter: `applications.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Compute Gallery Sharing Admin'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-applicationsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-applicationsroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-applicationsroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-applicationsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-applicationsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-applicationsroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-applicationsroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-applicationsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `applications.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `applications.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `applications.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `applications.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `applications.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `applications.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `applications.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `applications.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `applications.tags` + +Tags for all resources. + +- Required: No +- Type: object + +### Parameter: `description` + +Description of the Azure Shared Image Gallery. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `images` + +Images to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`identifier`](#parameter-imagesidentifier) | object | This is the gallery image definition identifier. | +| [`name`](#parameter-imagesname) | string | Name of the image definition. | +| [`osState`](#parameter-imagesosstate) | string | This property allows the user to specify the state of the OS of the image. | +| [`osType`](#parameter-imagesostype) | string | This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowUpdateImage`](#parameter-imagesallowupdateimage) | bool | Must be set to true if the gallery image features are being updated. | +| [`architecture`](#parameter-imagesarchitecture) | string | The architecture of the image. Applicable to OS disks only. | +| [`description`](#parameter-imagesdescription) | string | The description of this gallery image definition resource. This property is updatable. | +| [`diskControllerType`](#parameter-imagesdiskcontrollertype) | string | The disk controllers that an OS disk supports. | +| [`endOfLife`](#parameter-imagesendoflife) | string | The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable. | +| [`eula`](#parameter-imageseula) | string | The Eula agreement for the gallery image definition. | +| [`excludedDiskTypes`](#parameter-imagesexcludeddisktypes) | array | Describes the disallowed disk types. | +| [`hyperVGeneration`](#parameter-imageshypervgeneration) | string | The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1. | +| [`isAcceleratedNetworkSupported`](#parameter-imagesisacceleratednetworksupported) | bool | Specify if the image supports accelerated networking. Defaults to true. | +| [`isHibernateSupported`](#parameter-imagesishibernatesupported) | bool | Specify if the image supports hibernation. | +| [`memory`](#parameter-imagesmemory) | object | Describes the resource range (1-4000 GB RAM). Defaults to min=4, max=16. | +| [`privacyStatementUri`](#parameter-imagesprivacystatementuri) | string | The privacy statement uri. | +| [`purchasePlan`](#parameter-imagespurchaseplan) | object | Describes the gallery image definition purchase plan. This is used by marketplace images. | +| [`releaseNoteUri`](#parameter-imagesreleasenoteuri) | string | The release note uri. Has to be a valid URL. | +| [`securityType`](#parameter-imagessecuritytype) | string | The security type of the image. Requires a hyperVGeneration V2. Defaults to `Standard`. | +| [`vCPUs`](#parameter-imagesvcpus) | object | Describes the resource range (1-128 CPU cores). Defaults to min=1, max=4. | + +### Parameter: `images.identifier` + +This is the gallery image definition identifier. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`offer`](#parameter-imagesidentifieroffer) | string | The name of the gallery image definition offer. | +| [`publisher`](#parameter-imagesidentifierpublisher) | string | The name of the gallery image definition publisher. | +| [`sku`](#parameter-imagesidentifiersku) | string | The name of the gallery image definition SKU. | + +### Parameter: `images.identifier.offer` + +The name of the gallery image definition offer. + +- Required: Yes +- Type: string + +### Parameter: `images.identifier.publisher` + +The name of the gallery image definition publisher. + +- Required: Yes +- Type: string + +### Parameter: `images.identifier.sku` + +The name of the gallery image definition SKU. + +- Required: Yes +- Type: string + +### Parameter: `images.name` + +Name of the image definition. + +- Required: Yes +- Type: string + +### Parameter: `images.osState` + +This property allows the user to specify the state of the OS of the image. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Generalized' + 'Specialized' + ] + ``` + +### Parameter: `images.osType` + +This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `images.allowUpdateImage` + +Must be set to true if the gallery image features are being updated. + +- Required: No +- Type: bool + +### Parameter: `images.architecture` + +The architecture of the image. Applicable to OS disks only. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Arm64' + 'x64' + ] + ``` + +### Parameter: `images.description` + +The description of this gallery image definition resource. This property is updatable. + +- Required: No +- Type: string + +### Parameter: `images.diskControllerType` + +The disk controllers that an OS disk supports. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'NVMe, SCSI' + 'SCSI' + 'SCSI, NVMe' + ] + ``` + +### Parameter: `images.endOfLife` + +The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable. + +- Required: No +- Type: string + +### Parameter: `images.eula` + +The Eula agreement for the gallery image definition. + +- Required: No +- Type: string + +### Parameter: `images.excludedDiskTypes` + +Describes the disallowed disk types. + +- Required: No +- Type: array + +### Parameter: `images.hyperVGeneration` + +The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'V1' + 'V2' + ] + ``` + +### Parameter: `images.isAcceleratedNetworkSupported` + +Specify if the image supports accelerated networking. Defaults to true. + +- Required: No +- Type: bool + +### Parameter: `images.isHibernateSupported` + +Specify if the image supports hibernation. + +- Required: No +- Type: bool + +### Parameter: `images.memory` + +Describes the resource range (1-4000 GB RAM). Defaults to min=4, max=16. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`max`](#parameter-imagesmemorymax) | int | The minimum number of the resource. | +| [`min`](#parameter-imagesmemorymin) | int | The minimum number of the resource. | + +### Parameter: `images.memory.max` + +The minimum number of the resource. + +- Required: No +- Type: int + +### Parameter: `images.memory.min` + +The minimum number of the resource. + +- Required: No +- Type: int +- MinValue: 1 + +### Parameter: `images.privacyStatementUri` + +The privacy statement uri. + +- Required: No +- Type: string + +### Parameter: `images.purchasePlan` + +Describes the gallery image definition purchase plan. This is used by marketplace images. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-imagespurchaseplanname) | string | The plan ID. | +| [`product`](#parameter-imagespurchaseplanproduct) | string | The product ID. | +| [`publisher`](#parameter-imagespurchaseplanpublisher) | string | The publisher ID. | + +### Parameter: `images.purchasePlan.name` + +The plan ID. + +- Required: Yes +- Type: string + +### Parameter: `images.purchasePlan.product` + +The product ID. + +- Required: Yes +- Type: string + +### Parameter: `images.purchasePlan.publisher` + +The publisher ID. + +- Required: Yes +- Type: string + +### Parameter: `images.releaseNoteUri` + +The release note uri. Has to be a valid URL. + +- Required: No +- Type: string + +### Parameter: `images.securityType` + +The security type of the image. Requires a hyperVGeneration V2. Defaults to `Standard`. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'ConfidentialVM' + 'ConfidentialVMSupported' + 'Standard' + 'TrustedLaunch' + 'TrustedLaunchAndConfidentialVmSupported' + 'TrustedLaunchSupported' + ] + ``` + +### Parameter: `images.vCPUs` + +Describes the resource range (1-128 CPU cores). Defaults to min=1, max=4. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`max`](#parameter-imagesvcpusmax) | int | The minimum number of the resource. | +| [`min`](#parameter-imagesvcpusmin) | int | The minimum number of the resource. | + +### Parameter: `images.vCPUs.max` + +The minimum number of the resource. + +- Required: No +- Type: int + +### Parameter: `images.vCPUs.min` + +The minimum number of the resource. + +- Required: No +- Type: int +- MinValue: 1 + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Compute Gallery Sharing Admin'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `sharingProfile` + +Profile for gallery sharing to subscription or tenant. + +- Required: No +- Type: object + +### Parameter: `softDeletePolicy` + +Soft deletion policy of the gallery. + +- Required: No +- Type: object + +### Parameter: `tags` + +Tags for all resources. + +- Required: No +- Type: object +- Example: + ```Bicep + { + key1: 'value1' + key2: 'value2' + } + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `imageResourceIds` | array | The resource ids of the deployed images. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed image gallery. | +| `resourceGroupName` | string | The resource group of the deployed image gallery. | +| `resourceId` | string | The resource ID of the deployed image gallery. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.3.0` | Remote reference | + +## Notes + +Currently it is not possible to redeploy the `image.diskControllerType` property with a value of `NVMe, SCSI`. The initial deployment is working, but other deployments will result in an error. + +```json +"details": [ + { + "code": "PropertyChangeNotAllowed", + "target": "DiskControllerTypes", + "message": "Changing property 'DiskControllerTypes' is not allowed." + } + ] +``` + +Once this bug has been resolved, the max test will be updated to deploy an image with the property value. + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/compute/gallery/application/README.md b/avm/1.1.0/res/compute/gallery/application/README.md new file mode 100644 index 000000000..80c590cb8 --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/application/README.md @@ -0,0 +1,454 @@ +# Compute Galleries Applications `[Microsoft.Compute/galleries/applications]` + +This module deploys an Azure Compute Gallery Application. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Compute/galleries/applications` | [2024-03-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-03-03/galleries/applications) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the application definition. | +| [`supportedOSType`](#parameter-supportedostype) | string | This property allows you to specify the supported type of the OS that application is built for. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`galleryName`](#parameter-galleryname) | string | The name of the parent Azure Compute Gallery. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`customActions`](#parameter-customactions) | array | A list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application. | +| [`description`](#parameter-description) | string | The description of this gallery Application Definition resource. This property is updatable. | +| [`endOfLifeDate`](#parameter-endoflifedate) | string | The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z. | +| [`eula`](#parameter-eula) | string | The Eula agreement for the gallery Application Definition. Has to be a valid URL. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`privacyStatementUri`](#parameter-privacystatementuri) | string | The privacy statement uri. Has to be a valid URL. | +| [`releaseNoteUri`](#parameter-releasenoteuri) | string | The release note uri. Has to be a valid URL. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags for all resources. | + +### Parameter: `name` + +Name of the application definition. + +- Required: Yes +- Type: string + +### Parameter: `supportedOSType` + +This property allows you to specify the supported type of the OS that application is built for. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `galleryName` + +The name of the parent Azure Compute Gallery. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `customActions` + +A list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-customactionsname) | string | The name of the custom action. Must be unique within the Gallery Application Version. | +| [`script`](#parameter-customactionsscript) | string | The script to run when executing this custom action. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-customactionsdescription) | string | Description to help the users understand what this custom action does. | +| [`parameters`](#parameter-customactionsparameters) | array | The parameters that this custom action uses. | + +### Parameter: `customActions.name` + +The name of the custom action. Must be unique within the Gallery Application Version. + +- Required: Yes +- Type: string + +### Parameter: `customActions.script` + +The script to run when executing this custom action. + +- Required: Yes +- Type: string + +### Parameter: `customActions.description` + +Description to help the users understand what this custom action does. + +- Required: No +- Type: string + +### Parameter: `customActions.parameters` + +The parameters that this custom action uses. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-customactionsparametersname) | string | The name of the parameter. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`defaultValue`](#parameter-customactionsparametersdefaultvalue) | string | The default value of the parameter. Only applies to string types. | +| [`description`](#parameter-customactionsparametersdescription) | string | A description to help users understand what this parameter means. | +| [`required`](#parameter-customactionsparametersrequired) | bool | Indicates whether this parameter must be passed when running the custom action. | +| [`type`](#parameter-customactionsparameterstype) | string | Specifies the type of the custom action parameter. | + +### Parameter: `customActions.parameters.name` + +The name of the parameter. + +- Required: Yes +- Type: string + +### Parameter: `customActions.parameters.defaultValue` + +The default value of the parameter. Only applies to string types. + +- Required: No +- Type: string + +### Parameter: `customActions.parameters.description` + +A description to help users understand what this parameter means. + +- Required: No +- Type: string + +### Parameter: `customActions.parameters.required` + +Indicates whether this parameter must be passed when running the custom action. + +- Required: No +- Type: bool + +### Parameter: `customActions.parameters.type` + +Specifies the type of the custom action parameter. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'ConfigurationDataBlob' + 'LogOutputBlob' + 'String' + ] + ``` + +### Parameter: `description` + +The description of this gallery Application Definition resource. This property is updatable. + +- Required: No +- Type: string + +### Parameter: `endOfLifeDate` + +The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z. + +- Required: No +- Type: string + +### Parameter: `eula` + +The Eula agreement for the gallery Application Definition. Has to be a valid URL. + +- Required: No +- Type: string + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `privacyStatementUri` + +The privacy statement uri. Has to be a valid URL. + +- Required: No +- Type: string + +### Parameter: `releaseNoteUri` + +The release note uri. Has to be a valid URL. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Compute Gallery Sharing Admin'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags for all resources. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the image. | +| `resourceGroupName` | string | The resource group the image was deployed into. | +| `resourceId` | string | The resource ID of the image. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.3.0` | Remote reference | + +## Notes + +### Parameter Usage: `customActions` + +Create a list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application. + +

+ +Parameter JSON format + +```json +"customActions": { + "value": [ + { + "description": "This is a sample custom action", + "name": "Name of the custom action 1 (Required). Must be unique within the Compute Gallery", + "parameters": [ + { + "defaultValue": "Default Value of Parameter1. Only applies to string types.", + "description": "a description value to help others understands what it means.", + "name": "The parameter name. (Required)", + "required": True, + "type": "ConfigurationDataBlob, LogOutputBlob, or String" + }, + { + "defaultValue": "Default Value of Parameter2. Only applies to string types.", + "description": "a description value to help others understands what it means.", + "name": "The parameter name. (Required)", + "required": False, + "type": "ConfigurationDataBlob, LogOutputBlob, or String" + } + ], + "script": "The script to run when executing this custom action. (Required)" + }, + { + "description": "This is another sample custom action", + "name": "Name of the custom action 2 (Required). Must be unique within the Compute Gallery", + "parameters": [ + { + "defaultValue": "Default Value of Parameter1. Only applies to string types.", + "description": "a description value to help others understands what it means.", + "name": "The parameter name. (Required)", + "required": True, + "type": "ConfigurationDataBlob, LogOutputBlob, or String" + } + ], + "script": "The script to run when executing this custom action. (Required)" + } + ] +} +``` + +
+ +
+ +Bicep format + +```bicep +customActions: [ + { + description: "This is a sample custom action" + name: "Name of the custom action 1 (Required). Must be unique within the Compute Gallery" + parameters: [ + { + defaultValue: "Default Value of Parameter 1. Only applies to string types." + description: "a description value to help others understands what it means." + name: "The parameter name. (Required)" + required: True, + type: "ConfigurationDataBlob, LogOutputBlob, or String" + } + { + defaultValue: "Default Value of Parameter 2. Only applies to string types." + description: "a description value to help others understands what it means." + name: "The parameter name. (Required)" + required: True, + type: "ConfigurationDataBlob, LogOutputBlob, or String" + } + ] + script: "The script to run when executing this custom action. (Required)" + } + { + description: "This is another sample custom action" + name: "Name of the custom action 2 (Required). Must be unique within the Compute Gallery" + parameters: [ + { + defaultValue: "Default Value of Parameter. Only applies to string types." + description: "a description value to help others understands what it means." + name: "The paramter name. (Required)" + required: True, + type: "ConfigurationDataBlob, LogOutputBlob, or String" + } + ] + script: "The script to run when executing this custom action. (Required)" + } +] +``` + +
+

diff --git a/avm/1.1.0/res/compute/gallery/application/main.bicep b/avm/1.1.0/res/compute/gallery/application/main.bicep new file mode 100644 index 000000000..b8cddc851 --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/application/main.bicep @@ -0,0 +1,155 @@ +metadata name = 'Compute Galleries Applications' +metadata description = 'This module deploys an Azure Compute Gallery Application.' + +@sys.description('Required. Name of the application definition.') +param name string + +@sys.description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@sys.description('Conditional. The name of the parent Azure Compute Gallery. Required if the template is used in a standalone deployment.') +@minLength(1) +param galleryName string + +@sys.description('Optional. The description of this gallery Application Definition resource. This property is updatable.') +param description string? + +@sys.description('Optional. The Eula agreement for the gallery Application Definition. Has to be a valid URL.') +param eula string? + +@sys.description('Optional. The privacy statement uri. Has to be a valid URL.') +param privacyStatementUri string? + +@sys.description('Optional. The release note uri. Has to be a valid URL.') +param releaseNoteUri string? + +@sys.description('Required. This property allows you to specify the supported type of the OS that application is built for.') +@allowed([ + 'Windows' + 'Linux' +]) +param supportedOSType string + +@sys.description('Optional. The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z.') +param endOfLifeDate string? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.3.0' +@sys.description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@sys.description('Optional. Tags for all resources.') +param tags object? + +@sys.description('Optional. A list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application.') +param customActions customActionType[]? + +var builtInRoleNames = { + 'Compute Gallery Sharing Admin': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '1ef6a3be-d0ac-425d-8c01-acb62866290b' + ) + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource gallery 'Microsoft.Compute/galleries@2024-03-03' existing = { + name: galleryName +} + +resource application 'Microsoft.Compute/galleries/applications@2024-03-03' = { + name: name + parent: gallery + location: location + tags: tags + properties: { + customActions: customActions + description: description + endOfLifeDate: endOfLifeDate + eula: eula + privacyStatementUri: privacyStatementUri + releaseNoteUri: releaseNoteUri + supportedOSType: supportedOSType + } +} + +resource application_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(application.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: application + } +] + +@sys.description('The resource group the image was deployed into.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The resource ID of the image.') +output resourceId string = application.id + +@sys.description('The name of the image.') +output name string = application.name + +@sys.description('The location the resource was deployed into.') +output location string = application.location + +// =============== // +// Definitions // +// =============== // + +@export() +type customActionType = { + @sys.description('Required. The name of the custom action. Must be unique within the Gallery Application Version.') + name: string + + @sys.description('Required. The script to run when executing this custom action.') + script: string + + @sys.description('Optional. Description to help the users understand what this custom action does.') + description: string? + + @sys.description('Optional. The parameters that this custom action uses.') + parameters: { + @sys.description('Required. The name of the parameter.') + name: string + + @sys.description('Optional. Specifies the type of the custom action parameter.') + type: ('ConfigurationDataBlob' | 'LogOutputBlob' | 'String')? + + @sys.description('Optional. A description to help users understand what this parameter means.') + description: string? + + @sys.description('Optional. The default value of the parameter. Only applies to string types.') + defaultValue: string? + + @sys.description('Optional. Indicates whether this parameter must be passed when running the custom action.') + required: bool? + }[]? +} diff --git a/avm/1.1.0/res/compute/gallery/application/main.json b/avm/1.1.0/res/compute/gallery/application/main.json new file mode 100644 index 000000000..389026f8c --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/application/main.json @@ -0,0 +1,356 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "8421640590183520512" + }, + "name": "Compute Galleries Applications", + "description": "This module deploys an Azure Compute Gallery Application." + }, + "definitions": { + "customActionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the custom action. Must be unique within the Gallery Application Version." + } + }, + "script": { + "type": "string", + "metadata": { + "description": "Required. The script to run when executing this custom action." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description to help the users understand what this custom action does." + } + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the parameter." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "ConfigurationDataBlob", + "LogOutputBlob", + "String" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the type of the custom action parameter." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description to help users understand what this parameter means." + } + }, + "defaultValue": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The default value of the parameter. Only applies to string types." + } + }, + "required": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether this parameter must be passed when running the custom action." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The parameters that this custom action uses." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the application definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "galleryName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Conditional. The name of the parent Azure Compute Gallery. Required if the template is used in a standalone deployment." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this gallery Application Definition resource. This property is updatable." + } + }, + "eula": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Eula agreement for the gallery Application Definition. Has to be a valid URL." + } + }, + "privacyStatementUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The privacy statement uri. Has to be a valid URL." + } + }, + "releaseNoteUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The release note uri. Has to be a valid URL." + } + }, + "supportedOSType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. This property allows you to specify the supported type of the OS that application is built for." + } + }, + "endOfLifeDate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for all resources." + } + }, + "customActions": { + "type": "array", + "items": { + "$ref": "#/definitions/customActionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Compute Gallery Sharing Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1ef6a3be-d0ac-425d-8c01-acb62866290b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "gallery": { + "existing": true, + "type": "Microsoft.Compute/galleries", + "apiVersion": "2024-03-03", + "name": "[parameters('galleryName')]" + }, + "application": { + "type": "Microsoft.Compute/galleries/applications", + "apiVersion": "2024-03-03", + "name": "[format('{0}/{1}', parameters('galleryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "customActions": "[parameters('customActions')]", + "description": "[parameters('description')]", + "endOfLifeDate": "[parameters('endOfLifeDate')]", + "eula": "[parameters('eula')]", + "privacyStatementUri": "[parameters('privacyStatementUri')]", + "releaseNoteUri": "[parameters('releaseNoteUri')]", + "supportedOSType": "[parameters('supportedOSType')]" + } + }, + "application_roleAssignments": { + "copy": { + "name": "application_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/galleries/{0}/applications/{1}', parameters('galleryName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/galleries/applications', parameters('galleryName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "application" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the image was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the image." + }, + "value": "[resourceId('Microsoft.Compute/galleries/applications', parameters('galleryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the image." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('application', '2024-03-03', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/gallery/image/README.md b/avm/1.1.0/res/compute/gallery/image/README.md new file mode 100644 index 000000000..a5cf55dbb --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/image/README.md @@ -0,0 +1,521 @@ +# Compute Galleries Image Definitions `[Microsoft.Compute/galleries/images]` + +This module deploys an Azure Compute Gallery Image Definition. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Compute/galleries/images` | [2024-03-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-03-03/galleries/images) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`identifier`](#parameter-identifier) | object | This is the gallery image definition identifier. | +| [`name`](#parameter-name) | string | Name of the image definition. | +| [`osState`](#parameter-osstate) | string | This property allows the user to specify the state of the OS of the image. | +| [`osType`](#parameter-ostype) | string | This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`galleryName`](#parameter-galleryname) | string | The name of the parent Azure Shared Image Gallery. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowUpdateImage`](#parameter-allowupdateimage) | bool | Must be set to true if the gallery image features are being updated. | +| [`architecture`](#parameter-architecture) | string | The architecture of the image. Applicable to OS disks only. | +| [`description`](#parameter-description) | string | The description of this gallery image definition resource. This property is updatable. | +| [`disallowed`](#parameter-disallowed) | object | Describes the disallowed disk types. | +| [`diskControllerType`](#parameter-diskcontrollertype) | string | The disk controllers that an OS disk supports. | +| [`endOfLifeDate`](#parameter-endoflifedate) | string | The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable. | +| [`eula`](#parameter-eula) | string | The Eula agreement for the gallery image definition. | +| [`hyperVGeneration`](#parameter-hypervgeneration) | string | The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1. | +| [`isAcceleratedNetworkSupported`](#parameter-isacceleratednetworksupported) | bool | Specify if the image supports accelerated networking. | +| [`isHibernateSupported`](#parameter-ishibernatesupported) | bool | Specifiy if the image supports hibernation. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`memory`](#parameter-memory) | object | Describes the resource range (1-4000 GB RAM). | +| [`privacyStatementUri`](#parameter-privacystatementuri) | string | The privacy statement uri. | +| [`purchasePlan`](#parameter-purchaseplan) | object | Describes the gallery image definition purchase plan. This is used by marketplace images. | +| [`releaseNoteUri`](#parameter-releasenoteuri) | string | The release note uri. Has to be a valid URL. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`securityType`](#parameter-securitytype) | string | The security type of the image. Requires a hyperVGeneration V2. | +| [`tags`](#parameter-tags) | object | Tags for all the image. | +| [`vCPUs`](#parameter-vcpus) | object | Describes the resource range (1-128 CPU cores). | + +### Parameter: `identifier` + +This is the gallery image definition identifier. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`offer`](#parameter-identifieroffer) | string | The name of the gallery image definition offer. | +| [`publisher`](#parameter-identifierpublisher) | string | The name of the gallery image definition publisher. | +| [`sku`](#parameter-identifiersku) | string | The name of the gallery image definition SKU. | + +### Parameter: `identifier.offer` + +The name of the gallery image definition offer. + +- Required: Yes +- Type: string + +### Parameter: `identifier.publisher` + +The name of the gallery image definition publisher. + +- Required: Yes +- Type: string + +### Parameter: `identifier.sku` + +The name of the gallery image definition SKU. + +- Required: Yes +- Type: string + +### Parameter: `name` + +Name of the image definition. + +- Required: Yes +- Type: string + +### Parameter: `osState` + +This property allows the user to specify the state of the OS of the image. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Generalized' + 'Specialized' + ] + ``` + +### Parameter: `osType` + +This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `galleryName` + +The name of the parent Azure Shared Image Gallery. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `allowUpdateImage` + +Must be set to true if the gallery image features are being updated. + +- Required: No +- Type: bool + +### Parameter: `architecture` + +The architecture of the image. Applicable to OS disks only. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Arm64' + 'x64' + ] + ``` + +### Parameter: `description` + +The description of this gallery image definition resource. This property is updatable. + +- Required: No +- Type: string + +### Parameter: `disallowed` + +Describes the disallowed disk types. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`diskTypes`](#parameter-disalloweddisktypes) | array | A list of disk types. | + +### Parameter: `disallowed.diskTypes` + +A list of disk types. + +- Required: Yes +- Type: array +- Example: + ```Bicep + [ + 'Standard_LRS' + ] + ``` + +### Parameter: `diskControllerType` + +The disk controllers that an OS disk supports. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'NVMe, SCSI' + 'SCSI' + 'SCSI, NVMe' + ] + ``` + +### Parameter: `endOfLifeDate` + +The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable. + +- Required: No +- Type: string + +### Parameter: `eula` + +The Eula agreement for the gallery image definition. + +- Required: No +- Type: string + +### Parameter: `hyperVGeneration` + +The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'V1' + 'V2' + ] + ``` + +### Parameter: `isAcceleratedNetworkSupported` + +Specify if the image supports accelerated networking. + +- Required: No +- Type: bool + +### Parameter: `isHibernateSupported` + +Specifiy if the image supports hibernation. + +- Required: No +- Type: bool + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `memory` + +Describes the resource range (1-4000 GB RAM). + +- Required: No +- Type: object +- Default: + ```Bicep + { + max: 16 + min: 4 + } + ``` + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`max`](#parameter-memorymax) | int | The minimum number of the resource. | +| [`min`](#parameter-memorymin) | int | The minimum number of the resource. | + +### Parameter: `memory.max` + +The minimum number of the resource. + +- Required: No +- Type: int + +### Parameter: `memory.min` + +The minimum number of the resource. + +- Required: No +- Type: int +- MinValue: 1 + +### Parameter: `privacyStatementUri` + +The privacy statement uri. + +- Required: No +- Type: string + +### Parameter: `purchasePlan` + +Describes the gallery image definition purchase plan. This is used by marketplace images. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-purchaseplanname) | string | The plan ID. | +| [`product`](#parameter-purchaseplanproduct) | string | The product ID. | +| [`publisher`](#parameter-purchaseplanpublisher) | string | The publisher ID. | + +### Parameter: `purchasePlan.name` + +The plan ID. + +- Required: Yes +- Type: string + +### Parameter: `purchasePlan.product` + +The product ID. + +- Required: Yes +- Type: string + +### Parameter: `purchasePlan.publisher` + +The publisher ID. + +- Required: Yes +- Type: string + +### Parameter: `releaseNoteUri` + +The release note uri. Has to be a valid URL. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Compute Gallery Sharing Admin'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `securityType` + +The security type of the image. Requires a hyperVGeneration V2. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'ConfidentialVM' + 'ConfidentialVMSupported' + 'Standard' + 'TrustedLaunch' + 'TrustedLaunchAndConfidentialVmSupported' + 'TrustedLaunchSupported' + ] + ``` + +### Parameter: `tags` + +Tags for all the image. + +- Required: No +- Type: object +- Example: + ```Bicep + { + key1: 'value1' + key2: 'value2' + } + ``` + +### Parameter: `vCPUs` + +Describes the resource range (1-128 CPU cores). + +- Required: No +- Type: object +- Default: + ```Bicep + { + max: 4 + min: 1 + } + ``` + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`max`](#parameter-vcpusmax) | int | The minimum number of the resource. | +| [`min`](#parameter-vcpusmin) | int | The minimum number of the resource. | + +### Parameter: `vCPUs.max` + +The minimum number of the resource. + +- Required: No +- Type: int + +### Parameter: `vCPUs.min` + +The minimum number of the resource. + +- Required: No +- Type: int +- MinValue: 1 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the image. | +| `resourceGroupName` | string | The resource group the image was deployed into. | +| `resourceId` | string | The resource ID of the image. | diff --git a/avm/1.1.0/res/compute/gallery/image/main.bicep b/avm/1.1.0/res/compute/gallery/image/main.bicep new file mode 100644 index 000000000..ae277e2cf --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/image/main.bicep @@ -0,0 +1,288 @@ +metadata name = 'Compute Galleries Image Definitions' +metadata description = 'This module deploys an Azure Compute Gallery Image Definition.' + +@sys.description('Required. Name of the image definition.') +@minLength(1) +@maxLength(80) +param name string + +@sys.description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@sys.description('Conditional. The name of the parent Azure Shared Image Gallery. Required if the template is used in a standalone deployment.') +@minLength(1) +param galleryName string + +@sys.description('Required. This is the gallery image definition identifier.') +param identifier identifierType + +@sys.description('Required. This property allows the user to specify the state of the OS of the image.') +param osState ('Generalized' | 'Specialized') + +@sys.description('Required. This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image.') +param osType ('Linux' | 'Windows') + +@sys.description('Optional. The privacy statement uri.') +param privacyStatementUri string? + +@sys.description('Optional. Describes the gallery image definition purchase plan. This is used by marketplace images.') +param purchasePlan purchasePlanType? + +@sys.description('Optional. Describes the resource range (1-128 CPU cores).') +param vCPUs resourceRangeType = { min: 1, max: 4 } + +@sys.description('Optional. Describes the resource range (1-4000 GB RAM).') +param memory resourceRangeType = { min: 4, max: 16 } + +@sys.description('Optional. The release note uri. Has to be a valid URL.') +param releaseNoteUri string? + +@sys.description('Optional. The security type of the image. Requires a hyperVGeneration V2.') +param securityType ( + | 'Standard' + | 'ConfidentialVM' + | 'TrustedLaunchSupported' + | 'TrustedLaunch' + | 'TrustedLaunchAndConfidentialVmSupported' + | 'ConfidentialVMSupported')? + +@sys.description('Optional. Specify if the image supports accelerated networking.') +param isAcceleratedNetworkSupported bool? + +@sys.description('Optional. Specifiy if the image supports hibernation.') +param isHibernateSupported bool? + +@sys.description('Optional. Must be set to true if the gallery image features are being updated.') +param allowUpdateImage bool? + +@sys.description('Optional. The architecture of the image. Applicable to OS disks only.') +param architecture ('x64' | 'Arm64')? + +@sys.description('Optional. The description of this gallery image definition resource. This property is updatable.') +param description string? + +@sys.description('Optional. Describes the disallowed disk types.') +param disallowed disallowedType? + +@sys.description('Optional. The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable.') +param endOfLifeDate string? + +@sys.description('Optional. The Eula agreement for the gallery image definition.') +param eula string? + +@sys.description('Optional. The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.') +param hyperVGeneration ('V1' | 'V2')? + +@sys.description('Optional. The disk controllers that an OS disk supports.') +param diskControllerType ('SCSI' | 'SCSI, NVMe' | 'NVMe, SCSI')? + +@sys.description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@sys.description('Optional. Tags for all the image.') +@metadata({ + example: ''' +{ + key1: 'value1' + key2: 'value2' +} +''' +}) +param tags object? + +var builtInRoleNames = { + 'Compute Gallery Sharing Admin': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '1ef6a3be-d0ac-425d-8c01-acb62866290b' + ) + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource gallery 'Microsoft.Compute/galleries@2024-03-03' existing = { + name: galleryName +} + +resource image 'Microsoft.Compute/galleries/images@2024-03-03' = { + name: name + parent: gallery + location: location + tags: tags + properties: { + allowUpdateImage: allowUpdateImage != null ? allowUpdateImage : null + architecture: architecture + description: description + disallowed: { + diskTypes: disallowed.?diskTypes ?? [] + } + endOfLifeDate: endOfLifeDate + eula: eula + features: union( + (isAcceleratedNetworkSupported != null // Accelerated network is not set by default and must not be set for unsupported skus + ? [ + { + name: 'IsAcceleratedNetworkSupported' + value: '${isAcceleratedNetworkSupported}' + } + ] + : []), + (securityType != null && securityType != 'Standard' // Standard is the default and is not set + ? [ + { + name: 'SecurityType' + value: '${securityType}' + } + ] + : []), + (isHibernateSupported != null + ? [ + { + name: 'IsHibernateSupported' + value: '${isHibernateSupported}' + } + ] + : []), + (diskControllerType != null + ? [ + { + name: 'DiskControllerTypes' + value: '${diskControllerType}' + } + ] + : []) + ) + hyperVGeneration: hyperVGeneration ?? (!empty(securityType ?? '') ? 'V2' : 'V1') + identifier: { + publisher: identifier.publisher + offer: identifier.offer + sku: identifier.sku + } + osState: osState + osType: osType + privacyStatementUri: privacyStatementUri + purchasePlan: purchasePlan ?? null + recommended: { vCPUs: vCPUs, memory: memory } + releaseNoteUri: releaseNoteUri + } +} + +resource image_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(image.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: image + } +] + +@sys.description('The resource group the image was deployed into.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The resource ID of the image.') +output resourceId string = image.id + +@sys.description('The name of the image.') +output name string = image.name + +@sys.description('The location the resource was deployed into.') +output location string = image.location + +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @sys.description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @sys.description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @sys.description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @sys.description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @sys.description('Optional. The description of the role assignment.') + 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".') + condition: string? + + @sys.description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @sys.description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +@export() +type resourceRangeType = { + @sys.description('Optional. The minimum number of the resource.') + @minValue(1) + min: int? + + @sys.description('Optional. The minimum number of the resource.') + max: int? +} + +type disallowedType = { + @sys.description('Required. A list of disk types.') + @metadata({ example: ''' + [ + 'Standard_LRS' + ]''' }) + diskTypes: string[] +}? + +@export() +type identifierType = { + @sys.description('Required. The name of the gallery image definition publisher.') + publisher: string + + @sys.description('Required. The name of the gallery image definition offer.') + offer: string + + @sys.description('Required. The name of the gallery image definition SKU.') + sku: string +} + +@export() +type purchasePlanType = { + @sys.description('Required. The plan ID.') + name: string + + @sys.description('Required. The product ID.') + product: string + + @sys.description('Required. The publisher ID.') + publisher: string +}? diff --git a/avm/1.1.0/res/compute/gallery/image/main.json b/avm/1.1.0/res/compute/gallery/image/main.json new file mode 100644 index 000000000..647150763 --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/image/main.json @@ -0,0 +1,494 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "5191633407919649272" + }, + "name": "Compute Galleries Image Definitions", + "description": "This module deploys an Azure Compute Gallery Image Definition." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "resourceRangeType": { + "type": "object", + "properties": { + "min": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + }, + "max": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "disallowedType": { + "type": "object", + "properties": { + "diskTypes": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "example": " [\n 'Standard_LRS'\n ]", + "description": "Required. A list of disk types." + } + } + }, + "nullable": true + }, + "identifierType": { + "type": "object", + "properties": { + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition publisher." + } + }, + "offer": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition offer." + } + }, + "sku": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition SKU." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "purchasePlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The plan ID." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product ID." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The publisher ID." + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 80, + "metadata": { + "description": "Required. Name of the image definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "galleryName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Conditional. The name of the parent Azure Shared Image Gallery. Required if the template is used in a standalone deployment." + } + }, + "identifier": { + "$ref": "#/definitions/identifierType", + "metadata": { + "description": "Required. This is the gallery image definition identifier." + } + }, + "osState": { + "type": "string", + "allowedValues": [ + "Generalized", + "Specialized" + ], + "metadata": { + "description": "Required. This property allows the user to specify the state of the OS of the image." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "Required. This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image." + } + }, + "privacyStatementUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The privacy statement uri." + } + }, + "purchasePlan": { + "$ref": "#/definitions/purchasePlanType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the gallery image definition purchase plan. This is used by marketplace images." + } + }, + "vCPUs": { + "$ref": "#/definitions/resourceRangeType", + "defaultValue": { + "min": 1, + "max": 4 + }, + "metadata": { + "description": "Optional. Describes the resource range (1-128 CPU cores)." + } + }, + "memory": { + "$ref": "#/definitions/resourceRangeType", + "defaultValue": { + "min": 4, + "max": 16 + }, + "metadata": { + "description": "Optional. Describes the resource range (1-4000 GB RAM)." + } + }, + "releaseNoteUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The release note uri. Has to be a valid URL." + } + }, + "securityType": { + "type": "string", + "allowedValues": [ + "ConfidentialVM", + "ConfidentialVMSupported", + "Standard", + "TrustedLaunch", + "TrustedLaunchAndConfidentialVmSupported", + "TrustedLaunchSupported" + ], + "nullable": true, + "metadata": { + "description": "Optional. The security type of the image. Requires a hyperVGeneration V2." + } + }, + "isAcceleratedNetworkSupported": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specify if the image supports accelerated networking." + } + }, + "isHibernateSupported": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifiy if the image supports hibernation." + } + }, + "allowUpdateImage": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Must be set to true if the gallery image features are being updated." + } + }, + "architecture": { + "type": "string", + "allowedValues": [ + "Arm64", + "x64" + ], + "nullable": true, + "metadata": { + "description": "Optional. The architecture of the image. Applicable to OS disks only." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this gallery image definition resource. This property is updatable." + } + }, + "disallowed": { + "$ref": "#/definitions/disallowedType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the disallowed disk types." + } + }, + "endOfLifeDate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable." + } + }, + "eula": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Eula agreement for the gallery image definition." + } + }, + "hyperVGeneration": { + "type": "string", + "allowedValues": [ + "V1", + "V2" + ], + "nullable": true, + "metadata": { + "description": "Optional. The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1." + } + }, + "diskControllerType": { + "type": "string", + "allowedValues": [ + "NVMe, SCSI", + "SCSI", + "SCSI, NVMe" + ], + "nullable": true, + "metadata": { + "description": "Optional. The disk controllers that an OS disk supports." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": "{\n key1: 'value1'\n key2: 'value2'\n}\n", + "description": "Optional. Tags for all the image." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Compute Gallery Sharing Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1ef6a3be-d0ac-425d-8c01-acb62866290b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "gallery": { + "existing": true, + "type": "Microsoft.Compute/galleries", + "apiVersion": "2024-03-03", + "name": "[parameters('galleryName')]" + }, + "image": { + "type": "Microsoft.Compute/galleries/images", + "apiVersion": "2024-03-03", + "name": "[format('{0}/{1}', parameters('galleryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "allowUpdateImage": "[if(not(equals(parameters('allowUpdateImage'), null())), parameters('allowUpdateImage'), null())]", + "architecture": "[parameters('architecture')]", + "description": "[parameters('description')]", + "disallowed": { + "diskTypes": "[coalesce(tryGet(parameters('disallowed'), 'diskTypes'), createArray())]" + }, + "endOfLifeDate": "[parameters('endOfLifeDate')]", + "eula": "[parameters('eula')]", + "features": "[union(if(not(equals(parameters('isAcceleratedNetworkSupported'), null())), createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), createArray()), if(and(not(equals(parameters('securityType'), null())), not(equals(parameters('securityType'), 'Standard'))), createArray(createObject('name', 'SecurityType', 'value', format('{0}', parameters('securityType')))), createArray()), if(not(equals(parameters('isHibernateSupported'), null())), createArray(createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), createArray()), if(not(equals(parameters('diskControllerType'), null())), createArray(createObject('name', 'DiskControllerTypes', 'value', format('{0}', parameters('diskControllerType')))), createArray()))]", + "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(coalesce(parameters('securityType'), ''))), 'V2', 'V1'))]", + "identifier": { + "publisher": "[parameters('identifier').publisher]", + "offer": "[parameters('identifier').offer]", + "sku": "[parameters('identifier').sku]" + }, + "osState": "[parameters('osState')]", + "osType": "[parameters('osType')]", + "privacyStatementUri": "[parameters('privacyStatementUri')]", + "purchasePlan": "[coalesce(parameters('purchasePlan'), null())]", + "recommended": { + "vCPUs": "[parameters('vCPUs')]", + "memory": "[parameters('memory')]" + }, + "releaseNoteUri": "[parameters('releaseNoteUri')]" + } + }, + "image_roleAssignments": { + "copy": { + "name": "image_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/galleries/{0}/images/{1}', parameters('galleryName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/galleries/images', parameters('galleryName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "image" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the image was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the image." + }, + "value": "[resourceId('Microsoft.Compute/galleries/images', parameters('galleryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the image." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('image', '2024-03-03', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/gallery/main.bicep b/avm/1.1.0/res/compute/gallery/main.bicep new file mode 100644 index 000000000..0902a5620 --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/main.bicep @@ -0,0 +1,325 @@ +metadata name = 'Azure Compute Galleries' +metadata description = 'This module deploys an Azure Compute Gallery (formerly known as Shared Image Gallery).' + +// ============ // +// Parameters // +// ============ // + +@minLength(1) +@sys.description('Required. Name of the Azure Compute Gallery.') +param name string + +@sys.description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@sys.description('Optional. Description of the Azure Shared Image Gallery.') +param description string? + +@sys.description('Optional. Applications to create.') +param applications applicationsType[]? + +@sys.description('Optional. Images to create.') +param images imageType[]? // use a UDT here to not overload the main module, as it has images and applications parameters + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.3.0' +@sys.description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.3.0' +@sys.description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@sys.description('Optional. Tags for all resources.') +@metadata({ + example: ''' + { + key1: 'value1' + key2: 'value2' + } + ''' +}) +param tags object? + +@sys.description('Optional. Profile for gallery sharing to subscription or tenant.') +param sharingProfile object? + +@sys.description('Optional. Soft deletion policy of the gallery.') +param softDeletePolicy object? + +var builtInRoleNames = { + 'Compute Gallery Sharing Admin': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '1ef6a3be-d0ac-425d-8c01-acb62866290b' + ) + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.compute-gallery.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource gallery 'Microsoft.Compute/galleries@2024-03-03' = { + name: name + location: location + tags: tags + properties: { + description: description + // identifier: {} // Contains only read-only properties + sharingProfile: sharingProfile + softDeletePolicy: softDeletePolicy + } +} + +resource gallery_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: gallery +} + +resource gallery_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(gallery.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: gallery + } +] + +module galleries_applications 'application/main.bicep' = [ + for (application, index) in (applications ?? []): { + name: '${uniqueString(deployment().name, location)}-Gallery-Application-${index}' + params: { + location: location + name: application.name + galleryName: gallery.name + supportedOSType: application.supportedOSType + description: application.?description + eula: application.?eula + privacyStatementUri: application.?privacyStatementUri + releaseNoteUri: application.?releaseNoteUri + endOfLifeDate: application.?endOfLifeDate + roleAssignments: application.?roleAssignments + customActions: application.?customActions + tags: application.?tags ?? tags + } + } +] + +module galleries_images 'image/main.bicep' = [ + for (image, index) in (images ?? []): { + name: '${uniqueString(deployment().name, location)}-Gallery-Image-${index}' + params: { + name: image.name + location: image.?location ?? location + galleryName: gallery.name + description: image.?description + allowUpdateImage: image.?allowUpdateImage + osType: image.osType + osState: image.osState + identifier: image.identifier + vCPUs: image.?vCPUs + memory: image.?memory + hyperVGeneration: image.?hyperVGeneration + securityType: image.?securityType + isAcceleratedNetworkSupported: image.?isAcceleratedNetworkSupported + isHibernateSupported: image.?isHibernateSupported + diskControllerType: image.?diskControllerType + architecture: image.?architecture + eula: image.?eula + privacyStatementUri: image.?privacyStatementUri + releaseNoteUri: image.?releaseNoteUri + purchasePlan: image.?purchasePlan + endOfLifeDate: image.?endOfLife + disallowed: { diskTypes: image.?excludedDiskTypes ?? [] } + roleAssignments: image.?roleAssignments + tags: image.?tags ?? tags + } + } +] + +// ============ // +// Outputs // +// ============ // + +@sys.description('The resource ID of the deployed image gallery.') +output resourceId string = gallery.id + +@sys.description('The resource group of the deployed image gallery.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The name of the deployed image gallery.') +output name string = gallery.name + +@sys.description('The location the resource was deployed into.') +output location string = gallery.location + +@sys.description('The resource ids of the deployed images.') +output imageResourceIds array = [ + for index in range(0, length(images ?? [])): galleries_images[index].outputs.resourceId +] + +// =============== // +// Definitions // +// =============== // + +import { identifierType, purchasePlanType, resourceRangeType } from './image/main.bicep' +@export() +type imageType = { + @sys.description('Required. Name of the image definition.') + @minLength(1) + @maxLength(80) + name: string + + @sys.description('Optional. The description of this gallery image definition resource. This property is updatable.') + description: string? + + @sys.description('Optional. Must be set to true if the gallery image features are being updated.') + allowUpdateImage: bool? + + @sys.description('Required. This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image.') + osType: ('Linux' | 'Windows') + + @sys.description('Required. This property allows the user to specify the state of the OS of the image.') + osState: ('Generalized' | 'Specialized') + + @sys.description('Required. This is the gallery image definition identifier.') + identifier: identifierType + + @sys.description('Optional. Describes the resource range (1-128 CPU cores). Defaults to min=1, max=4.') + vCPUs: resourceRangeType? + + @sys.description('Optional. Describes the resource range (1-4000 GB RAM). Defaults to min=4, max=16.') + memory: resourceRangeType? + + @sys.description('Optional. The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.') + hyperVGeneration: ('V1' | 'V2')? + + @sys.description('Optional. The security type of the image. Requires a hyperVGeneration V2. Defaults to `Standard`.') + securityType: ( + | 'Standard' + | 'ConfidentialVM' + | 'TrustedLaunchSupported' + | 'TrustedLaunch' + | 'TrustedLaunchAndConfidentialVmSupported' + | 'ConfidentialVMSupported')? + + @sys.description('Optional. Specify if the image supports accelerated networking. Defaults to true.') + isAcceleratedNetworkSupported: bool? + + @sys.description('Optional. Specify if the image supports hibernation.') + isHibernateSupported: bool? + + @sys.description('Optional. The disk controllers that an OS disk supports.') + diskControllerType: ('SCSI' | 'SCSI, NVMe' | 'NVMe, SCSI')? + + @sys.description('Optional. The architecture of the image. Applicable to OS disks only.') + architecture: ('x64' | 'Arm64')? + + @sys.description('Optional. The Eula agreement for the gallery image definition.') + eula: string? + + @sys.description('Optional. The privacy statement uri.') + privacyStatementUri: string? + + @sys.description('Optional. The release note uri. Has to be a valid URL.') + releaseNoteUri: string? + + @sys.description('Optional. Describes the gallery image definition purchase plan. This is used by marketplace images.') + purchasePlan: purchasePlanType? + + @sys.description('Optional. The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable.') + endOfLife: string? + + @sys.description('Optional. Describes the disallowed disk types.') + excludedDiskTypes: string[]? +} + +import { customActionType } from './application/main.bicep' +type applicationsType = { + @sys.description('Required. Name of the application definition.') + @minLength(1) + @maxLength(80) + name: string + + @sys.description('Required. The OS type of the application.') + supportedOSType: 'Linux' | 'Windows' + + @sys.description('Optional. The description of this gallery application definition resource. This property is updatable.') + description: string? + + @sys.description('Optional. The Eula agreement for the gallery application definition.') + eula: string? + + @sys.description('Optional. The privacy statement uri.') + privacyStatementUri: string? + + @sys.description('Optional. The release note uri. Has to be a valid URL.') + releaseNoteUri: string? + + @sys.description('Optional. The end of life date of the gallery application definition. This property can be used for decommissioning purposes. This property is updatable.') + endOfLifeDate: string? + + @sys.description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType[]? + + @sys.description('Optional. A list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application.') + customActions: customActionType[]? + + @sys.description('Optional. Tags for all resources.') + tags: object? +} diff --git a/avm/1.1.0/res/compute/gallery/main.json b/avm/1.1.0/res/compute/gallery/main.json new file mode 100644 index 000000000..cbcc15f39 --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/main.json @@ -0,0 +1,1762 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "13276352345178978927" + }, + "name": "Azure Compute Galleries", + "description": "This module deploys an Azure Compute Gallery (formerly known as Shared Image Gallery)." + }, + "definitions": { + "imageType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 80, + "metadata": { + "description": "Required. Name of the image definition." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this gallery image definition resource. This property is updatable." + } + }, + "allowUpdateImage": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Must be set to true if the gallery image features are being updated." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "Required. This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image." + } + }, + "osState": { + "type": "string", + "allowedValues": [ + "Generalized", + "Specialized" + ], + "metadata": { + "description": "Required. This property allows the user to specify the state of the OS of the image." + } + }, + "identifier": { + "$ref": "#/definitions/identifierType", + "metadata": { + "description": "Required. This is the gallery image definition identifier." + } + }, + "vCPUs": { + "$ref": "#/definitions/resourceRangeType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the resource range (1-128 CPU cores). Defaults to min=1, max=4." + } + }, + "memory": { + "$ref": "#/definitions/resourceRangeType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the resource range (1-4000 GB RAM). Defaults to min=4, max=16." + } + }, + "hyperVGeneration": { + "type": "string", + "allowedValues": [ + "V1", + "V2" + ], + "nullable": true, + "metadata": { + "description": "Optional. The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1." + } + }, + "securityType": { + "type": "string", + "allowedValues": [ + "ConfidentialVM", + "ConfidentialVMSupported", + "Standard", + "TrustedLaunch", + "TrustedLaunchAndConfidentialVmSupported", + "TrustedLaunchSupported" + ], + "nullable": true, + "metadata": { + "description": "Optional. The security type of the image. Requires a hyperVGeneration V2. Defaults to `Standard`." + } + }, + "isAcceleratedNetworkSupported": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specify if the image supports accelerated networking. Defaults to true." + } + }, + "isHibernateSupported": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specify if the image supports hibernation." + } + }, + "diskControllerType": { + "type": "string", + "allowedValues": [ + "NVMe, SCSI", + "SCSI", + "SCSI, NVMe" + ], + "nullable": true, + "metadata": { + "description": "Optional. The disk controllers that an OS disk supports." + } + }, + "architecture": { + "type": "string", + "allowedValues": [ + "Arm64", + "x64" + ], + "nullable": true, + "metadata": { + "description": "Optional. The architecture of the image. Applicable to OS disks only." + } + }, + "eula": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Eula agreement for the gallery image definition." + } + }, + "privacyStatementUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The privacy statement uri." + } + }, + "releaseNoteUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The release note uri. Has to be a valid URL." + } + }, + "purchasePlan": { + "$ref": "#/definitions/purchasePlanType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the gallery image definition purchase plan. This is used by marketplace images." + } + }, + "endOfLife": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable." + } + }, + "excludedDiskTypes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Describes the disallowed disk types." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "applicationsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 80, + "metadata": { + "description": "Required. Name of the application definition." + } + }, + "supportedOSType": { + "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "Required. The OS type of the application." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this gallery application definition resource. This property is updatable." + } + }, + "eula": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Eula agreement for the gallery application definition." + } + }, + "privacyStatementUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The privacy statement uri." + } + }, + "releaseNoteUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The release note uri. Has to be a valid URL." + } + }, + "endOfLifeDate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The end of life date of the gallery application definition. This property can be used for decommissioning purposes. This property is updatable." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "customActions": { + "type": "array", + "items": { + "$ref": "#/definitions/customActionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for all resources." + } + } + } + }, + "customActionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the custom action. Must be unique within the Gallery Application Version." + } + }, + "script": { + "type": "string", + "metadata": { + "description": "Required. The script to run when executing this custom action." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description to help the users understand what this custom action does." + } + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the parameter." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "ConfigurationDataBlob", + "LogOutputBlob", + "String" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the type of the custom action parameter." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description to help users understand what this parameter means." + } + }, + "defaultValue": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The default value of the parameter. Only applies to string types." + } + }, + "required": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether this parameter must be passed when running the custom action." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The parameters that this custom action uses." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "application/main.bicep" + } + } + }, + "identifierType": { + "type": "object", + "properties": { + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition publisher." + } + }, + "offer": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition offer." + } + }, + "sku": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition SKU." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "image/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + }, + "purchasePlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The plan ID." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product ID." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The publisher ID." + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "image/main.bicep" + } + } + }, + "resourceRangeType": { + "type": "object", + "properties": { + "min": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + }, + "max": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "image/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the Azure Compute Gallery." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the Azure Shared Image Gallery." + } + }, + "applications": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Applications to create." + } + }, + "images": { + "type": "array", + "items": { + "$ref": "#/definitions/imageType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Images to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n key1: 'value1'\n key2: 'value2'\n }\n ", + "description": "Optional. Tags for all resources." + } + }, + "sharingProfile": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Profile for gallery sharing to subscription or tenant." + } + }, + "softDeletePolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Soft deletion policy of the gallery." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Compute Gallery Sharing Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1ef6a3be-d0ac-425d-8c01-acb62866290b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.compute-gallery.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "gallery": { + "type": "Microsoft.Compute/galleries", + "apiVersion": "2024-03-03", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "description": "[parameters('description')]", + "sharingProfile": "[parameters('sharingProfile')]", + "softDeletePolicy": "[parameters('softDeletePolicy')]" + } + }, + "gallery_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Compute/galleries/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "gallery" + ] + }, + "gallery_roleAssignments": { + "copy": { + "name": "gallery_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/galleries/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/galleries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "gallery" + ] + }, + "galleries_applications": { + "copy": { + "name": "galleries_applications", + "count": "[length(coalesce(parameters('applications'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Gallery-Application-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "name": { + "value": "[coalesce(parameters('applications'), createArray())[copyIndex()].name]" + }, + "galleryName": { + "value": "[parameters('name')]" + }, + "supportedOSType": { + "value": "[coalesce(parameters('applications'), createArray())[copyIndex()].supportedOSType]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'description')]" + }, + "eula": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'eula')]" + }, + "privacyStatementUri": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'privacyStatementUri')]" + }, + "releaseNoteUri": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'releaseNoteUri')]" + }, + "endOfLifeDate": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'endOfLifeDate')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "customActions": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'customActions')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "8421640590183520512" + }, + "name": "Compute Galleries Applications", + "description": "This module deploys an Azure Compute Gallery Application." + }, + "definitions": { + "customActionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the custom action. Must be unique within the Gallery Application Version." + } + }, + "script": { + "type": "string", + "metadata": { + "description": "Required. The script to run when executing this custom action." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description to help the users understand what this custom action does." + } + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the parameter." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "ConfigurationDataBlob", + "LogOutputBlob", + "String" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the type of the custom action parameter." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description to help users understand what this parameter means." + } + }, + "defaultValue": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The default value of the parameter. Only applies to string types." + } + }, + "required": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether this parameter must be passed when running the custom action." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The parameters that this custom action uses." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the application definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "galleryName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Conditional. The name of the parent Azure Compute Gallery. Required if the template is used in a standalone deployment." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this gallery Application Definition resource. This property is updatable." + } + }, + "eula": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Eula agreement for the gallery Application Definition. Has to be a valid URL." + } + }, + "privacyStatementUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The privacy statement uri. Has to be a valid URL." + } + }, + "releaseNoteUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The release note uri. Has to be a valid URL." + } + }, + "supportedOSType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. This property allows you to specify the supported type of the OS that application is built for." + } + }, + "endOfLifeDate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for all resources." + } + }, + "customActions": { + "type": "array", + "items": { + "$ref": "#/definitions/customActionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Compute Gallery Sharing Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1ef6a3be-d0ac-425d-8c01-acb62866290b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "gallery": { + "existing": true, + "type": "Microsoft.Compute/galleries", + "apiVersion": "2024-03-03", + "name": "[parameters('galleryName')]" + }, + "application": { + "type": "Microsoft.Compute/galleries/applications", + "apiVersion": "2024-03-03", + "name": "[format('{0}/{1}', parameters('galleryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "customActions": "[parameters('customActions')]", + "description": "[parameters('description')]", + "endOfLifeDate": "[parameters('endOfLifeDate')]", + "eula": "[parameters('eula')]", + "privacyStatementUri": "[parameters('privacyStatementUri')]", + "releaseNoteUri": "[parameters('releaseNoteUri')]", + "supportedOSType": "[parameters('supportedOSType')]" + } + }, + "application_roleAssignments": { + "copy": { + "name": "application_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/galleries/{0}/applications/{1}', parameters('galleryName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/galleries/applications', parameters('galleryName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "application" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the image was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the image." + }, + "value": "[resourceId('Microsoft.Compute/galleries/applications', parameters('galleryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the image." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('application', '2024-03-03', 'full').location]" + } + } + } + }, + "dependsOn": [ + "gallery" + ] + }, + "galleries_images": { + "copy": { + "name": "galleries_images", + "count": "[length(coalesce(parameters('images'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Gallery-Image-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('images'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "galleryName": { + "value": "[parameters('name')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'description')]" + }, + "allowUpdateImage": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'allowUpdateImage')]" + }, + "osType": { + "value": "[coalesce(parameters('images'), createArray())[copyIndex()].osType]" + }, + "osState": { + "value": "[coalesce(parameters('images'), createArray())[copyIndex()].osState]" + }, + "identifier": { + "value": "[coalesce(parameters('images'), createArray())[copyIndex()].identifier]" + }, + "vCPUs": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'vCPUs')]" + }, + "memory": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'memory')]" + }, + "hyperVGeneration": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'hyperVGeneration')]" + }, + "securityType": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'securityType')]" + }, + "isAcceleratedNetworkSupported": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'isAcceleratedNetworkSupported')]" + }, + "isHibernateSupported": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'isHibernateSupported')]" + }, + "diskControllerType": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'diskControllerType')]" + }, + "architecture": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'architecture')]" + }, + "eula": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'eula')]" + }, + "privacyStatementUri": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'privacyStatementUri')]" + }, + "releaseNoteUri": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'releaseNoteUri')]" + }, + "purchasePlan": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'purchasePlan')]" + }, + "endOfLifeDate": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'endOfLife')]" + }, + "disallowed": { + "value": { + "diskTypes": "[coalesce(tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'excludedDiskTypes'), createArray())]" + } + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "5191633407919649272" + }, + "name": "Compute Galleries Image Definitions", + "description": "This module deploys an Azure Compute Gallery Image Definition." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "resourceRangeType": { + "type": "object", + "properties": { + "min": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + }, + "max": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "disallowedType": { + "type": "object", + "properties": { + "diskTypes": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "example": " [\n 'Standard_LRS'\n ]", + "description": "Required. A list of disk types." + } + } + }, + "nullable": true + }, + "identifierType": { + "type": "object", + "properties": { + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition publisher." + } + }, + "offer": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition offer." + } + }, + "sku": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition SKU." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "purchasePlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The plan ID." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product ID." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The publisher ID." + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 80, + "metadata": { + "description": "Required. Name of the image definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "galleryName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Conditional. The name of the parent Azure Shared Image Gallery. Required if the template is used in a standalone deployment." + } + }, + "identifier": { + "$ref": "#/definitions/identifierType", + "metadata": { + "description": "Required. This is the gallery image definition identifier." + } + }, + "osState": { + "type": "string", + "allowedValues": [ + "Generalized", + "Specialized" + ], + "metadata": { + "description": "Required. This property allows the user to specify the state of the OS of the image." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "Required. This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image." + } + }, + "privacyStatementUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The privacy statement uri." + } + }, + "purchasePlan": { + "$ref": "#/definitions/purchasePlanType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the gallery image definition purchase plan. This is used by marketplace images." + } + }, + "vCPUs": { + "$ref": "#/definitions/resourceRangeType", + "defaultValue": { + "min": 1, + "max": 4 + }, + "metadata": { + "description": "Optional. Describes the resource range (1-128 CPU cores)." + } + }, + "memory": { + "$ref": "#/definitions/resourceRangeType", + "defaultValue": { + "min": 4, + "max": 16 + }, + "metadata": { + "description": "Optional. Describes the resource range (1-4000 GB RAM)." + } + }, + "releaseNoteUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The release note uri. Has to be a valid URL." + } + }, + "securityType": { + "type": "string", + "allowedValues": [ + "ConfidentialVM", + "ConfidentialVMSupported", + "Standard", + "TrustedLaunch", + "TrustedLaunchAndConfidentialVmSupported", + "TrustedLaunchSupported" + ], + "nullable": true, + "metadata": { + "description": "Optional. The security type of the image. Requires a hyperVGeneration V2." + } + }, + "isAcceleratedNetworkSupported": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specify if the image supports accelerated networking." + } + }, + "isHibernateSupported": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifiy if the image supports hibernation." + } + }, + "allowUpdateImage": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Must be set to true if the gallery image features are being updated." + } + }, + "architecture": { + "type": "string", + "allowedValues": [ + "Arm64", + "x64" + ], + "nullable": true, + "metadata": { + "description": "Optional. The architecture of the image. Applicable to OS disks only." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this gallery image definition resource. This property is updatable." + } + }, + "disallowed": { + "$ref": "#/definitions/disallowedType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the disallowed disk types." + } + }, + "endOfLifeDate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable." + } + }, + "eula": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Eula agreement for the gallery image definition." + } + }, + "hyperVGeneration": { + "type": "string", + "allowedValues": [ + "V1", + "V2" + ], + "nullable": true, + "metadata": { + "description": "Optional. The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1." + } + }, + "diskControllerType": { + "type": "string", + "allowedValues": [ + "NVMe, SCSI", + "SCSI", + "SCSI, NVMe" + ], + "nullable": true, + "metadata": { + "description": "Optional. The disk controllers that an OS disk supports." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": "{\n key1: 'value1'\n key2: 'value2'\n}\n", + "description": "Optional. Tags for all the image." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Compute Gallery Sharing Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1ef6a3be-d0ac-425d-8c01-acb62866290b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "gallery": { + "existing": true, + "type": "Microsoft.Compute/galleries", + "apiVersion": "2024-03-03", + "name": "[parameters('galleryName')]" + }, + "image": { + "type": "Microsoft.Compute/galleries/images", + "apiVersion": "2024-03-03", + "name": "[format('{0}/{1}', parameters('galleryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "allowUpdateImage": "[if(not(equals(parameters('allowUpdateImage'), null())), parameters('allowUpdateImage'), null())]", + "architecture": "[parameters('architecture')]", + "description": "[parameters('description')]", + "disallowed": { + "diskTypes": "[coalesce(tryGet(parameters('disallowed'), 'diskTypes'), createArray())]" + }, + "endOfLifeDate": "[parameters('endOfLifeDate')]", + "eula": "[parameters('eula')]", + "features": "[union(if(not(equals(parameters('isAcceleratedNetworkSupported'), null())), createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), createArray()), if(and(not(equals(parameters('securityType'), null())), not(equals(parameters('securityType'), 'Standard'))), createArray(createObject('name', 'SecurityType', 'value', format('{0}', parameters('securityType')))), createArray()), if(not(equals(parameters('isHibernateSupported'), null())), createArray(createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), createArray()), if(not(equals(parameters('diskControllerType'), null())), createArray(createObject('name', 'DiskControllerTypes', 'value', format('{0}', parameters('diskControllerType')))), createArray()))]", + "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(coalesce(parameters('securityType'), ''))), 'V2', 'V1'))]", + "identifier": { + "publisher": "[parameters('identifier').publisher]", + "offer": "[parameters('identifier').offer]", + "sku": "[parameters('identifier').sku]" + }, + "osState": "[parameters('osState')]", + "osType": "[parameters('osType')]", + "privacyStatementUri": "[parameters('privacyStatementUri')]", + "purchasePlan": "[coalesce(parameters('purchasePlan'), null())]", + "recommended": { + "vCPUs": "[parameters('vCPUs')]", + "memory": "[parameters('memory')]" + }, + "releaseNoteUri": "[parameters('releaseNoteUri')]" + } + }, + "image_roleAssignments": { + "copy": { + "name": "image_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/galleries/{0}/images/{1}', parameters('galleryName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/galleries/images', parameters('galleryName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "image" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the image was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the image." + }, + "value": "[resourceId('Microsoft.Compute/galleries/images', parameters('galleryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the image." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('image', '2024-03-03', 'full').location]" + } + } + } + }, + "dependsOn": [ + "gallery" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed image gallery." + }, + "value": "[resourceId('Microsoft.Compute/galleries', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed image gallery." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed image gallery." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('gallery', '2024-03-03', 'full').location]" + }, + "imageResourceIds": { + "type": "array", + "metadata": { + "description": "The resource ids of the deployed images." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('images'), createArray()))))]", + "input": "[reference(format('galleries_images[{0}]', range(0, length(coalesce(parameters('images'), createArray())))[copyIndex()])).outputs.resourceId.value]" + } + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/gallery/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/compute/gallery/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..e4e7235dc --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.galleries-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cgmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/compute/gallery/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/compute/gallery/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/compute/gallery/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/compute/gallery/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..c301dea7d --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/tests/e2e/max/main.test.bicep @@ -0,0 +1,271 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.galleries-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cgmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + description: 'This is a test deployment.' + applications: [ + { + name: '${namePrefix}-${serviceShort}-appd-001' + supportedOSType: 'Linux' + } + { + name: '${namePrefix}-${serviceShort}-appd-002' + supportedOSType: 'Windows' + roleAssignments: [ + { + name: '4ef8d3d3-54be-4522-92c3-284977292d87' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + ] + images: [ + { + name: '${namePrefix}-az-imgd-ws-001' + allowUpdateImage: true + hyperVGeneration: 'V1' + identifier: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + } + osType: 'Windows' + osState: 'Generalized' + eula: 'test Eula' + architecture: 'x64' + description: 'testDescription' + privacyStatementUri: 'https://testPrivacyStatementUri.com' + excludedDiskTypes: ['Standard_LRS'] + purchasePlan: { + name: 'testPlanName1' + product: 'testProduct1' + publisher: 'testPublisher1' + } + endOfLife: '2033-01-01' + releaseNoteUri: 'https://testReleaseNoteUri.com' + } + { + name: '${namePrefix}-az-imgd-ws-002' + allowUpdateImage: false + hyperVGeneration: 'V2' + identifier: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition-hibernate' + } + osType: 'Windows' + vCPUs: { + min: 2 + max: 8 + } + memory: { + min: 4 + max: 16 + } + + osState: 'Generalized' + isHibernateSupported: true + isAcceleratedNetworkSupported: false + } + { + name: '${namePrefix}-az-imgd-wdtl-003' + securityType: 'Standard' + osType: 'Windows' + osState: 'Generalized' + hyperVGeneration: 'V2' + identifier: { + publisher: 'MicrosoftWindowsDesktop' + offer: 'WindowsDesktop' + sku: 'Win11-21H2' + } + memory: { + min: 4 + max: 16 + } + vCPUs: { + min: 2 + max: 8 + } + purchasePlan: { + name: 'testPlanName' + product: 'testProduct' + publisher: 'testPublisher' + } + } + { + name: '${namePrefix}-az-imgd-us-004' + osType: 'Linux' + osState: 'Generalized' + hyperVGeneration: 'V2' + identifier: { + publisher: 'canonical' + offer: '0001-com-ubuntu-minimal-focal' + sku: '22_04-lts-gen2' + } + memory: { + min: 4 + max: 32 + } + vCPUs: { + min: 1 + max: 4 + } + isAcceleratedNetworkSupported: false + diskControllerType: 'SCSI' + } + { + name: '${namePrefix}-az-imgd-us-005' + osType: 'Linux' + osState: 'Generalized' + hyperVGeneration: 'V2' + identifier: { + publisher: 'canonical' + offer: '0001-com-ubuntu-minimal-focal' + sku: '20_04-lts-gen2' + } + memory: { + min: 4 + max: 32 + } + vCPUs: { + min: 1 + max: 4 + } + isAcceleratedNetworkSupported: true + diskControllerType: 'SCSI, NVMe' + } + { + name: '${namePrefix}-az-imgd-us-006' + description: 'testDescription' + osType: 'Linux' + osState: 'Generalized' + hyperVGeneration: 'V2' + identifier: { + publisher: 'canonical' + offer: '0001-com-ubuntu-server-focal' + sku: '20_04-lts-gen2' + } + memory: { + min: 4 + max: 32 + } + vCPUs: { + min: 1 + max: 4 + } + securityType: 'TrustedLaunch' + architecture: 'x64' + endOfLife: '2033-01-01' + eula: 'test Eula' + excludedDiskTypes: ['Standard_LRS'] + isHibernateSupported: true + privacyStatementUri: 'https://testPrivacyStatementUri.com' + purchasePlan: { + name: 'testPlanName' + product: 'testProduct' + publisher: 'testPublisher' + } + releaseNoteUri: 'https://testReleaseNoteUri.com' + isAcceleratedNetworkSupported: false + // diskControllerType: 'NVMe, SCSI' // --> needs to remain commented, as there is a bug setting the value starting with 'NVMe' again, which prevents the idem test to pass + } + ] + roleAssignments: [ + { + name: '3bd58a78-108d-4f87-b404-0a03e49303d8' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/compute/gallery/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/compute/gallery/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/compute/gallery/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/compute/gallery/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..6e757f64c --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,71 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.galleries-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cgwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + applications: [ + { + name: '${namePrefix}-${serviceShort}-appd-001' + supportedOSType: 'Windows' + } + ] + images: [ + { + name: '${namePrefix}-az-imgd-ws-001' + identifier: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + } + osType: 'Windows' + osState: 'Generalized' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/compute/gallery/version.json b/avm/1.1.0/res/compute/gallery/version.json new file mode 100644 index 000000000..6b6be9389 --- /dev/null +++ b/avm/1.1.0/res/compute/gallery/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.9", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/image/README.md b/avm/1.1.0/res/compute/image/README.md new file mode 100644 index 000000000..3cc93b4b9 --- /dev/null +++ b/avm/1.1.0/res/compute/image/README.md @@ -0,0 +1,739 @@ +# Images `[Microsoft.Compute/images]` + +This module deploys a Compute Image. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Compute/images` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-07-01/images) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/compute/image:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module image 'br/public:avm/res/compute/image:' = { + name: 'imageDeployment' + params: { + // Required parameters + name: 'cimin001' + osAccountType: 'Standard_LRS' + osDiskBlobUri: '' + osDiskCaching: 'ReadWrite' + osType: 'Windows' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "cimin001" + }, + "osAccountType": { + "value": "Standard_LRS" + }, + "osDiskBlobUri": { + "value": "" + }, + "osDiskCaching": { + "value": "ReadWrite" + }, + "osType": { + "value": "Windows" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/image:' + +// Required parameters +param name = 'cimin001' +param osAccountType = 'Standard_LRS' +param osDiskBlobUri = '' +param osDiskCaching = 'ReadWrite' +param osType = 'Windows' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module image 'br/public:avm/res/compute/image:' = { + name: 'imageDeployment' + params: { + // Required parameters + name: 'cimax001' + osAccountType: 'Premium_LRS' + osDiskBlobUri: '' + osDiskCaching: 'ReadWrite' + osType: 'Windows' + // Non-required parameters + diskEncryptionSetResourceId: '' + diskSizeGB: 128 + hyperVGeneration: 'V1' + location: '' + osState: 'Generalized' + roleAssignments: [ + { + name: '2dfcdedd-220c-4b6b-b8bd-58e22e0c5434' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + zoneResilient: true + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "cimax001" + }, + "osAccountType": { + "value": "Premium_LRS" + }, + "osDiskBlobUri": { + "value": "" + }, + "osDiskCaching": { + "value": "ReadWrite" + }, + "osType": { + "value": "Windows" + }, + // Non-required parameters + "diskEncryptionSetResourceId": { + "value": "" + }, + "diskSizeGB": { + "value": 128 + }, + "hyperVGeneration": { + "value": "V1" + }, + "location": { + "value": "" + }, + "osState": { + "value": "Generalized" + }, + "roleAssignments": { + "value": [ + { + "name": "2dfcdedd-220c-4b6b-b8bd-58e22e0c5434", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "zoneResilient": { + "value": true + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/image:' + +// Required parameters +param name = 'cimax001' +param osAccountType = 'Premium_LRS' +param osDiskBlobUri = '' +param osDiskCaching = 'ReadWrite' +param osType = 'Windows' +// Non-required parameters +param diskEncryptionSetResourceId = '' +param diskSizeGB = 128 +param hyperVGeneration = 'V1' +param location = '' +param osState = 'Generalized' +param roleAssignments = [ + { + name: '2dfcdedd-220c-4b6b-b8bd-58e22e0c5434' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zoneResilient = true +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module image 'br/public:avm/res/compute/image:' = { + name: 'imageDeployment' + params: { + // Required parameters + name: 'ciwaf001' + osAccountType: 'Premium_LRS' + osDiskBlobUri: '' + osDiskCaching: 'ReadWrite' + osType: 'Windows' + // Non-required parameters + diskEncryptionSetResourceId: '' + diskSizeGB: 128 + hyperVGeneration: 'V1' + osState: 'Generalized' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + zoneResilient: true + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ciwaf001" + }, + "osAccountType": { + "value": "Premium_LRS" + }, + "osDiskBlobUri": { + "value": "" + }, + "osDiskCaching": { + "value": "ReadWrite" + }, + "osType": { + "value": "Windows" + }, + // Non-required parameters + "diskEncryptionSetResourceId": { + "value": "" + }, + "diskSizeGB": { + "value": 128 + }, + "hyperVGeneration": { + "value": "V1" + }, + "osState": { + "value": "Generalized" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "zoneResilient": { + "value": true + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/image:' + +// Required parameters +param name = 'ciwaf001' +param osAccountType = 'Premium_LRS' +param osDiskBlobUri = '' +param osDiskCaching = 'ReadWrite' +param osType = 'Windows' +// Non-required parameters +param diskEncryptionSetResourceId = '' +param diskSizeGB = 128 +param hyperVGeneration = 'V1' +param osState = 'Generalized' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zoneResilient = true +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the image. | +| [`osAccountType`](#parameter-osaccounttype) | string | Specifies the storage account type for the managed disk. NOTE: UltraSSD_LRS can only be used with data disks, it cannot be used with OS Disk. | +| [`osDiskBlobUri`](#parameter-osdiskbloburi) | string | The Virtual Hard Disk. | +| [`osDiskCaching`](#parameter-osdiskcaching) | string | Specifies the caching requirements. Default: None for Standard storage. ReadOnly for Premium storage. | +| [`osType`](#parameter-ostype) | string | This property allows you to specify the type of the OS that is included in the disk if creating a VM from a custom image. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dataDisks`](#parameter-datadisks) | array | Specifies the parameters that are used to add a data disk to a virtual machine. | +| [`diskEncryptionSetResourceId`](#parameter-diskencryptionsetresourceid) | string | Specifies the customer managed disk encryption set resource ID for the managed image disk. | +| [`diskSizeGB`](#parameter-disksizegb) | int | Specifies the size of empty data disks in gigabytes. This element can be used to overwrite the name of the disk in a virtual machine image. This value cannot be larger than 1023 GB. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`extendedLocation`](#parameter-extendedlocation) | object | The extended location of the Image. | +| [`hyperVGeneration`](#parameter-hypervgeneration) | string | Gets the HyperVGenerationType of the VirtualMachine created from the image. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`managedDiskResourceId`](#parameter-manageddiskresourceid) | string | The managedDisk. | +| [`osState`](#parameter-osstate) | string | The OS State. For managed images, use Generalized. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`snapshotResourceId`](#parameter-snapshotresourceid) | string | The snapshot resource ID. | +| [`sourceVirtualMachineResourceId`](#parameter-sourcevirtualmachineresourceid) | string | The source virtual machine from which Image is created. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`zoneResilient`](#parameter-zoneresilient) | bool | Default is false. Specifies whether an image is zone resilient or not. Zone resilient images can be created only in regions that provide Zone Redundant Storage (ZRS). | + +### Parameter: `name` + +The name of the image. + +- Required: Yes +- Type: string + +### Parameter: `osAccountType` + +Specifies the storage account type for the managed disk. NOTE: UltraSSD_LRS can only be used with data disks, it cannot be used with OS Disk. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Premium_LRS' + 'Standard_LRS' + 'StandardSSD_LRS' + 'UltraSSD_LRS' + ] + ``` + +### Parameter: `osDiskBlobUri` + +The Virtual Hard Disk. + +- Required: Yes +- Type: string + +### Parameter: `osDiskCaching` + +Specifies the caching requirements. Default: None for Standard storage. ReadOnly for Premium storage. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'None' + 'ReadOnly' + 'ReadWrite' + ] + ``` + +### Parameter: `osType` + +This property allows you to specify the type of the OS that is included in the disk if creating a VM from a custom image. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `dataDisks` + +Specifies the parameters that are used to add a data disk to a virtual machine. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `diskEncryptionSetResourceId` + +Specifies the customer managed disk encryption set resource ID for the managed image disk. + +- Required: No +- Type: string + +### Parameter: `diskSizeGB` + +Specifies the size of empty data disks in gigabytes. This element can be used to overwrite the name of the disk in a virtual machine image. This value cannot be larger than 1023 GB. + +- Required: No +- Type: int +- Default: `128` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `extendedLocation` + +The extended location of the Image. + +- Required: No +- Type: object + +### Parameter: `hyperVGeneration` + +Gets the HyperVGenerationType of the VirtualMachine created from the image. + +- Required: No +- Type: string +- Default: `'V1'` +- Allowed: + ```Bicep + [ + 'V1' + 'V2' + ] + ``` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `managedDiskResourceId` + +The managedDisk. + +- Required: No +- Type: string + +### Parameter: `osState` + +The OS State. For managed images, use Generalized. + +- Required: No +- Type: string +- Default: `'Generalized'` +- Allowed: + ```Bicep + [ + 'Generalized' + 'Specialized' + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `snapshotResourceId` + +The snapshot resource ID. + +- Required: No +- Type: string + +### Parameter: `sourceVirtualMachineResourceId` + +The source virtual machine from which Image is created. + +- Required: No +- Type: string + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `zoneResilient` + +Default is false. Specifies whether an image is zone resilient or not. Zone resilient images can be created only in regions that provide Zone Redundant Storage (ZRS). + +- Required: No +- Type: bool +- Default: `False` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the image. | +| `resourceGroupName` | string | The resource group the image was deployed into. | +| `resourceId` | string | The resource ID of the image. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.4.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/compute/image/main.bicep b/avm/1.1.0/res/compute/image/main.bicep new file mode 100644 index 000000000..25cbe11fb --- /dev/null +++ b/avm/1.1.0/res/compute/image/main.bicep @@ -0,0 +1,197 @@ +metadata name = 'Images' +metadata description = 'This module deploys a Compute Image.' + +@description('Required. The name of the image.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Required. The Virtual Hard Disk.') +param osDiskBlobUri string + +@description('Required. This property allows you to specify the type of the OS that is included in the disk if creating a VM from a custom image.') +@allowed([ + 'Windows' + 'Linux' +]) +param osType string + +@description('Required. Specifies the caching requirements. Default: None for Standard storage. ReadOnly for Premium storage.') +@allowed([ + 'None' + 'ReadOnly' + 'ReadWrite' +]) +param osDiskCaching string + +@description('Required. Specifies the storage account type for the managed disk. NOTE: UltraSSD_LRS can only be used with data disks, it cannot be used with OS Disk.') +@allowed([ + 'Standard_LRS' + 'Premium_LRS' + 'StandardSSD_LRS' + 'UltraSSD_LRS' +]) +param osAccountType string + +@description('Optional. Default is false. Specifies whether an image is zone resilient or not. Zone resilient images can be created only in regions that provide Zone Redundant Storage (ZRS).') +param zoneResilient bool = false + +@description('Optional. Gets the HyperVGenerationType of the VirtualMachine created from the image.') +@allowed([ + 'V1' + 'V2' +]) +param hyperVGeneration string = 'V1' + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.4.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. The extended location of the Image.') +param extendedLocation object? + +@description('Optional. The source virtual machine from which Image is created.') +param sourceVirtualMachineResourceId string? + +@description('Optional. Specifies the customer managed disk encryption set resource ID for the managed image disk.') +param diskEncryptionSetResourceId string? + +@description('Optional. The managedDisk.') +param managedDiskResourceId string? + +@description('Optional. Specifies the size of empty data disks in gigabytes. This element can be used to overwrite the name of the disk in a virtual machine image. This value cannot be larger than 1023 GB.') +param diskSizeGB int = 128 + +@description('Optional. The OS State. For managed images, use Generalized.') +@allowed([ + 'Generalized' + 'Specialized' +]) +param osState string = 'Generalized' + +@description('Optional. The snapshot resource ID.') +param snapshotResourceId string? + +@description('Optional. Specifies the parameters that are used to add a data disk to a virtual machine.') +param dataDisks array = [] + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.compute-image.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource image 'Microsoft.Compute/images@2024-07-01' = { + name: name + location: location + tags: tags + extendedLocation: extendedLocation + properties: { + storageProfile: { + osDisk: { + osType: osType + blobUri: osDiskBlobUri + caching: osDiskCaching + storageAccountType: osAccountType + osState: osState + diskEncryptionSet: !empty(diskEncryptionSetResourceId) + ? { + id: diskEncryptionSetResourceId + } + : null + diskSizeGB: diskSizeGB + managedDisk: !empty(managedDiskResourceId) + ? { + id: managedDiskResourceId + } + : null + snapshot: !empty(snapshotResourceId) + ? { + id: snapshotResourceId + } + : null + } + dataDisks: dataDisks + zoneResilient: zoneResilient + } + hyperVGeneration: hyperVGeneration + sourceVirtualMachine: !empty(sourceVirtualMachineResourceId) + ? { + id: sourceVirtualMachineResourceId + } + : null + } +} + +resource image_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(image.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: image + } +] + +@description('The resource ID of the image.') +output resourceId string = image.id + +@description('The resource group the image was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the image.') +output name string = image.name + +@description('The location the resource was deployed into.') +output location string = image.location diff --git a/avm/1.1.0/res/compute/image/main.json b/avm/1.1.0/res/compute/image/main.json new file mode 100644 index 000000000..acf742793 --- /dev/null +++ b/avm/1.1.0/res/compute/image/main.json @@ -0,0 +1,364 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3106672883286346461" + }, + "name": "Images", + "description": "This module deploys a Compute Image." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the image." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "osDiskBlobUri": { + "type": "string", + "metadata": { + "description": "Required. The Virtual Hard Disk." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. This property allows you to specify the type of the OS that is included in the disk if creating a VM from a custom image." + } + }, + "osDiskCaching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "metadata": { + "description": "Required. Specifies the caching requirements. Default: None for Standard storage. ReadOnly for Premium storage." + } + }, + "osAccountType": { + "type": "string", + "allowedValues": [ + "Standard_LRS", + "Premium_LRS", + "StandardSSD_LRS", + "UltraSSD_LRS" + ], + "metadata": { + "description": "Required. Specifies the storage account type for the managed disk. NOTE: UltraSSD_LRS can only be used with data disks, it cannot be used with OS Disk." + } + }, + "zoneResilient": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Default is false. Specifies whether an image is zone resilient or not. Zone resilient images can be created only in regions that provide Zone Redundant Storage (ZRS)." + } + }, + "hyperVGeneration": { + "type": "string", + "defaultValue": "V1", + "allowedValues": [ + "V1", + "V2" + ], + "metadata": { + "description": "Optional. Gets the HyperVGenerationType of the VirtualMachine created from the image." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "extendedLocation": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The extended location of the Image." + } + }, + "sourceVirtualMachineResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source virtual machine from which Image is created." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource ID for the managed image disk." + } + }, + "managedDiskResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The managedDisk." + } + }, + "diskSizeGB": { + "type": "int", + "defaultValue": 128, + "metadata": { + "description": "Optional. Specifies the size of empty data disks in gigabytes. This element can be used to overwrite the name of the disk in a virtual machine image. This value cannot be larger than 1023 GB." + } + }, + "osState": { + "type": "string", + "defaultValue": "Generalized", + "allowedValues": [ + "Generalized", + "Specialized" + ], + "metadata": { + "description": "Optional. The OS State. For managed images, use Generalized." + } + }, + "snapshotResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The snapshot resource ID." + } + }, + "dataDisks": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies the parameters that are used to add a data disk to a virtual machine." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.compute-image.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "image": { + "type": "Microsoft.Compute/images", + "apiVersion": "2024-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "extendedLocation": "[parameters('extendedLocation')]", + "properties": { + "storageProfile": { + "osDisk": { + "osType": "[parameters('osType')]", + "blobUri": "[parameters('osDiskBlobUri')]", + "caching": "[parameters('osDiskCaching')]", + "storageAccountType": "[parameters('osAccountType')]", + "osState": "[parameters('osState')]", + "diskEncryptionSet": "[if(not(empty(parameters('diskEncryptionSetResourceId'))), createObject('id', parameters('diskEncryptionSetResourceId')), null())]", + "diskSizeGB": "[parameters('diskSizeGB')]", + "managedDisk": "[if(not(empty(parameters('managedDiskResourceId'))), createObject('id', parameters('managedDiskResourceId')), null())]", + "snapshot": "[if(not(empty(parameters('snapshotResourceId'))), createObject('id', parameters('snapshotResourceId')), null())]" + }, + "dataDisks": "[parameters('dataDisks')]", + "zoneResilient": "[parameters('zoneResilient')]" + }, + "hyperVGeneration": "[parameters('hyperVGeneration')]", + "sourceVirtualMachine": "[if(not(empty(parameters('sourceVirtualMachineResourceId'))), createObject('id', parameters('sourceVirtualMachineResourceId')), null())]" + } + }, + "image_roleAssignments": { + "copy": { + "name": "image_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/images/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/images', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "image" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the image." + }, + "value": "[resourceId('Microsoft.Compute/images', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the image was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the image." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('image', '2024-07-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/image/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/compute/image/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..071f61a57 --- /dev/null +++ b/avm/1.1.0/res/compute/image/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,154 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create and to copy the VHD into.') +param storageAccountName string + +@description('Required. The name prefix of the Image Template to create.') +param imageTemplateNamePrefix string + +@description('Generated. Do not provide a value! This date value is used to generate a unique image template name.') +param baseTime string = utcNow('yyyy-MM-dd-HH-mm-ss') + +@description('Required. The name of the Deployment Script to create for triggering the image creation.') +param triggerImageDeploymentScriptName string + +@description('Required. The name of the Deployment Script to copy the VHD to a destination storage account.') +param copyVhdDeploymentScriptName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: storageAccountName + location: location + kind: 'StorageV2' + sku: { + name: 'Standard_LRS' + } + properties: { + allowBlobPublicAccess: false + } + resource blobServices 'blobServices@2022-09-01' = { + name: 'default' + resource container 'containers@2022-09-01' = { + name: 'vhds' + properties: { + publicAccess: 'None' + } + } + } +} + +resource resourceGroupContributorRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().subscriptionId, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalId: managedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +// Deploy image template +resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2022-02-14' = { + #disable-next-line use-stable-resource-identifiers + name: '${imageTemplateNamePrefix}-${baseTime}' + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + buildTimeoutInMinutes: 0 + vmProfile: { + vmSize: 'Standard_D2s_v3' + osDiskSizeGB: 127 + } + source: { + type: 'PlatformImage' + publisher: 'MicrosoftWindowsDesktop' + offer: 'Windows-11' + sku: 'win11-21h2-avd' + version: 'latest' + } + distribute: [ + { + type: 'VHD' + runOutputName: '${imageTemplateNamePrefix}-VHD' + artifactTags: {} + } + ] + customize: [ + { + restartTimeout: '30m' + type: 'WindowsRestart' + } + ] + } +} + +// Trigger VHD creation +resource triggerImageDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: triggerImageDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '11.5' // Source: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list + retentionInterval: 'P1D' + arguments: '-ImageTemplateName \\"${imageTemplate.name}\\" -ImageTemplateResourceGroup \\"${resourceGroup().name}\\"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Start-ImageTemplate.ps1') + cleanupPreference: 'OnSuccess' + forceUpdateTag: baseTime + } + dependsOn: [ + resourceGroupContributorRole + ] +} + +// Copy VHD to destination storage account +resource copyVhdDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: copyVhdDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '11.5' // Source: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list + retentionInterval: 'P1D' + arguments: '-ImageTemplateName \\"${imageTemplate.name}\\" -ImageTemplateResourceGroup \\"${resourceGroup().name}\\" -DestinationStorageAccountName \\"${storageAccount.name}\\" -VhdName \\"${imageTemplateNamePrefix}\\" -WaitForComplete' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Copy-VhdToStorageAccount.ps1') + cleanupPreference: 'OnSuccess' + forceUpdateTag: baseTime + } + dependsOn: [triggerImageDeploymentScript] +} + +@description('The URI of the created VHD.') +output vhdUri string = 'https://${storageAccount.name}.blob.${environment().suffixes.storage}/vhds/${imageTemplateNamePrefix}.vhd' + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/avm/1.1.0/res/compute/image/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/compute/image/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..fb280ff53 --- /dev/null +++ b/avm/1.1.0/res/compute/image/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,69 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +// e.g., for a module 'network/private-endpoint' you could use 'dep-dev-network.privateendpoints-${serviceShort}-rg' +param resourceGroupName string = 'dep-${namePrefix}-compute.images-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +// e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test +param serviceShort string = 'cimin' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + storageAccountName: 'dep${namePrefix}sa${serviceShort}${substring(uniqueString(baseTime), 0, 3)}' + imageTemplateNamePrefix: 'dep-${namePrefix}-imgt-${serviceShort}' + triggerImageDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}-triggerImageTemplate' + copyVhdDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}-copyVhdToStorage' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + osAccountType: 'Standard_LRS' + osDiskBlobUri: nestedDependencies.outputs.vhdUri + osDiskCaching: 'ReadWrite' + osType: 'Windows' + } + } +] diff --git a/avm/1.1.0/res/compute/image/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/compute/image/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..1c43483a9 --- /dev/null +++ b/avm/1.1.0/res/compute/image/tests/e2e/max/dependencies.bicep @@ -0,0 +1,242 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create and to copy the VHD into.') +param storageAccountName string + +@description('Required. The name of the Disk Encryption Set to create.') +param diskEncryptionSetName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name prefix of the Image Template to create.') +param imageTemplateNamePrefix string + +@description('Generated. Do not provide a value! This date value is used to generate a unique image template name.') +param baseTime string = utcNow('yyyy-MM-dd-HH-mm-ss') + +@description('Required. The name of the Deployment Script to create for triggering the image creation.') +param triggerImageDeploymentScriptName string + +@description('Required. The name of the Deployment Script to copy the VHD to a destination storage account.') +param copyVhdDeploymentScriptName string + +@description('Required. The name of the deployment script that waits for a role assignment to propagate.') +param waitDeploymentScriptName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: storageAccountName + location: location + kind: 'StorageV2' + sku: { + name: 'Standard_LRS' + } + properties: { + allowBlobPublicAccess: false + } + resource blobServices 'blobServices@2022-09-01' = { + name: 'default' + resource container 'containers@2022-09-01' = { + name: 'vhds' + properties: { + publicAccess: 'None' + } + } + } +} + +resource resourceGroupContributorRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().subscriptionId, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalId: managedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +// Deploy image template +resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2022-02-14' = { + #disable-next-line use-stable-resource-identifiers + name: '${imageTemplateNamePrefix}-${baseTime}' + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + buildTimeoutInMinutes: 0 + vmProfile: { + vmSize: 'Standard_D2s_v3' + osDiskSizeGB: 127 + } + source: { + type: 'PlatformImage' + publisher: 'MicrosoftWindowsDesktop' + offer: 'Windows-11' + sku: 'win11-21h2-avd' + version: 'latest' + } + distribute: [ + { + type: 'VHD' + runOutputName: '${imageTemplateNamePrefix}-VHD' + artifactTags: {} + } + ] + customize: [ + { + restartTimeout: '30m' + type: 'WindowsRestart' + } + ] + } +} + +// Trigger VHD creation +resource triggerImageDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: triggerImageDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '11.5' // Source: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list + retentionInterval: 'P1D' + arguments: '-ImageTemplateName \\"${imageTemplate.name}\\" -ImageTemplateResourceGroup \\"${resourceGroup().name}\\"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Start-ImageTemplate.ps1') + cleanupPreference: 'OnSuccess' + forceUpdateTag: baseTime + } + dependsOn: [ + resourceGroupContributorRole + ] +} + +// Copy VHD to destination storage account +resource copyVhdDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: copyVhdDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '11.5' // Source: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list + retentionInterval: 'P1D' + arguments: '-ImageTemplateName \\"${imageTemplate.name}\\" -ImageTemplateResourceGroup \\"${resourceGroup().name}\\" -DestinationStorageAccountName \\"${storageAccount.name}\\" -VhdName \\"${imageTemplateNamePrefix}\\" -WaitForComplete' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Copy-VhdToStorageAccount.ps1') + cleanupPreference: 'OnSuccess' + forceUpdateTag: baseTime + } + dependsOn: [ + triggerImageDeploymentScript + ] +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'encryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource keyVaultKeyCryptoRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-Key-RoleAssignment') + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +// Waiting for the role assignment to propagate +resource waitForDeployment 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + dependsOn: [keyVaultKeyCryptoRole] + name: waitDeploymentScriptName + location: location + kind: 'AzurePowerShell' + properties: { + retentionInterval: 'PT1H' + azPowerShellVersion: '11.0' + cleanupPreference: 'Always' + scriptContent: 'write-output "Sleeping for 15"; start-sleep -Seconds 15' + } +} + +resource diskEncryptionSet 'Microsoft.Compute/diskEncryptionSets@2023-10-02' = { + dependsOn: [waitForDeployment] + name: diskEncryptionSetName + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + activeKey: { + sourceVault: { + id: keyVault.id + } + keyUrl: keyVault::key.properties.keyUriWithVersion + } + encryptionType: 'EncryptionAtRestWithCustomerKey' + } +} + +@description('The URI of the created VHD.') +output vhdUri string = 'https://${storageAccount.name}.blob.${environment().suffixes.storage}/vhds/${imageTemplateNamePrefix}.vhd' + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Disk Encryption Set.') +output diskEncryptionSetResourceId string = diskEncryptionSet.id diff --git a/avm/1.1.0/res/compute/image/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/compute/image/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..406f8faef --- /dev/null +++ b/avm/1.1.0/res/compute/image/tests/e2e/max/main.test.bicep @@ -0,0 +1,103 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.images-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cimax' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + diskEncryptionSetName: 'dep-${namePrefix}-des-${serviceShort}' + storageAccountName: 'dep${namePrefix}sa${serviceShort}${substring(uniqueString(baseTime), 0, 3)}' + imageTemplateNamePrefix: 'dep-${namePrefix}-imgt-${serviceShort}' + triggerImageDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}-triggerImageTemplate' + copyVhdDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}-copyVhdToStorage' + waitDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}-waitForPropagation' + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + osAccountType: 'Premium_LRS' + osDiskBlobUri: nestedDependencies.outputs.vhdUri + osDiskCaching: 'ReadWrite' + osType: 'Windows' + hyperVGeneration: 'V1' + roleAssignments: [ + { + name: '2dfcdedd-220c-4b6b-b8bd-58e22e0c5434' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + zoneResilient: true + diskEncryptionSetResourceId: nestedDependencies.outputs.diskEncryptionSetResourceId + osState: 'Generalized' + diskSizeGB: 128 + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/compute/image/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/compute/image/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..1c43483a9 --- /dev/null +++ b/avm/1.1.0/res/compute/image/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,242 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create and to copy the VHD into.') +param storageAccountName string + +@description('Required. The name of the Disk Encryption Set to create.') +param diskEncryptionSetName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name prefix of the Image Template to create.') +param imageTemplateNamePrefix string + +@description('Generated. Do not provide a value! This date value is used to generate a unique image template name.') +param baseTime string = utcNow('yyyy-MM-dd-HH-mm-ss') + +@description('Required. The name of the Deployment Script to create for triggering the image creation.') +param triggerImageDeploymentScriptName string + +@description('Required. The name of the Deployment Script to copy the VHD to a destination storage account.') +param copyVhdDeploymentScriptName string + +@description('Required. The name of the deployment script that waits for a role assignment to propagate.') +param waitDeploymentScriptName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: storageAccountName + location: location + kind: 'StorageV2' + sku: { + name: 'Standard_LRS' + } + properties: { + allowBlobPublicAccess: false + } + resource blobServices 'blobServices@2022-09-01' = { + name: 'default' + resource container 'containers@2022-09-01' = { + name: 'vhds' + properties: { + publicAccess: 'None' + } + } + } +} + +resource resourceGroupContributorRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().subscriptionId, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalId: managedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +// Deploy image template +resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2022-02-14' = { + #disable-next-line use-stable-resource-identifiers + name: '${imageTemplateNamePrefix}-${baseTime}' + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + buildTimeoutInMinutes: 0 + vmProfile: { + vmSize: 'Standard_D2s_v3' + osDiskSizeGB: 127 + } + source: { + type: 'PlatformImage' + publisher: 'MicrosoftWindowsDesktop' + offer: 'Windows-11' + sku: 'win11-21h2-avd' + version: 'latest' + } + distribute: [ + { + type: 'VHD' + runOutputName: '${imageTemplateNamePrefix}-VHD' + artifactTags: {} + } + ] + customize: [ + { + restartTimeout: '30m' + type: 'WindowsRestart' + } + ] + } +} + +// Trigger VHD creation +resource triggerImageDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: triggerImageDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '11.5' // Source: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list + retentionInterval: 'P1D' + arguments: '-ImageTemplateName \\"${imageTemplate.name}\\" -ImageTemplateResourceGroup \\"${resourceGroup().name}\\"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Start-ImageTemplate.ps1') + cleanupPreference: 'OnSuccess' + forceUpdateTag: baseTime + } + dependsOn: [ + resourceGroupContributorRole + ] +} + +// Copy VHD to destination storage account +resource copyVhdDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: copyVhdDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '11.5' // Source: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list + retentionInterval: 'P1D' + arguments: '-ImageTemplateName \\"${imageTemplate.name}\\" -ImageTemplateResourceGroup \\"${resourceGroup().name}\\" -DestinationStorageAccountName \\"${storageAccount.name}\\" -VhdName \\"${imageTemplateNamePrefix}\\" -WaitForComplete' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Copy-VhdToStorageAccount.ps1') + cleanupPreference: 'OnSuccess' + forceUpdateTag: baseTime + } + dependsOn: [ + triggerImageDeploymentScript + ] +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'encryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource keyVaultKeyCryptoRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-Key-RoleAssignment') + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +// Waiting for the role assignment to propagate +resource waitForDeployment 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + dependsOn: [keyVaultKeyCryptoRole] + name: waitDeploymentScriptName + location: location + kind: 'AzurePowerShell' + properties: { + retentionInterval: 'PT1H' + azPowerShellVersion: '11.0' + cleanupPreference: 'Always' + scriptContent: 'write-output "Sleeping for 15"; start-sleep -Seconds 15' + } +} + +resource diskEncryptionSet 'Microsoft.Compute/diskEncryptionSets@2023-10-02' = { + dependsOn: [waitForDeployment] + name: diskEncryptionSetName + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + activeKey: { + sourceVault: { + id: keyVault.id + } + keyUrl: keyVault::key.properties.keyUriWithVersion + } + encryptionType: 'EncryptionAtRestWithCustomerKey' + } +} + +@description('The URI of the created VHD.') +output vhdUri string = 'https://${storageAccount.name}.blob.${environment().suffixes.storage}/vhds/${imageTemplateNamePrefix}.vhd' + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Disk Encryption Set.') +output diskEncryptionSetResourceId string = diskEncryptionSet.id diff --git a/avm/1.1.0/res/compute/image/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/compute/image/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..6a374eb41 --- /dev/null +++ b/avm/1.1.0/res/compute/image/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,80 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.images-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ciwaf' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + diskEncryptionSetName: 'dep-${namePrefix}-des-${serviceShort}' + storageAccountName: 'dep${namePrefix}sa${serviceShort}${substring(uniqueString(baseTime), 0, 3)}' + imageTemplateNamePrefix: 'dep-${namePrefix}-imgt-${serviceShort}' + triggerImageDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}-triggerImageTemplate' + copyVhdDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}-copyVhdToStorage' + waitDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}-waitForPropagation' + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + osAccountType: 'Premium_LRS' + osDiskBlobUri: nestedDependencies.outputs.vhdUri + osDiskCaching: 'ReadWrite' + osType: 'Windows' + hyperVGeneration: 'V1' + zoneResilient: true + diskEncryptionSetResourceId: nestedDependencies.outputs.diskEncryptionSetResourceId + osState: 'Generalized' + diskSizeGB: 128 + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/compute/image/version.json b/avm/1.1.0/res/compute/image/version.json new file mode 100644 index 000000000..c177b1bb5 --- /dev/null +++ b/avm/1.1.0/res/compute/image/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/proximity-placement-group/README.md b/avm/1.1.0/res/compute/proximity-placement-group/README.md new file mode 100644 index 000000000..5da6adc55 --- /dev/null +++ b/avm/1.1.0/res/compute/proximity-placement-group/README.md @@ -0,0 +1,682 @@ +# Proximity Placement Groups `[Microsoft.Compute/proximityPlacementGroups]` + +This module deploys a Proximity Placement Group. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Compute/proximityPlacementGroups` | [2022-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-08-01/proximityPlacementGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/compute/proximity-placement-group:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-group:' = { + name: 'proximityPlacementGroupDeployment' + params: { + // Required parameters + name: 'cppgmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "cppgmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/proximity-placement-group:' + +// Required parameters +param name = 'cppgmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-group:' = { + name: 'proximityPlacementGroupDeployment' + params: { + // Required parameters + name: 'cppgmax001' + // Non-required parameters + colocationStatus: { + code: 'ColocationStatus/Aligned' + displayStatus: 'Aligned' + level: 'Info' + message: 'I\'m a default error message' + } + intent: { + vmSizes: [ + 'Standard_B1ms' + 'Standard_B4ms' + ] + } + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '9e0b6b99-ff4b-4c99-a2ce-3a2a1a880874' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + TagA: 'Would you kindly...' + TagB: 'Tags for sale' + } + type: 'Standard' + zones: [ + '1' + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "cppgmax001" + }, + // Non-required parameters + "colocationStatus": { + "value": { + "code": "ColocationStatus/Aligned", + "displayStatus": "Aligned", + "level": "Info", + "message": "I\"m a default error message" + } + }, + "intent": { + "value": { + "vmSizes": [ + "Standard_B1ms", + "Standard_B4ms" + ] + } + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "9e0b6b99-ff4b-4c99-a2ce-3a2a1a880874", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name", + "TagA": "Would you kindly...", + "TagB": "Tags for sale" + } + }, + "type": { + "value": "Standard" + }, + "zones": { + "value": [ + "1" + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/proximity-placement-group:' + +// Required parameters +param name = 'cppgmax001' +// Non-required parameters +param colocationStatus = { + code: 'ColocationStatus/Aligned' + displayStatus: 'Aligned' + level: 'Info' + message: 'I\'m a default error message' +} +param intent = { + vmSizes: [ + 'Standard_B1ms' + 'Standard_B4ms' + ] +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '9e0b6b99-ff4b-4c99-a2ce-3a2a1a880874' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 'hidden-title': 'This is visible in the resource name' + TagA: 'Would you kindly...' + TagB: 'Tags for sale' +} +param type = 'Standard' +param zones = [ + '1' +] +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-group:' = { + name: 'proximityPlacementGroupDeployment' + params: { + // Required parameters + name: 'cppgwaf001' + // Non-required parameters + colocationStatus: { + code: 'ColocationStatus/Aligned' + displayStatus: 'Aligned' + level: 'Info' + message: 'I\'m a default error message' + } + intent: { + vmSizes: [ + 'Standard_B1ms' + 'Standard_B4ms' + ] + } + location: '' + tags: { + 'hidden-title': 'This is visible in the resource name' + TagA: 'Would you kindly...' + TagB: 'Tags for sale' + } + type: 'Standard' + zones: [ + '1' + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "cppgwaf001" + }, + // Non-required parameters + "colocationStatus": { + "value": { + "code": "ColocationStatus/Aligned", + "displayStatus": "Aligned", + "level": "Info", + "message": "I\"m a default error message" + } + }, + "intent": { + "value": { + "vmSizes": [ + "Standard_B1ms", + "Standard_B4ms" + ] + } + }, + "location": { + "value": "" + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name", + "TagA": "Would you kindly...", + "TagB": "Tags for sale" + } + }, + "type": { + "value": "Standard" + }, + "zones": { + "value": [ + "1" + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/proximity-placement-group:' + +// Required parameters +param name = 'cppgwaf001' +// Non-required parameters +param colocationStatus = { + code: 'ColocationStatus/Aligned' + displayStatus: 'Aligned' + level: 'Info' + message: 'I\'m a default error message' +} +param intent = { + vmSizes: [ + 'Standard_B1ms' + 'Standard_B4ms' + ] +} +param location = '' +param tags = { + 'hidden-title': 'This is visible in the resource name' + TagA: 'Would you kindly...' + TagB: 'Tags for sale' +} +param type = 'Standard' +param zones = [ + '1' +] +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the proximity placement group that is being created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`colocationStatus`](#parameter-colocationstatus) | object | Describes colocation status of the Proximity Placement Group. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`intent`](#parameter-intent) | object | Specifies the user intent of the proximity placement group. | +| [`location`](#parameter-location) | string | Resource location. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the proximity placement group resource. | +| [`type`](#parameter-type) | string | Specifies the type of the proximity placement group. | +| [`zones`](#parameter-zones) | array | Specifies the Availability Zone where virtual machine, virtual machine scale set or availability set associated with the proximity placement group can be created. | + +### Parameter: `name` + +The name of the proximity placement group that is being created. + +- Required: Yes +- Type: string + +### Parameter: `colocationStatus` + +Describes colocation status of the Proximity Placement Group. + +- Required: No +- Type: object + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `intent` + +Specifies the user intent of the proximity placement group. + +- Required: No +- Type: object + +### Parameter: `location` + +Resource location. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the proximity placement group resource. + +- Required: No +- Type: object + +### Parameter: `type` + +Specifies the type of the proximity placement group. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Standard' + 'Ultra' + ] + ``` + +### Parameter: `zones` + +Specifies the Availability Zone where virtual machine, virtual machine scale set or availability set associated with the proximity placement group can be created. + +- Required: No +- Type: array + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the proximity placement group. | +| `resourceGroupName` | string | The resource group the proximity placement group was deployed into. | +| `resourceId` | string | The resourceId the proximity placement group. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/compute/proximity-placement-group/main.bicep b/avm/1.1.0/res/compute/proximity-placement-group/main.bicep new file mode 100644 index 000000000..5af9f4994 --- /dev/null +++ b/avm/1.1.0/res/compute/proximity-placement-group/main.bicep @@ -0,0 +1,173 @@ +metadata name = 'Proximity Placement Groups' +metadata description = 'This module deploys a Proximity Placement Group.' + +@description('Required. The name of the proximity placement group that is being created.') +param name string + +@description('Optional. Specifies the type of the proximity placement group.') +@allowed([ + 'Standard' + 'Ultra' +]) +param type string = 'Standard' + +@description('Optional. Resource location.') +param location string = resourceGroup().location + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the proximity placement group resource.') +param tags object? + +@description('Optional. Specifies the Availability Zone where virtual machine, virtual machine scale set or availability set associated with the proximity placement group can be created.') +param zones array? + +@description('Optional. Describes colocation status of the Proximity Placement Group.') +param colocationStatus object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Specifies the user intent of the proximity placement group.') +param intent object? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.compute-proximityplacementgroup.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource proximityPlacementGroup 'Microsoft.Compute/proximityPlacementGroups@2022-08-01' = { + name: name + location: location + tags: tags + zones: zones + properties: { + proximityPlacementGroupType: type + colocationStatus: colocationStatus + intent: intent + } +} + +resource proximityPlacementGroup_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: proximityPlacementGroup +} + +resource proximityPlacementGroup_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + proximityPlacementGroup.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: proximityPlacementGroup + } +] + +@description('The name of the proximity placement group.') +output name string = proximityPlacementGroup.name + +@description('The resourceId the proximity placement group.') +output resourceId string = proximityPlacementGroup.id + +@description('The resource group the proximity placement group was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = proximityPlacementGroup.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/compute/proximity-placement-group/main.json b/avm/1.1.0/res/compute/proximity-placement-group/main.json new file mode 100644 index 000000000..bdc0cd238 --- /dev/null +++ b/avm/1.1.0/res/compute/proximity-placement-group/main.json @@ -0,0 +1,304 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "17441221183640310554" + }, + "name": "Proximity Placement Groups", + "description": "This module deploys a Proximity Placement Group." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the proximity placement group that is being created." + } + }, + "type": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Standard", + "Ultra" + ], + "metadata": { + "description": "Optional. Specifies the type of the proximity placement group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Resource location." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the proximity placement group resource." + } + }, + "zones": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the Availability Zone where virtual machine, virtual machine scale set or availability set associated with the proximity placement group can be created." + } + }, + "colocationStatus": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Describes colocation status of the Proximity Placement Group." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "intent": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the user intent of the proximity placement group." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.compute-proximityplacementgroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "proximityPlacementGroup": { + "type": "Microsoft.Compute/proximityPlacementGroups", + "apiVersion": "2022-08-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "zones": "[parameters('zones')]", + "properties": { + "proximityPlacementGroupType": "[parameters('type')]", + "colocationStatus": "[parameters('colocationStatus')]", + "intent": "[parameters('intent')]" + } + }, + "proximityPlacementGroup_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Compute/proximityPlacementGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "proximityPlacementGroup" + ] + }, + "proximityPlacementGroup_roleAssignments": { + "copy": { + "name": "proximityPlacementGroup_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/proximityPlacementGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/proximityPlacementGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "proximityPlacementGroup" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the proximity placement group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resourceId the proximity placement group." + }, + "value": "[resourceId('Microsoft.Compute/proximityPlacementGroups', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the proximity placement group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('proximityPlacementGroup', '2022-08-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..31714c6f0 --- /dev/null +++ b/avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.proximityplacementgroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cppgmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..ae14f18cc --- /dev/null +++ b/avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/max/main.test.bicep @@ -0,0 +1,104 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.proximityplacementgroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cppgmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '9e0b6b99-ff4b-4c99-a2ce-3a2a1a880874' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + zones: [ + '1' + ] + type: 'Standard' + tags: { + 'hidden-title': 'This is visible in the resource name' + TagA: 'Would you kindly...' + TagB: 'Tags for sale' + } + colocationStatus: { + code: 'ColocationStatus/Aligned' + displayStatus: 'Aligned' + level: 'Info' + message: 'I\'m a default error message' + } + intent: { + vmSizes: [ + 'Standard_B1ms' + 'Standard_B4ms' + ] + } + } + } +] diff --git a/avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..b98da1299 --- /dev/null +++ b/avm/1.1.0/res/compute/proximity-placement-group/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,69 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.proximityplacementgroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cppgwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + zones: [ + '1' + ] + type: 'Standard' + tags: { + 'hidden-title': 'This is visible in the resource name' + TagA: 'Would you kindly...' + TagB: 'Tags for sale' + } + colocationStatus: { + code: 'ColocationStatus/Aligned' + displayStatus: 'Aligned' + level: 'Info' + message: 'I\'m a default error message' + } + intent: { + vmSizes: [ + 'Standard_B1ms' + 'Standard_B4ms' + ] + } + } + } +] diff --git a/avm/1.1.0/res/compute/proximity-placement-group/version.json b/avm/1.1.0/res/compute/proximity-placement-group/version.json new file mode 100644 index 000000000..c177b1bb5 --- /dev/null +++ b/avm/1.1.0/res/compute/proximity-placement-group/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/ssh-public-key/README.md b/avm/1.1.0/res/compute/ssh-public-key/README.md new file mode 100644 index 000000000..0edc87a24 --- /dev/null +++ b/avm/1.1.0/res/compute/ssh-public-key/README.md @@ -0,0 +1,627 @@ +# Public SSH Keys `[Microsoft.Compute/sshPublicKeys]` + +This module deploys a Public SSH Key. + +> Note: The resource does not auto-generate the key for you. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Compute/sshPublicKeys` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-03-01/sshPublicKeys) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/compute/ssh-public-key:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = { + name: 'sshPublicKeyDeployment' + params: { + // Required parameters + name: 'cspkmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "cspkmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/ssh-public-key:' + +// Required parameters +param name = 'cspkmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = { + name: 'sshPublicKeyDeployment' + params: { + // Required parameters + name: 'sshkey-cspkmax001' + // Non-required parameters + enableTelemetry: true + location: '' + lock: { + kind: 'CanNotDelete' + name: 'lock' + } + publicKey: '' + roleAssignments: [ + { + name: '74ec0421-c3f4-46f2-acf0-b519fe6fcf1c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "sshkey-cspkmax001" + }, + // Non-required parameters + "enableTelemetry": { + "value": true + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "lock" + } + }, + "publicKey": { + "value": "" + }, + "roleAssignments": { + "value": [ + { + "name": "74ec0421-c3f4-46f2-acf0-b519fe6fcf1c", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/ssh-public-key:' + +// Required parameters +param name = 'sshkey-cspkmax001' +// Non-required parameters +param enableTelemetry = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'lock' +} +param publicKey = '' +param roleAssignments = [ + { + name: '74ec0421-c3f4-46f2-acf0-b519fe6fcf1c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = { + name: 'sshPublicKeyDeployment' + params: { + // Required parameters + name: 'sshkey-cspkwaf001' + // Non-required parameters + enableTelemetry: true + location: '' + lock: { + kind: 'CanNotDelete' + name: 'lock' + } + publicKey: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "sshkey-cspkwaf001" + }, + // Non-required parameters + "enableTelemetry": { + "value": true + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "lock" + } + }, + "publicKey": { + "value": "" + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/ssh-public-key:' + +// Required parameters +param name = 'sshkey-cspkwaf001' +// Non-required parameters +param enableTelemetry = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'lock' +} +param publicKey = '' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the SSH public Key that is being created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Resource location. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`publicKey`](#parameter-publickey) | string | SSH public key used to authenticate to a virtual machine through SSH. If this property is not initially provided when the resource is created, the publicKey property will be populated when generateKeyPair is called. If the public key is provided upon resource creation, the provided public key needs to be at least 2048-bit and in ssh-rsa format. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the availability set resource. | + +### Parameter: `name` + +The name of the SSH public Key that is being created. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Resource location. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `publicKey` + +SSH public key used to authenticate to a virtual machine through SSH. If this property is not initially provided when the resource is created, the publicKey property will be populated when generateKeyPair is called. If the public key is provided upon resource creation, the provided public key needs to be at least 2048-bit and in ssh-rsa format. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the availability set resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the Public SSH Key. | +| `resourceGroupName` | string | The name of the Resource Group the Public SSH Key was created in. | +| `resourceId` | string | The resource ID of the Public SSH Key. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/compute/ssh-public-key/main.bicep b/avm/1.1.0/res/compute/ssh-public-key/main.bicep new file mode 100644 index 000000000..45bb102ec --- /dev/null +++ b/avm/1.1.0/res/compute/ssh-public-key/main.bicep @@ -0,0 +1,156 @@ +metadata name = 'Public SSH Keys' +metadata description = '''This module deploys a Public SSH Key. + +> Note: The resource does not auto-generate the key for you.''' + +@description('Required. The name of the SSH public Key that is being created.') +param name string + +@description('Optional. Resource location.') +param location string = resourceGroup().location + +@description('Optional. SSH public key used to authenticate to a virtual machine through SSH. If this property is not initially provided when the resource is created, the publicKey property will be populated when generateKeyPair is called. If the public key is provided upon resource creation, the provided public key needs to be at least 2048-bit and in ssh-rsa format.') +param publicKey string? + +@description('Optional. Tags of the availability set resource.') +param tags object? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + // Add other relevant built-in roles here for your resource as per BCPNFR5 + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.compute-sshpublickey.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource sshPublicKey 'Microsoft.Compute/sshPublicKeys@2024-03-01' = { + name: name + location: location + tags: tags + properties: { + publicKey: publicKey + } +} + +resource sshPublicKeyLock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: sshPublicKey +} + +resource sshPublicKey_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(sshPublicKey.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: sshPublicKey + } +] + +@description('The name of the Resource Group the Public SSH Key was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the Public SSH Key.') +output resourceId string = sshPublicKey.id + +@description('The name of the Public SSH Key.') +output name string = sshPublicKey.name + +@description('The location the resource was deployed into.') +output location string = sshPublicKey.location + +// ================ // +// Definitions // +// ================ // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? diff --git a/avm/1.1.0/res/compute/ssh-public-key/main.json b/avm/1.1.0/res/compute/ssh-public-key/main.json new file mode 100644 index 000000000..72bfc7753 --- /dev/null +++ b/avm/1.1.0/res/compute/ssh-public-key/main.json @@ -0,0 +1,276 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "616504106529068315" + }, + "name": "Public SSH Keys", + "description": "This module deploys a Public SSH Key.\n\n> Note: The resource does not auto-generate the key for you." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SSH public Key that is being created." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Resource location." + } + }, + "publicKey": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. SSH public key used to authenticate to a virtual machine through SSH. If this property is not initially provided when the resource is created, the publicKey property will be populated when generateKeyPair is called. If the public key is provided upon resource creation, the provided public key needs to be at least 2048-bit and in ssh-rsa format." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the availability set resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.compute-sshpublickey.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "sshPublicKey": { + "type": "Microsoft.Compute/sshPublicKeys", + "apiVersion": "2024-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publicKey": "[parameters('publicKey')]" + } + }, + "sshPublicKeyLock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Compute/sshPublicKeys/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "sshPublicKey" + ] + }, + "sshPublicKey_roleAssignments": { + "copy": { + "name": "sshPublicKey_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/sshPublicKeys/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/sshPublicKeys', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "sshPublicKey" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Public SSH Key was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Public SSH Key." + }, + "value": "[resourceId('Microsoft.Compute/sshPublicKeys', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Public SSH Key." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('sshPublicKey', '2024-03-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..e46bb6c22 --- /dev/null +++ b/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,43 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.sshPublicKeys-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cspkmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}-${serviceShort}001' + location: resourceLocation + } +} diff --git a/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..79ed631a9 --- /dev/null +++ b/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/max/dependencies.bicep @@ -0,0 +1,64 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Optional. Name of the Deployment Script that creates the SSH Public Key.') +param generateSshPubKeyScriptName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. Name of the temporary SSH Public Key to create for test.') +param sshKeyName string + +@description('Optional. Do not provide a value. Used to force the deployment script to rerun on every redeployment.') +param utcValue string = utcNow() + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +// required for the deployment script to create a new temporary ssh public key object +resource msi_ContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'ManagedIdentityContributor', '#_namePrefix_#') + properties: { + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalId: managedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +resource createPubKeyScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: generateSshPubKeyScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '8.0' + retentionInterval: 'P1D' + arguments: '-ResourceGroupName ${resourceGroup().name} -SSHKeyName ${sshKeyName}' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/New-SSHKey.ps1') + cleanupPreference: 'OnExpiration' + forceUpdateTag: utcValue + } + dependsOn: [ + msi_ContributorRoleAssignment + ] +} + +@description('The public key to be added to the SSH Public Key resource.') +output publicKey string = createPubKeyScript.properties.outputs.publicKey + +@description('The resource ID of the managed Identity') +output managedIdentityId string = managedIdentity.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..6b73bf45d --- /dev/null +++ b/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/max/main.test.bicep @@ -0,0 +1,89 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.sshPublicKeys-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +@maxLength(7) +param serviceShort string = 'cspkmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + generateSshPubKeyScriptName: 'dep-${namePrefix}-ds-${serviceShort}-generateSshPubKey' + sshKeyName: 'dep-${namePrefix}-ssh-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}-sshkey-${serviceShort}001' + publicKey: nestedDependencies.outputs.publicKey + lock: { + kind: 'CanNotDelete' + name: 'lock' + } + roleAssignments: [ + { + name: '74ec0421-c3f4-46f2-acf0-b519fe6fcf1c' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + location: resourceLocation + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + enableTelemetry: true + } +} diff --git a/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..c8a2dfc40 --- /dev/null +++ b/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,64 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Optional. Name of the Deployment Script that creates the SSH Public Key.') +param generateSshPubKeyScriptName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. Name of the temporary SSH Public Key to create for test.') +param sshKeyName string + +@description('Optional. Do not provide a value. Used to force the deployment script to rerun on every redeployment.') +param utcValue string = utcNow() + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +// required for the deployment script to create a new temporary ssh public key object +resource msi_ContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'ManagedIdentityContributor', managedIdentityName) + properties: { + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalId: managedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +resource createPubKeyScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: generateSshPubKeyScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '8.0' + retentionInterval: 'P1D' + arguments: '-ResourceGroupName ${resourceGroup().name} -SSHKeyName ${sshKeyName}' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/New-SSHKey.ps1') + cleanupPreference: 'OnExpiration' + forceUpdateTag: utcValue + } + dependsOn: [ + msi_ContributorRoleAssignment + ] +} + +@description('The public key to be added to the SSH Public Key resource.') +output publicKey string = createPubKeyScript.properties.outputs.publicKey + +@description('The resource ID of the managed Identity') +output managedIdentityId string = managedIdentity.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..868248aa8 --- /dev/null +++ b/avm/1.1.0/res/compute/ssh-public-key/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,88 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.sshPublicKeys-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +@maxLength(7) +param serviceShort string = 'cspkwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + generateSshPubKeyScriptName: 'dep-${namePrefix}-ds-${serviceShort}-generateSshPubKey' + sshKeyName: 'dep-${namePrefix}-ssh-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}-sshkey-${serviceShort}001' + publicKey: nestedDependencies.outputs.publicKey + lock: { + kind: 'CanNotDelete' + name: 'lock' + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + location: resourceLocation + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + enableTelemetry: true + } +} diff --git a/avm/1.1.0/res/compute/ssh-public-key/tests/unit/custom.tests.ps1 b/avm/1.1.0/res/compute/ssh-public-key/tests/unit/custom.tests.ps1 new file mode 100644 index 000000000..36b53af9c --- /dev/null +++ b/avm/1.1.0/res/compute/ssh-public-key/tests/unit/custom.tests.ps1 @@ -0,0 +1,7 @@ +########################### +## Additional unit tests ## +########################### +## +## You can add any custom static validation tests you want here, or add them spread accross multiple test files in the unit folder. +## +########################### diff --git a/avm/1.1.0/res/compute/ssh-public-key/version.json b/avm/1.1.0/res/compute/ssh-public-key/version.json new file mode 100644 index 000000000..3f863a2be --- /dev/null +++ b/avm/1.1.0/res/compute/ssh-public-key/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.4", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/README.md b/avm/1.1.0/res/compute/virtual-machine-scale-set/README.md new file mode 100644 index 000000000..cb943b363 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/README.md @@ -0,0 +1,3452 @@ +# Virtual Machine Scale Sets `[Microsoft.Compute/virtualMachineScaleSets]` + +This module deploys a Virtual Machine Scale Set. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Compute/virtualMachineScaleSets` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-07-01/virtualMachineScaleSets) | +| `Microsoft.Compute/virtualMachineScaleSets/extensions` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-09-01/virtualMachineScaleSets/extensions) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/compute/virtual-machine-scale-set:`. + +- [Using only defaults for Linux](#example-1-using-only-defaults-for-linux) +- [Using large parameter set for Linux](#example-2-using-large-parameter-set-for-linux) +- [Using disk encryption set for the VM.](#example-3-using-disk-encryption-set-for-the-vm) +- [Using only defaults for Windows](#example-4-using-only-defaults-for-windows) +- [Using large parameter set for Windows](#example-5-using-large-parameter-set-for-windows) +- [WAF-aligned](#example-6-waf-aligned) + +### Example 1: _Using only defaults for Linux_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-set:' = { + name: 'virtualMachineScaleSetDeployment' + params: { + // Required parameters + adminPassword: '' + adminUsername: 'scaleSetAdmin' + imageReference: { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' + } + name: 'cvmsslinmin001' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslinmin' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } + ] + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Linux' + skuName: 'Standard_B12ms' + // Non-required parameters + disablePasswordAuthentication: true + location: '' + publicKeys: [ + { + keyData: '' + path: '/home/scaleSetAdmin/.ssh/authorized_keys' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminPassword": { + "value": "" + }, + "adminUsername": { + "value": "scaleSetAdmin" + }, + "imageReference": { + "value": { + "offer": "0001-com-ubuntu-server-jammy", + "publisher": "Canonical", + "sku": "22_04-lts-gen2", + "version": "latest" + } + }, + "name": { + "value": "cvmsslinmin001" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsslinmin" + }, + "subnet": { + "id": "" + } + } + } + ], + "nicSuffix": "-nic01" + } + ] + }, + "osDisk": { + "value": { + "createOption": "fromImage", + "diskSizeGB": "128", + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Linux" + }, + "skuName": { + "value": "Standard_B12ms" + }, + // Non-required parameters + "disablePasswordAuthentication": { + "value": true + }, + "location": { + "value": "" + }, + "publicKeys": { + "value": [ + { + "keyData": "", + "path": "/home/scaleSetAdmin/.ssh/authorized_keys" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +param adminPassword = '' +param adminUsername = 'scaleSetAdmin' +param imageReference = { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' +} +param name = 'cvmsslinmin001' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslinmin' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } +] +param osDisk = { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Linux' +param skuName = 'Standard_B12ms' +// Non-required parameters +param disablePasswordAuthentication = true +param location = '' +param publicKeys = [ + { + keyData: '' + path: '/home/scaleSetAdmin/.ssh/authorized_keys' + } +] +``` + +
+

+ +### Example 2: _Using large parameter set for Linux_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-set:' = { + name: 'virtualMachineScaleSetDeployment' + params: { + // Required parameters + adminPassword: '' + adminUsername: 'scaleSetAdmin' + imageReference: { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' + } + name: 'cvmsslinmax001' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslinmax' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } + ] + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Linux' + skuName: 'Standard_B12ms' + // Non-required parameters + availabilityZones: [ + '2' + ] + bootDiagnosticEnabled: true + bootDiagnosticStorageAccountName: '' + dataDisks: [ + { + caching: 'ReadOnly' + createOption: 'Empty' + diskSizeGB: '256' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + { + caching: 'ReadOnly' + createOption: 'Empty' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + disablePasswordAuthentication: true + encryptionAtHost: false + extensionAzureDiskEncryptionConfig: { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + VolumeType: 'All' + } + } + extensionCustomScriptConfig: { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + protectedSettings: { + commandToExecute: 'sudo apt-get update' + } + } + extensionDependencyAgentConfig: { + enabled: true + } + extensionMonitoringAgentConfig: { + autoUpgradeMinorVersion: true + enabled: true + } + extensionNetworkWatcherAgentConfig: { + enabled: true + } + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] + } + publicKeys: [ + { + keyData: '' + path: '/home/scaleSetAdmin/.ssh/authorized_keys' + } + ] + roleAssignments: [ + { + name: '8abf72f9-e918-4adc-b20b-c783b8799065' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + scaleSetFaultDomain: 1 + skuCapacity: 1 + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + upgradePolicyMode: 'Manual' + vmNamePrefix: 'vmsslinvm' + vmPriority: 'Regular' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminPassword": { + "value": "" + }, + "adminUsername": { + "value": "scaleSetAdmin" + }, + "imageReference": { + "value": { + "offer": "0001-com-ubuntu-server-jammy", + "publisher": "Canonical", + "sku": "22_04-lts-gen2", + "version": "latest" + } + }, + "name": { + "value": "cvmsslinmax001" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsslinmax" + }, + "subnet": { + "id": "" + } + } + } + ], + "nicSuffix": "-nic01" + } + ] + }, + "osDisk": { + "value": { + "createOption": "fromImage", + "diskSizeGB": "128", + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Linux" + }, + "skuName": { + "value": "Standard_B12ms" + }, + // Non-required parameters + "availabilityZones": { + "value": [ + "2" + ] + }, + "bootDiagnosticEnabled": { + "value": true + }, + "bootDiagnosticStorageAccountName": { + "value": "" + }, + "dataDisks": { + "value": [ + { + "caching": "ReadOnly", + "createOption": "Empty", + "diskSizeGB": "256", + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + }, + { + "caching": "ReadOnly", + "createOption": "Empty", + "diskSizeGB": "128", + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "disablePasswordAuthentication": { + "value": true + }, + "encryptionAtHost": { + "value": false + }, + "extensionAzureDiskEncryptionConfig": { + "value": { + "enabled": true, + "settings": { + "EncryptionOperation": "EnableEncryption", + "KekVaultResourceId": "", + "KeyEncryptionAlgorithm": "RSA-OAEP", + "KeyEncryptionKeyURL": "", + "KeyVaultResourceId": "", + "KeyVaultURL": "", + "ResizeOSDisk": "false", + "VolumeType": "All" + } + } + }, + "extensionCustomScriptConfig": { + "value": { + "enabled": true, + "fileData": [ + { + "storageAccountId": "", + "uri": "" + } + ], + "protectedSettings": { + "commandToExecute": "sudo apt-get update" + } + } + }, + "extensionDependencyAgentConfig": { + "value": { + "enabled": true + } + }, + "extensionMonitoringAgentConfig": { + "value": { + "autoUpgradeMinorVersion": true, + "enabled": true + } + }, + "extensionNetworkWatcherAgentConfig": { + "value": { + "enabled": true + } + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "systemAssigned": false, + "userAssignedResourceIds": [ + "" + ] + } + }, + "publicKeys": { + "value": [ + { + "keyData": "", + "path": "/home/scaleSetAdmin/.ssh/authorized_keys" + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "8abf72f9-e918-4adc-b20b-c783b8799065", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "scaleSetFaultDomain": { + "value": 1 + }, + "skuCapacity": { + "value": 1 + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "upgradePolicyMode": { + "value": "Manual" + }, + "vmNamePrefix": { + "value": "vmsslinvm" + }, + "vmPriority": { + "value": "Regular" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +param adminPassword = '' +param adminUsername = 'scaleSetAdmin' +param imageReference = { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' +} +param name = 'cvmsslinmax001' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslinmax' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } +] +param osDisk = { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Linux' +param skuName = 'Standard_B12ms' +// Non-required parameters +param availabilityZones = [ + '2' +] +param bootDiagnosticEnabled = true +param bootDiagnosticStorageAccountName = '' +param dataDisks = [ + { + caching: 'ReadOnly' + createOption: 'Empty' + diskSizeGB: '256' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + { + caching: 'ReadOnly' + createOption: 'Empty' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disablePasswordAuthentication = true +param encryptionAtHost = false +param extensionAzureDiskEncryptionConfig = { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + VolumeType: 'All' + } +} +param extensionCustomScriptConfig = { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + protectedSettings: { + commandToExecute: 'sudo apt-get update' + } +} +param extensionDependencyAgentConfig = { + enabled: true +} +param extensionMonitoringAgentConfig = { + autoUpgradeMinorVersion: true + enabled: true +} +param extensionNetworkWatcherAgentConfig = { + enabled: true +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param publicKeys = [ + { + keyData: '' + path: '/home/scaleSetAdmin/.ssh/authorized_keys' + } +] +param roleAssignments = [ + { + name: '8abf72f9-e918-4adc-b20b-c783b8799065' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scaleSetFaultDomain = 1 +param skuCapacity = 1 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param upgradePolicyMode = 'Manual' +param vmNamePrefix = 'vmsslinvm' +param vmPriority = 'Regular' +``` + +
+

+ +### Example 3: _Using disk encryption set for the VM._ + +This instance deploys the module with disk enryption set. + + +

+ +via Bicep module + +```bicep +module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-set:' = { + name: 'virtualMachineScaleSetDeployment' + params: { + // Required parameters + adminPassword: '' + adminUsername: 'scaleSetAdmin' + imageReference: { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' + } + name: 'cvmsslcmk001' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslcmk' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } + ] + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + diskEncryptionSet: { + id: '' + } + storageAccountType: 'Premium_LRS' + } + } + osType: 'Linux' + skuName: 'Standard_B12ms' + // Non-required parameters + dataDisks: [ + { + caching: 'ReadOnly' + createOption: 'Empty' + diskSizeGB: '128' + managedDisk: { + diskEncryptionSet: { + id: '' + } + storageAccountType: 'Premium_LRS' + } + } + ] + disablePasswordAuthentication: true + extensionMonitoringAgentConfig: { + autoUpgradeMinorVersion: true + enabled: true + } + location: '' + publicKeys: [ + { + keyData: '' + path: '/home/scaleSetAdmin/.ssh/authorized_keys' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminPassword": { + "value": "" + }, + "adminUsername": { + "value": "scaleSetAdmin" + }, + "imageReference": { + "value": { + "offer": "0001-com-ubuntu-server-jammy", + "publisher": "Canonical", + "sku": "22_04-lts-gen2", + "version": "latest" + } + }, + "name": { + "value": "cvmsslcmk001" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsslcmk" + }, + "subnet": { + "id": "" + } + } + } + ], + "nicSuffix": "-nic01" + } + ] + }, + "osDisk": { + "value": { + "createOption": "fromImage", + "diskSizeGB": "128", + "managedDisk": { + "diskEncryptionSet": { + "id": "" + }, + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Linux" + }, + "skuName": { + "value": "Standard_B12ms" + }, + // Non-required parameters + "dataDisks": { + "value": [ + { + "caching": "ReadOnly", + "createOption": "Empty", + "diskSizeGB": "128", + "managedDisk": { + "diskEncryptionSet": { + "id": "" + }, + "storageAccountType": "Premium_LRS" + } + } + ] + }, + "disablePasswordAuthentication": { + "value": true + }, + "extensionMonitoringAgentConfig": { + "value": { + "autoUpgradeMinorVersion": true, + "enabled": true + } + }, + "location": { + "value": "" + }, + "publicKeys": { + "value": [ + { + "keyData": "", + "path": "/home/scaleSetAdmin/.ssh/authorized_keys" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +param adminPassword = '' +param adminUsername = 'scaleSetAdmin' +param imageReference = { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' +} +param name = 'cvmsslcmk001' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslcmk' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } +] +param osDisk = { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + diskEncryptionSet: { + id: '' + } + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Linux' +param skuName = 'Standard_B12ms' +// Non-required parameters +param dataDisks = [ + { + caching: 'ReadOnly' + createOption: 'Empty' + diskSizeGB: '128' + managedDisk: { + diskEncryptionSet: { + id: '' + } + storageAccountType: 'Premium_LRS' + } + } +] +param disablePasswordAuthentication = true +param extensionMonitoringAgentConfig = { + autoUpgradeMinorVersion: true + enabled: true +} +param location = '' +param publicKeys = [ + { + keyData: '' + path: '/home/scaleSetAdmin/.ssh/authorized_keys' + } +] +``` + +
+

+ +### Example 4: _Using only defaults for Windows_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-set:' = { + name: 'virtualMachineScaleSetDeployment' + params: { + // Required parameters + adminPassword: '' + adminUsername: 'localAdminUser' + imageReference: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + name: 'cvmsswinmin001' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinmin' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } + ] + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + skuName: 'Standard_B12ms' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminPassword": { + "value": "" + }, + "adminUsername": { + "value": "localAdminUser" + }, + "imageReference": { + "value": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition", + "version": "latest" + } + }, + "name": { + "value": "cvmsswinmin001" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsswinmin" + }, + "subnet": { + "id": "" + } + } + } + ], + "nicSuffix": "-nic01" + } + ] + }, + "osDisk": { + "value": { + "createOption": "fromImage", + "diskSizeGB": "128", + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Windows" + }, + "skuName": { + "value": "Standard_B12ms" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +param adminPassword = '' +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmsswinmin001' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinmin' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } +] +param osDisk = { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param skuName = 'Standard_B12ms' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 5: _Using large parameter set for Windows_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-set:' = { + name: 'virtualMachineScaleSetDeployment' + params: { + // Required parameters + adminPassword: '' + adminUsername: 'localAdminUser' + imageReference: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + name: 'cvmsswinmax001' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinmax' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } + ] + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + skuName: 'Standard_B12ms' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + encryptionAtHost: false + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: true + Exclusions: { + Extensions: '.log;.ldf' + Paths: 'D:\\IISlogs;D:\\DatabaseLogs' + Processes: 'mssence.svc' + } + RealtimeProtectionEnabled: true + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + } + extensionAzureDiskEncryptionConfig: { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + VolumeType: 'All' + } + } + extensionCustomScriptConfig: { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + protectedSettings: { + commandToExecute: '' + } + } + extensionDependencyAgentConfig: { + enabled: true + } + extensionDSCConfig: { + enabled: true + } + extensionHealthConfig: { + enabled: true + settings: { + port: 80 + protocol: 'http' + requestPath: '/' + } + } + extensionMonitoringAgentConfig: { + autoUpgradeMinorVersion: true + enabled: true + } + extensionNetworkWatcherAgentConfig: { + enabled: true + } + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] + } + roleAssignments: [ + { + name: '1910de8c-4dab-4189-96bb-2feb68350fb8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + skuCapacity: 1 + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + upgradePolicyMode: 'Manual' + vmNamePrefix: 'vmsswinvm' + vmPriority: 'Regular' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminPassword": { + "value": "" + }, + "adminUsername": { + "value": "localAdminUser" + }, + "imageReference": { + "value": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition", + "version": "latest" + } + }, + "name": { + "value": "cvmsswinmax001" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsswinmax" + }, + "subnet": { + "id": "" + } + } + } + ], + "nicSuffix": "-nic01" + } + ] + }, + "osDisk": { + "value": { + "createOption": "fromImage", + "diskSizeGB": "128", + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Windows" + }, + "skuName": { + "value": "Standard_B12ms" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "encryptionAtHost": { + "value": false + }, + "extensionAntiMalwareConfig": { + "value": { + "enabled": true, + "settings": { + "AntimalwareEnabled": true, + "Exclusions": { + "Extensions": ".log;.ldf", + "Paths": "D:\\IISlogs;D:\\DatabaseLogs", + "Processes": "mssence.svc" + }, + "RealtimeProtectionEnabled": true, + "ScheduledScanSettings": { + "day": "7", + "isEnabled": "true", + "scanType": "Quick", + "time": "120" + } + } + } + }, + "extensionAzureDiskEncryptionConfig": { + "value": { + "enabled": true, + "settings": { + "EncryptionOperation": "EnableEncryption", + "KekVaultResourceId": "", + "KeyEncryptionAlgorithm": "RSA-OAEP", + "KeyEncryptionKeyURL": "", + "KeyVaultResourceId": "", + "KeyVaultURL": "", + "ResizeOSDisk": "false", + "VolumeType": "All" + } + } + }, + "extensionCustomScriptConfig": { + "value": { + "enabled": true, + "fileData": [ + { + "storageAccountId": "", + "uri": "" + } + ], + "protectedSettings": { + "commandToExecute": "" + } + } + }, + "extensionDependencyAgentConfig": { + "value": { + "enabled": true + } + }, + "extensionDSCConfig": { + "value": { + "enabled": true + } + }, + "extensionHealthConfig": { + "value": { + "enabled": true, + "settings": { + "port": 80, + "protocol": "http", + "requestPath": "/" + } + } + }, + "extensionMonitoringAgentConfig": { + "value": { + "autoUpgradeMinorVersion": true, + "enabled": true + } + }, + "extensionNetworkWatcherAgentConfig": { + "value": { + "enabled": true + } + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "systemAssigned": false, + "userAssignedResourceIds": [ + "" + ] + } + }, + "roleAssignments": { + "value": [ + { + "name": "1910de8c-4dab-4189-96bb-2feb68350fb8", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "skuCapacity": { + "value": 1 + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "upgradePolicyMode": { + "value": "Manual" + }, + "vmNamePrefix": { + "value": "vmsswinvm" + }, + "vmPriority": { + "value": "Regular" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +param adminPassword = '' +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmsswinmax001' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinmax' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } +] +param osDisk = { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param skuName = 'Standard_B12ms' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param encryptionAtHost = false +param extensionAntiMalwareConfig = { + enabled: true + settings: { + AntimalwareEnabled: true + Exclusions: { + Extensions: '.log;.ldf' + Paths: 'D:\\IISlogs;D:\\DatabaseLogs' + Processes: 'mssence.svc' + } + RealtimeProtectionEnabled: true + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } +} +param extensionAzureDiskEncryptionConfig = { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + VolumeType: 'All' + } +} +param extensionCustomScriptConfig = { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + protectedSettings: { + commandToExecute: '' + } +} +param extensionDependencyAgentConfig = { + enabled: true +} +param extensionDSCConfig = { + enabled: true +} +param extensionHealthConfig = { + enabled: true + settings: { + port: 80 + protocol: 'http' + requestPath: '/' + } +} +param extensionMonitoringAgentConfig = { + autoUpgradeMinorVersion: true + enabled: true +} +param extensionNetworkWatcherAgentConfig = { + enabled: true +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: '1910de8c-4dab-4189-96bb-2feb68350fb8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuCapacity = 1 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param upgradePolicyMode = 'Manual' +param vmNamePrefix = 'vmsswinvm' +param vmPriority = 'Regular' +``` + +
+

+ +### Example 6: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework for Windows. + + +

+ +via Bicep module + +```bicep +module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-set:' = { + name: 'virtualMachineScaleSetDeployment' + params: { + // Required parameters + adminPassword: '' + adminUsername: 'localAdminUser' + imageReference: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + name: 'cvmsswinwaf001' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinwaf' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } + ] + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + skuName: 'Standard_B12ms' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + encryptionAtHost: false + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: true + Exclusions: { + Extensions: '.log;.ldf' + Paths: 'D:\\IISlogs;D:\\DatabaseLogs' + Processes: 'mssence.svc' + } + RealtimeProtectionEnabled: true + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + } + extensionAzureDiskEncryptionConfig: { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + VolumeType: 'All' + } + } + extensionCustomScriptConfig: { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + protectedSettings: { + commandToExecute: '' + } + } + extensionDependencyAgentConfig: { + enabled: true + } + extensionDSCConfig: { + enabled: true + } + extensionMonitoringAgentConfig: { + autoUpgradeMinorVersion: true + enabled: true + } + extensionNetworkWatcherAgentConfig: { + enabled: true + } + location: '' + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] + } + skuCapacity: 1 + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + upgradePolicyMode: 'Manual' + vmNamePrefix: 'vmsswinvm' + vmPriority: 'Regular' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminPassword": { + "value": "" + }, + "adminUsername": { + "value": "localAdminUser" + }, + "imageReference": { + "value": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition", + "version": "latest" + } + }, + "name": { + "value": "cvmsswinwaf001" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pip-cvmsswinwaf" + }, + "subnet": { + "id": "" + } + } + } + ], + "nicSuffix": "-nic01" + } + ] + }, + "osDisk": { + "value": { + "createOption": "fromImage", + "diskSizeGB": "128", + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Windows" + }, + "skuName": { + "value": "Standard_B12ms" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "encryptionAtHost": { + "value": false + }, + "extensionAntiMalwareConfig": { + "value": { + "enabled": true, + "settings": { + "AntimalwareEnabled": true, + "Exclusions": { + "Extensions": ".log;.ldf", + "Paths": "D:\\IISlogs;D:\\DatabaseLogs", + "Processes": "mssence.svc" + }, + "RealtimeProtectionEnabled": true, + "ScheduledScanSettings": { + "day": "7", + "isEnabled": "true", + "scanType": "Quick", + "time": "120" + } + } + } + }, + "extensionAzureDiskEncryptionConfig": { + "value": { + "enabled": true, + "settings": { + "EncryptionOperation": "EnableEncryption", + "KekVaultResourceId": "", + "KeyEncryptionAlgorithm": "RSA-OAEP", + "KeyEncryptionKeyURL": "", + "KeyVaultResourceId": "", + "KeyVaultURL": "", + "ResizeOSDisk": "false", + "VolumeType": "All" + } + } + }, + "extensionCustomScriptConfig": { + "value": { + "enabled": true, + "fileData": [ + { + "storageAccountId": "", + "uri": "" + } + ], + "protectedSettings": { + "commandToExecute": "" + } + } + }, + "extensionDependencyAgentConfig": { + "value": { + "enabled": true + } + }, + "extensionDSCConfig": { + "value": { + "enabled": true + } + }, + "extensionMonitoringAgentConfig": { + "value": { + "autoUpgradeMinorVersion": true, + "enabled": true + } + }, + "extensionNetworkWatcherAgentConfig": { + "value": { + "enabled": true + } + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "systemAssigned": false, + "userAssignedResourceIds": [ + "" + ] + } + }, + "skuCapacity": { + "value": 1 + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "upgradePolicyMode": { + "value": "Manual" + }, + "vmNamePrefix": { + "value": "vmsswinvm" + }, + "vmPriority": { + "value": "Regular" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +param adminPassword = '' +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmsswinwaf001' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinwaf' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } +] +param osDisk = { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param skuName = 'Standard_B12ms' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param encryptionAtHost = false +param extensionAntiMalwareConfig = { + enabled: true + settings: { + AntimalwareEnabled: true + Exclusions: { + Extensions: '.log;.ldf' + Paths: 'D:\\IISlogs;D:\\DatabaseLogs' + Processes: 'mssence.svc' + } + RealtimeProtectionEnabled: true + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } +} +param extensionAzureDiskEncryptionConfig = { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + VolumeType: 'All' + } +} +param extensionCustomScriptConfig = { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + protectedSettings: { + commandToExecute: '' + } +} +param extensionDependencyAgentConfig = { + enabled: true +} +param extensionDSCConfig = { + enabled: true +} +param extensionMonitoringAgentConfig = { + autoUpgradeMinorVersion: true + enabled: true +} +param extensionNetworkWatcherAgentConfig = { + enabled: true +} +param location = '' +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param skuCapacity = 1 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param upgradePolicyMode = 'Manual' +param vmNamePrefix = 'vmsswinvm' +param vmPriority = 'Regular' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`adminPassword`](#parameter-adminpassword) | securestring | When specifying a Windows Virtual Machine, this value should be passed. | +| [`adminUsername`](#parameter-adminusername) | securestring | Administrator username. | +| [`imageReference`](#parameter-imagereference) | object | OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. | +| [`name`](#parameter-name) | string | Name of the VMSS. | +| [`nicConfigurations`](#parameter-nicconfigurations) | array | Configures NICs and PIPs. | +| [`osDisk`](#parameter-osdisk) | object | Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VM Scale sets. | +| [`osType`](#parameter-ostype) | string | The chosen OS type. | +| [`skuName`](#parameter-skuname) | string | The SKU size of the VMs. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`additionalUnattendContent`](#parameter-additionalunattendcontent) | array | Specifies additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. - AdditionalUnattendContent object. | +| [`automaticRepairsPolicyEnabled`](#parameter-automaticrepairspolicyenabled) | bool | Specifies whether automatic repairs should be enabled on the virtual machine scale set. | +| [`availabilityZones`](#parameter-availabilityzones) | array | The virtual machine scale set zones. NOTE: Availability zones can only be set when you create the scale set. | +| [`bootDiagnosticEnabled`](#parameter-bootdiagnosticenabled) | bool | Enable boot diagnostics to use default managed or secure storage. Defaults set to false. | +| [`bootDiagnosticStorageAccountName`](#parameter-bootdiagnosticstorageaccountname) | string | The name of the boot diagnostic storage account. Provide this if you want to use your own storage account for security reasons instead of the recommended Microsoft Managed Storage Account. | +| [`bootDiagnosticStorageAccountUri`](#parameter-bootdiagnosticstorageaccounturi) | string | Storage account boot diagnostic base URI. | +| [`bypassPlatformSafetyChecksOnUserSchedule`](#parameter-bypassplatformsafetychecksonuserschedule) | bool | Enables customer to schedule patching without accidental upgrades. | +| [`customData`](#parameter-customdata) | string | Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format. | +| [`dataDisks`](#parameter-datadisks) | array | Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VM Scale sets. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`disableAutomaticRollback`](#parameter-disableautomaticrollback) | bool | Whether OS image rollback feature should be disabled. | +| [`disablePasswordAuthentication`](#parameter-disablepasswordauthentication) | bool | Specifies whether password authentication should be disabled. | +| [`doNotRunExtensionsOnOverprovisionedVMs`](#parameter-donotrunextensionsonoverprovisionedvms) | bool | When Overprovision is enabled, extensions are launched only on the requested number of VMs which are finally kept. This property will hence ensure that the extensions do not run on the extra overprovisioned VMs. | +| [`enableAutomaticOSUpgrade`](#parameter-enableautomaticosupgrade) | bool | Indicates whether OS upgrades should automatically be applied to scale set instances in a rolling fashion when a newer version of the OS image becomes available. Default value is false. If this is set to true for Windows based scale sets, enableAutomaticUpdates is automatically set to false and cannot be set to true. | +| [`enableAutomaticUpdates`](#parameter-enableautomaticupdates) | bool | Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning. | +| [`enableCrossZoneUpgrade`](#parameter-enablecrosszoneupgrade) | bool | Allow VMSS to ignore AZ boundaries when constructing upgrade batches. Take into consideration the Update Domain and maxBatchInstancePercent to determine the batch size. | +| [`enableEvictionPolicy`](#parameter-enableevictionpolicy) | bool | Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`encryptionAtHost`](#parameter-encryptionathost) | bool | This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your virtual machine scale sets. | +| [`extensionAntiMalwareConfig`](#parameter-extensionantimalwareconfig) | object | The configuration for the [Anti Malware] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionAzureDiskEncryptionConfig`](#parameter-extensionazurediskencryptionconfig) | object | The configuration for the [Azure Disk Encryption] extension. Must at least contain the ["enabled": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys. | +| [`extensionCustomScriptConfig`](#parameter-extensioncustomscriptconfig) | object | The configuration for the [Custom Script] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionDependencyAgentConfig`](#parameter-extensiondependencyagentconfig) | object | The configuration for the [Dependency Agent] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionDomainJoinConfig`](#parameter-extensiondomainjoinconfig) | secureObject | The configuration for the [Domain Join] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionDomainJoinPassword`](#parameter-extensiondomainjoinpassword) | securestring | Required if name is specified. Password of the user specified in user parameter. | +| [`extensionDSCConfig`](#parameter-extensiondscconfig) | object | The configuration for the [Desired State Configuration] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionHealthConfig`](#parameter-extensionhealthconfig) | object | Turned on by default. The configuration for the [Application Health Monitoring] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionMonitoringAgentConfig`](#parameter-extensionmonitoringagentconfig) | object | The configuration for the [Monitoring Agent] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionNetworkWatcherAgentConfig`](#parameter-extensionnetworkwatcheragentconfig) | object | The configuration for the [Network Watcher Agent] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`gracePeriod`](#parameter-graceperiod) | string | The amount of time for which automatic repairs are suspended due to a state change on VM. The grace time starts after the state change has completed. This helps avoid premature or accidental repairs. The time duration should be specified in ISO 8601 format. The minimum allowed grace period is 30 minutes (PT30M). The maximum allowed grace period is 90 minutes (PT90M). | +| [`licenseType`](#parameter-licensetype) | string | Specifies that the image or disk that is being used was licensed on-premises. This element is only used for images that contain the Windows Server operating system. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`maxBatchInstancePercent`](#parameter-maxbatchinstancepercent) | int | The maximum percent of total virtual machine instances that will be upgraded simultaneously by the rolling upgrade in one batch. As this is a maximum, unhealthy instances in previous or future batches can cause the percentage of instances in a batch to decrease to ensure higher reliability. | +| [`maxPriceForLowPriorityVm`](#parameter-maxpriceforlowpriorityvm) | int | Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars. | +| [`maxSurge`](#parameter-maxsurge) | bool | Create new virtual machines to upgrade the scale set, rather than updating the existing virtual machines. Existing virtual machines will be deleted once the new virtual machines are created for each batch. | +| [`maxUnhealthyInstancePercent`](#parameter-maxunhealthyinstancepercent) | int | The maximum percentage of the total virtual machine instances in the scale set that can be simultaneously unhealthy, either as a result of being upgraded, or by being found in an unhealthy state by the virtual machine health checks before the rolling upgrade aborts. This constraint will be checked prior to starting any batch. | +| [`maxUnhealthyUpgradedInstancePercent`](#parameter-maxunhealthyupgradedinstancepercent) | int | The maximum percentage of the total virtual machine instances in the scale set that can be simultaneously unhealthy, either as a result of being upgraded, or by being found in an unhealthy state by the virtual machine health checks before the rolling upgrade aborts. This constraint will be checked prior to starting any batch. | +| [`monitoringWorkspaceResourceId`](#parameter-monitoringworkspaceresourceid) | string | Resource ID of the monitoring log analytics workspace. | +| [`orchestrationMode`](#parameter-orchestrationmode) | string | Specifies the orchestration mode for the virtual machine scale set. | +| [`overprovision`](#parameter-overprovision) | bool | Specifies whether the Virtual Machine Scale Set should be overprovisioned. | +| [`patchAssessmentMode`](#parameter-patchassessmentmode) | string | VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours. | +| [`patchMode`](#parameter-patchmode) | string | VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'. | +| [`pauseTimeBetweenBatches`](#parameter-pausetimebetweenbatches) | string | The wait time between completing the update for all virtual machines in one batch and starting the next batch. The time duration should be specified in ISO 8601 format. | +| [`plan`](#parameter-plan) | object | Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use. | +| [`prioritizeUnhealthyInstances`](#parameter-prioritizeunhealthyinstances) | bool | Upgrade all unhealthy instances in a scale set before any healthy instances. | +| [`provisionVMAgent`](#parameter-provisionvmagent) | bool | Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later. | +| [`proximityPlacementGroupResourceId`](#parameter-proximityplacementgroupresourceid) | string | Resource ID of a proximity placement group. | +| [`publicKeys`](#parameter-publickeys) | array | The list of SSH public keys used to authenticate with linux based VMs. | +| [`rebootSetting`](#parameter-rebootsetting) | string | Specifies the reboot setting for all AutomaticByPlatform patch installation operations. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`rollbackFailedInstancesOnPolicyBreach`](#parameter-rollbackfailedinstancesonpolicybreach) | bool | Rollback failed instances to previous model if the Rolling Upgrade policy is violated. | +| [`sasTokenValidityLength`](#parameter-sastokenvaliditylength) | string | SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours. | +| [`scaleInPolicy`](#parameter-scaleinpolicy) | object | Specifies the scale-in policy that decides which virtual machines are chosen for removal when a Virtual Machine Scale Set is scaled-in. | +| [`scaleSetFaultDomain`](#parameter-scalesetfaultdomain) | int | Fault Domain count for each placement group. | +| [`scheduledEventsProfile`](#parameter-scheduledeventsprofile) | object | Specifies Scheduled Event related configurations. | +| [`secrets`](#parameter-secrets) | array | Specifies set of certificates that should be installed onto the virtual machines in the scale set. | +| [`secureBootEnabled`](#parameter-securebootenabled) | bool | Specifies whether secure boot should be enabled on the virtual machine scale set. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings. | +| [`securityType`](#parameter-securitytype) | string | Specifies the SecurityType of the virtual machine scale set. It is set as TrustedLaunch to enable UefiSettings. | +| [`singlePlacementGroup`](#parameter-singleplacementgroup) | bool | When true this limits the scale set to a single placement group, of max size 100 virtual machines. NOTE: If singlePlacementGroup is true, it may be modified to false. However, if singlePlacementGroup is false, it may not be modified to true. | +| [`skuCapacity`](#parameter-skucapacity) | int | The initial instance count of scale set VMs. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`timeZone`](#parameter-timezone) | string | Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`. | +| [`ultraSSDEnabled`](#parameter-ultrassdenabled) | bool | The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled. | +| [`upgradePolicyMode`](#parameter-upgradepolicymode) | string | Specifies the mode of an upgrade to virtual machines in the scale set.' Manual - You control the application of updates to virtual machines in the scale set. You do this by using the manualUpgrade action. ; Automatic - All virtual machines in the scale set are automatically updated at the same time. - Automatic, Manual, Rolling. | +| [`vmNamePrefix`](#parameter-vmnameprefix) | string | Specifies the computer name prefix for all of the virtual machines in the scale set. | +| [`vmPriority`](#parameter-vmpriority) | string | Specifies the priority for the virtual machine. | +| [`vTpmEnabled`](#parameter-vtpmenabled) | bool | Specifies whether vTPM should be enabled on the virtual machine scale set. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings. | +| [`winRM`](#parameter-winrm) | object | Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object. | +| [`zoneBalance`](#parameter-zonebalance) | bool | Whether to force strictly even Virtual Machine distribution cross x-zones in case there is zone outage. | + +**Generated parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`baseTime`](#parameter-basetime) | string | Do not provide a value! This date value is used to generate a registration token. | + +### Parameter: `adminPassword` + +When specifying a Windows Virtual Machine, this value should be passed. + +- Required: Yes +- Type: securestring + +### Parameter: `adminUsername` + +Administrator username. + +- Required: Yes +- Type: securestring + +### Parameter: `imageReference` + +OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. + +- Required: Yes +- Type: object + +### Parameter: `name` + +Name of the VMSS. + +- Required: Yes +- Type: string + +### Parameter: `nicConfigurations` + +Configures NICs and PIPs. + +- Required: Yes +- Type: array + +### Parameter: `osDisk` + +Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VM Scale sets. + +- Required: Yes +- Type: object + +### Parameter: `osType` + +The chosen OS type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `skuName` + +The SKU size of the VMs. + +- Required: Yes +- Type: string + +### Parameter: `additionalUnattendContent` + +Specifies additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. - AdditionalUnattendContent object. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `automaticRepairsPolicyEnabled` + +Specifies whether automatic repairs should be enabled on the virtual machine scale set. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `availabilityZones` + +The virtual machine scale set zones. NOTE: Availability zones can only be set when you create the scale set. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` + +### Parameter: `bootDiagnosticEnabled` + +Enable boot diagnostics to use default managed or secure storage. Defaults set to false. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `bootDiagnosticStorageAccountName` + +The name of the boot diagnostic storage account. Provide this if you want to use your own storage account for security reasons instead of the recommended Microsoft Managed Storage Account. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `bootDiagnosticStorageAccountUri` + +Storage account boot diagnostic base URI. + +- Required: No +- Type: string +- Default: `[format('.blob.{0}/', environment().suffixes.storage)]` + +### Parameter: `bypassPlatformSafetyChecksOnUserSchedule` + +Enables customer to schedule patching without accidental upgrades. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `customData` + +Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `dataDisks` + +Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VM Scale sets. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `disableAutomaticRollback` + +Whether OS image rollback feature should be disabled. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `disablePasswordAuthentication` + +Specifies whether password authentication should be disabled. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `doNotRunExtensionsOnOverprovisionedVMs` + +When Overprovision is enabled, extensions are launched only on the requested number of VMs which are finally kept. This property will hence ensure that the extensions do not run on the extra overprovisioned VMs. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableAutomaticOSUpgrade` + +Indicates whether OS upgrades should automatically be applied to scale set instances in a rolling fashion when a newer version of the OS image becomes available. Default value is false. If this is set to true for Windows based scale sets, enableAutomaticUpdates is automatically set to false and cannot be set to true. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableAutomaticUpdates` + +Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableCrossZoneUpgrade` + +Allow VMSS to ignore AZ boundaries when constructing upgrade batches. Take into consideration the Update Domain and maxBatchInstancePercent to determine the batch size. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableEvictionPolicy` + +Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `encryptionAtHost` + +This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your virtual machine scale sets. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `extensionAntiMalwareConfig` + +The configuration for the [Anti Malware] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `extensionAzureDiskEncryptionConfig` + +The configuration for the [Azure Disk Encryption] extension. Must at least contain the ["enabled": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `extensionCustomScriptConfig` + +The configuration for the [Custom Script] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + fileData: [] + } + ``` + +### Parameter: `extensionDependencyAgentConfig` + +The configuration for the [Dependency Agent] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `extensionDomainJoinConfig` + +The configuration for the [Domain Join] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: secureObject +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `extensionDomainJoinPassword` + +Required if name is specified. Password of the user specified in user parameter. + +- Required: No +- Type: securestring +- Default: `''` + +### Parameter: `extensionDSCConfig` + +The configuration for the [Desired State Configuration] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `extensionHealthConfig` + +Turned on by default. The configuration for the [Application Health Monitoring] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: true + settings: { + port: 80 + protocol: 'http' + requestPath: '/' + } + } + ``` + +### Parameter: `extensionMonitoringAgentConfig` + +The configuration for the [Monitoring Agent] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + autoUpgradeMinorVersion: true + enabled: false + } + ``` + +### Parameter: `extensionNetworkWatcherAgentConfig` + +The configuration for the [Network Watcher Agent] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `gracePeriod` + +The amount of time for which automatic repairs are suspended due to a state change on VM. The grace time starts after the state change has completed. This helps avoid premature or accidental repairs. The time duration should be specified in ISO 8601 format. The minimum allowed grace period is 30 minutes (PT30M). The maximum allowed grace period is 90 minutes (PT90M). + +- Required: No +- Type: string +- Default: `'PT30M'` + +### Parameter: `licenseType` + +Specifies that the image or disk that is being used was licensed on-premises. This element is only used for images that contain the Windows Server operating system. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Windows_Client' + 'Windows_Server' + ] + ``` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: No +- Type: array + +### Parameter: `maxBatchInstancePercent` + +The maximum percent of total virtual machine instances that will be upgraded simultaneously by the rolling upgrade in one batch. As this is a maximum, unhealthy instances in previous or future batches can cause the percentage of instances in a batch to decrease to ensure higher reliability. + +- Required: No +- Type: int +- Default: `20` + +### Parameter: `maxPriceForLowPriorityVm` + +Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars. + +- Required: No +- Type: int + +### Parameter: `maxSurge` + +Create new virtual machines to upgrade the scale set, rather than updating the existing virtual machines. Existing virtual machines will be deleted once the new virtual machines are created for each batch. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `maxUnhealthyInstancePercent` + +The maximum percentage of the total virtual machine instances in the scale set that can be simultaneously unhealthy, either as a result of being upgraded, or by being found in an unhealthy state by the virtual machine health checks before the rolling upgrade aborts. This constraint will be checked prior to starting any batch. + +- Required: No +- Type: int +- Default: `20` + +### Parameter: `maxUnhealthyUpgradedInstancePercent` + +The maximum percentage of the total virtual machine instances in the scale set that can be simultaneously unhealthy, either as a result of being upgraded, or by being found in an unhealthy state by the virtual machine health checks before the rolling upgrade aborts. This constraint will be checked prior to starting any batch. + +- Required: No +- Type: int +- Default: `20` + +### Parameter: `monitoringWorkspaceResourceId` + +Resource ID of the monitoring log analytics workspace. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `orchestrationMode` + +Specifies the orchestration mode for the virtual machine scale set. + +- Required: No +- Type: string +- Default: `'Flexible'` +- Allowed: + ```Bicep + [ + 'Flexible' + 'Uniform' + ] + ``` + +### Parameter: `overprovision` + +Specifies whether the Virtual Machine Scale Set should be overprovisioned. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `patchAssessmentMode` + +VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours. + +- Required: No +- Type: string +- Default: `'ImageDefault'` +- Allowed: + ```Bicep + [ + 'AutomaticByPlatform' + 'ImageDefault' + ] + ``` + +### Parameter: `patchMode` + +VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'. + +- Required: No +- Type: string +- Default: `'AutomaticByPlatform'` +- Allowed: + ```Bicep + [ + '' + 'AutomaticByOS' + 'AutomaticByPlatform' + 'ImageDefault' + 'Manual' + ] + ``` + +### Parameter: `pauseTimeBetweenBatches` + +The wait time between completing the update for all virtual machines in one batch and starting the next batch. The time duration should be specified in ISO 8601 format. + +- Required: No +- Type: string +- Default: `'PT0S'` + +### Parameter: `plan` + +Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `prioritizeUnhealthyInstances` + +Upgrade all unhealthy instances in a scale set before any healthy instances. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `provisionVMAgent` + +Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `proximityPlacementGroupResourceId` + +Resource ID of a proximity placement group. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `publicKeys` + +The list of SSH public keys used to authenticate with linux based VMs. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `rebootSetting` + +Specifies the reboot setting for all AutomaticByPlatform patch installation operations. + +- Required: No +- Type: string +- Default: `'IfRequired'` +- Allowed: + ```Bicep + [ + 'Always' + 'IfRequired' + 'Never' + 'Unknown' + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Operator for Managed Disks'` + - `'Desktop Virtualization Power On Contributor'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'DevTest Labs User'` + - `'Disk Backup Reader'` + - `'Disk Pool Operator'` + - `'Disk Restore Operator'` + - `'Disk Snapshot Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Virtual Machine Administrator Login'` + - `'Virtual Machine Contributor'` + - `'Virtual Machine User Login'` + - `'VM Scanner Operator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `rollbackFailedInstancesOnPolicyBreach` + +Rollback failed instances to previous model if the Rolling Upgrade policy is violated. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `sasTokenValidityLength` + +SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours. + +- Required: No +- Type: string +- Default: `'PT8H'` + +### Parameter: `scaleInPolicy` + +Specifies the scale-in policy that decides which virtual machines are chosen for removal when a Virtual Machine Scale Set is scaled-in. + +- Required: No +- Type: object +- Default: + ```Bicep + { + rules: [ + 'Default' + ] + } + ``` + +### Parameter: `scaleSetFaultDomain` + +Fault Domain count for each placement group. + +- Required: No +- Type: int +- Default: `1` + +### Parameter: `scheduledEventsProfile` + +Specifies Scheduled Event related configurations. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `secrets` + +Specifies set of certificates that should be installed onto the virtual machines in the scale set. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `secureBootEnabled` + +Specifies whether secure boot should be enabled on the virtual machine scale set. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `securityType` + +Specifies the SecurityType of the virtual machine scale set. It is set as TrustedLaunch to enable UefiSettings. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `singlePlacementGroup` + +When true this limits the scale set to a single placement group, of max size 100 virtual machines. NOTE: If singlePlacementGroup is true, it may be modified to false. However, if singlePlacementGroup is false, it may not be modified to true. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `skuCapacity` + +The initial instance count of scale set VMs. + +- Required: No +- Type: int +- Default: `1` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `timeZone` + +Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `ultraSSDEnabled` + +The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `upgradePolicyMode` + +Specifies the mode of an upgrade to virtual machines in the scale set.' Manual - You control the application of updates to virtual machines in the scale set. You do this by using the manualUpgrade action. ; Automatic - All virtual machines in the scale set are automatically updated at the same time. - Automatic, Manual, Rolling. + +- Required: No +- Type: string +- Default: `'Manual'` +- Allowed: + ```Bicep + [ + 'Automatic' + 'Manual' + 'Rolling' + ] + ``` + +### Parameter: `vmNamePrefix` + +Specifies the computer name prefix for all of the virtual machines in the scale set. + +- Required: No +- Type: string +- Default: `'vmssvm'` + +### Parameter: `vmPriority` + +Specifies the priority for the virtual machine. + +- Required: No +- Type: string +- Default: `'Regular'` +- Allowed: + ```Bicep + [ + 'Low' + 'Regular' + 'Spot' + ] + ``` + +### Parameter: `vTpmEnabled` + +Specifies whether vTPM should be enabled on the virtual machine scale set. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `winRM` + +Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `zoneBalance` + +Whether to force strictly even Virtual Machine distribution cross x-zones in case there is zone outage. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `baseTime` + +Do not provide a value! This date value is used to generate a registration token. + +- Required: No +- Type: string +- Default: `[utcNow('u')]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the virtual machine scale set. | +| `resourceGroupName` | string | The resource group of the virtual machine scale set. | +| `resourceId` | string | The resource ID of the virtual machine scale set. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/extension/README.md b/avm/1.1.0/res/compute/virtual-machine-scale-set/extension/README.md new file mode 100644 index 000000000..f169ea574 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/extension/README.md @@ -0,0 +1,132 @@ +# Virtual Machine Scale Set Extensions `[Microsoft.Compute/virtualMachineScaleSets/extensions]` + +This module deploys a Virtual Machine Scale Set Extension. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Compute/virtualMachineScaleSets/extensions` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-09-01/virtualMachineScaleSets/extensions) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`autoUpgradeMinorVersion`](#parameter-autoupgrademinorversion) | bool | Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. | +| [`enableAutomaticUpgrade`](#parameter-enableautomaticupgrade) | bool | Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. | +| [`name`](#parameter-name) | string | The name of the virtual machine scale set extension. | +| [`publisher`](#parameter-publisher) | string | The name of the extension handler publisher. | +| [`type`](#parameter-type) | string | Specifies the type of the extension; an example is "CustomScriptExtension". | +| [`typeHandlerVersion`](#parameter-typehandlerversion) | string | Specifies the version of the script handler. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`virtualMachineScaleSetName`](#parameter-virtualmachinescalesetname) | string | The name of the parent virtual machine scale set that extension is provisioned for. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`forceUpdateTag`](#parameter-forceupdatetag) | string | How the extension handler should be forced to update even if the extension configuration has not changed. | +| [`protectedSettings`](#parameter-protectedsettings) | secureObject | Any object that contains the extension specific protected settings. | +| [`settings`](#parameter-settings) | object | Any object that contains the extension specific settings. | +| [`supressFailures`](#parameter-supressfailures) | bool | Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false. | + +### Parameter: `autoUpgradeMinorVersion` + +Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. + +- Required: Yes +- Type: bool + +### Parameter: `enableAutomaticUpgrade` + +Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. + +- Required: Yes +- Type: bool + +### Parameter: `name` + +The name of the virtual machine scale set extension. + +- Required: Yes +- Type: string + +### Parameter: `publisher` + +The name of the extension handler publisher. + +- Required: Yes +- Type: string + +### Parameter: `type` + +Specifies the type of the extension; an example is "CustomScriptExtension". + +- Required: Yes +- Type: string + +### Parameter: `typeHandlerVersion` + +Specifies the version of the script handler. + +- Required: Yes +- Type: string + +### Parameter: `virtualMachineScaleSetName` + +The name of the parent virtual machine scale set that extension is provisioned for. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `forceUpdateTag` + +How the extension handler should be forced to update even if the extension configuration has not changed. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `protectedSettings` + +Any object that contains the extension specific protected settings. + +- Required: No +- Type: secureObject +- Default: `{}` + +### Parameter: `settings` + +Any object that contains the extension specific settings. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `supressFailures` + +Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false. + +- Required: No +- Type: bool +- Default: `False` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the extension. | +| `resourceGroupName` | string | The name of the Resource Group the extension was created in. | +| `resourceId` | string | The ResourceId of the extension. | diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/extension/main.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/extension/main.bicep new file mode 100644 index 000000000..9b10d671e --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/extension/main.bicep @@ -0,0 +1,65 @@ +metadata name = 'Virtual Machine Scale Set Extensions' +metadata description = 'This module deploys a Virtual Machine Scale Set Extension.' + +@description('Conditional. The name of the parent virtual machine scale set that extension is provisioned for. Required if the template is used in a standalone deployment.') +param virtualMachineScaleSetName string + +@description('Required. The name of the virtual machine scale set extension.') +param name string + +@description('Required. The name of the extension handler publisher.') +param publisher string + +@description('Required. Specifies the type of the extension; an example is "CustomScriptExtension".') +param type string + +@description('Required. Specifies the version of the script handler.') +param typeHandlerVersion string + +@description('Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true.') +param autoUpgradeMinorVersion bool + +@description('Optional. How the extension handler should be forced to update even if the extension configuration has not changed.') +param forceUpdateTag string = '' + +@description('Optional. Any object that contains the extension specific settings.') +param settings object = {} + +@description('Optional. Any object that contains the extension specific protected settings.') +@secure() +param protectedSettings object = {} + +@description('Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false.') +param supressFailures bool = false + +@description('Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available.') +param enableAutomaticUpgrade bool + +resource virtualMachineScaleSet 'Microsoft.Compute/virtualMachineScaleSets@2023-09-01' existing = { + name: virtualMachineScaleSetName +} + +resource extension 'Microsoft.Compute/virtualMachineScaleSets/extensions@2023-09-01' = { + name: name + parent: virtualMachineScaleSet + properties: { + publisher: publisher + type: type + typeHandlerVersion: typeHandlerVersion + autoUpgradeMinorVersion: autoUpgradeMinorVersion + enableAutomaticUpgrade: enableAutomaticUpgrade + forceUpdateTag: !empty(forceUpdateTag) ? forceUpdateTag : null + settings: !empty(settings) ? settings : null + protectedSettings: !empty(protectedSettings) ? protectedSettings : null + suppressFailures: supressFailures + } +} + +@description('The name of the extension.') +output name string = extension.name + +@description('The ResourceId of the extension.') +output resourceId string = extension.id + +@description('The name of the Resource Group the extension was created in.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/extension/main.json b/avm/1.1.0/res/compute/virtual-machine-scale-set/extension/main.json new file mode 100644 index 000000000..8c574f652 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/extension/main.json @@ -0,0 +1,126 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "285716786930852482" + }, + "name": "Virtual Machine Scale Set Extensions", + "description": "This module deploys a Virtual Machine Scale Set Extension." + }, + "parameters": { + "virtualMachineScaleSetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine scale set that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine scale set extension." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The ResourceId of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachineScaleSets/extensions', parameters('virtualMachineScaleSetName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/main.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/main.bicep new file mode 100644 index 000000000..6f398f5b6 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/main.bicep @@ -0,0 +1,958 @@ +metadata name = 'Virtual Machine Scale Sets' +metadata description = 'This module deploys a Virtual Machine Scale Set.' + +@description('Required. Name of the VMSS.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your virtual machine scale sets.') +param encryptionAtHost bool = true + +@description('Optional. Specifies the SecurityType of the virtual machine scale set. It is set as TrustedLaunch to enable UefiSettings.') +param securityType string = '' + +@description('Optional. Specifies whether secure boot should be enabled on the virtual machine scale set. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings.') +param secureBootEnabled bool = false + +@description('Optional. Specifies whether vTPM should be enabled on the virtual machine scale set. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings.') +param vTpmEnabled bool = false + +@description('Required. OS image reference. In case of marketplace images, it\'s the combination of the publisher, offer, sku, version attributes. In case of custom images it\'s the resource ID of the custom image.') +param imageReference object + +@description('Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use.') +param plan object = {} + +@description('Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VM Scale sets.') +param osDisk object + +@description('Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VM Scale sets.') +param dataDisks array = [] + +@description('Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled.') +param ultraSSDEnabled bool = false + +@description('Required. Administrator username.') +@secure() +param adminUsername string + +@description('Required. When specifying a Windows Virtual Machine, this value should be passed.') +@secure() +param adminPassword string + +@description('Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format.') +param customData string = '' + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Fault Domain count for each placement group.') +param scaleSetFaultDomain int = 1 + +@description('Optional. Resource ID of a proximity placement group.') +param proximityPlacementGroupResourceId string = '' + +@description('Required. Configures NICs and PIPs.') +param nicConfigurations array + +@description('Optional. Specifies the priority for the virtual machine.') +@allowed([ + 'Regular' + 'Low' + 'Spot' +]) +param vmPriority string = 'Regular' + +@description('Optional. Specifies the eviction policy for the low priority virtual machine. Will result in \'Deallocate\' eviction policy.') +param enableEvictionPolicy bool = false + +@description('Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars.') +param maxPriceForLowPriorityVm int? + +@description('Optional. Specifies that the image or disk that is being used was licensed on-premises. This element is only used for images that contain the Windows Server operating system.') +@allowed([ + 'Windows_Client' + 'Windows_Server' + '' +]) +param licenseType string = '' + +@description('Optional. Required if name is specified. Password of the user specified in user parameter.') +@secure() +param extensionDomainJoinPassword string = '' + +@description('Optional. The configuration for the [Domain Join] extension. Must at least contain the ["enabled": true] property to be executed.') +@secure() +#disable-next-line secure-parameter-default +param extensionDomainJoinConfig object = { + enabled: false +} + +@description('Optional. The configuration for the [Anti Malware] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionAntiMalwareConfig object = { + enabled: false +} + +@description('Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionMonitoringAgentConfig object = { + enabled: false + autoUpgradeMinorVersion: true +} + +@description('Optional. Resource ID of the monitoring log analytics workspace.') +param monitoringWorkspaceResourceId string = '' + +@description('Optional. The configuration for the [Dependency Agent] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionDependencyAgentConfig object = { + enabled: false +} + +@description('Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionNetworkWatcherAgentConfig object = { + enabled: false +} + +@description('Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the ["enabled": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys.') +param extensionAzureDiskEncryptionConfig object = { + enabled: false +} + +@description('Optional. Turned on by default. The configuration for the [Application Health Monitoring] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionHealthConfig object = { + enabled: true + settings: { + protocol: 'http' + port: 80 + requestPath: '/' + } +} + +@description('Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionDSCConfig object = { + enabled: false +} + +@description('Optional. The configuration for the [Custom Script] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionCustomScriptConfig object = { + enabled: false + fileData: [] +} + +@description('Optional. Storage account boot diagnostic base URI.') +param bootDiagnosticStorageAccountUri string = '.blob.${environment().suffixes.storage}/' + +@description('Optional. The name of the boot diagnostic storage account. Provide this if you want to use your own storage account for security reasons instead of the recommended Microsoft Managed Storage Account.') +param bootDiagnosticStorageAccountName string = '' + +@description('Optional. Enable boot diagnostics to use default managed or secure storage. Defaults set to false.') +param bootDiagnosticEnabled bool = false + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Specifies the mode of an upgrade to virtual machines in the scale set.\' Manual - You control the application of updates to virtual machines in the scale set. You do this by using the manualUpgrade action. ; Automatic - All virtual machines in the scale set are automatically updated at the same time. - Automatic, Manual, Rolling.') +@allowed([ + 'Manual' + 'Automatic' + 'Rolling' +]) +param upgradePolicyMode string = 'Manual' + +@description('Optional. Allow VMSS to ignore AZ boundaries when constructing upgrade batches. Take into consideration the Update Domain and maxBatchInstancePercent to determine the batch size.') +param enableCrossZoneUpgrade bool = false + +@description('Optional. Create new virtual machines to upgrade the scale set, rather than updating the existing virtual machines. Existing virtual machines will be deleted once the new virtual machines are created for each batch.') +param maxSurge bool = false + +@description('Optional. Upgrade all unhealthy instances in a scale set before any healthy instances.') +param prioritizeUnhealthyInstances bool = false + +@description('Optional. Rollback failed instances to previous model if the Rolling Upgrade policy is violated.') +param rollbackFailedInstancesOnPolicyBreach bool = false + +@description('Optional. The maximum percent of total virtual machine instances that will be upgraded simultaneously by the rolling upgrade in one batch. As this is a maximum, unhealthy instances in previous or future batches can cause the percentage of instances in a batch to decrease to ensure higher reliability.') +param maxBatchInstancePercent int = 20 + +@description('Optional. The maximum percentage of the total virtual machine instances in the scale set that can be simultaneously unhealthy, either as a result of being upgraded, or by being found in an unhealthy state by the virtual machine health checks before the rolling upgrade aborts. This constraint will be checked prior to starting any batch.') +param maxUnhealthyInstancePercent int = 20 + +@description('Optional. The maximum percentage of the total virtual machine instances in the scale set that can be simultaneously unhealthy, either as a result of being upgraded, or by being found in an unhealthy state by the virtual machine health checks before the rolling upgrade aborts. This constraint will be checked prior to starting any batch.') +param maxUnhealthyUpgradedInstancePercent int = 20 + +@description('Optional. The wait time between completing the update for all virtual machines in one batch and starting the next batch. The time duration should be specified in ISO 8601 format.') +param pauseTimeBetweenBatches string = 'PT0S' + +@description('Optional. Indicates whether OS upgrades should automatically be applied to scale set instances in a rolling fashion when a newer version of the OS image becomes available. Default value is false. If this is set to true for Windows based scale sets, enableAutomaticUpdates is automatically set to false and cannot be set to true.') +param enableAutomaticOSUpgrade bool = false + +@description('Optional. Whether OS image rollback feature should be disabled.') +param disableAutomaticRollback bool = false + +@description('Optional. Specifies whether automatic repairs should be enabled on the virtual machine scale set.') +param automaticRepairsPolicyEnabled bool = true + +@description('Optional. The amount of time for which automatic repairs are suspended due to a state change on VM. The grace time starts after the state change has completed. This helps avoid premature or accidental repairs. The time duration should be specified in ISO 8601 format. The minimum allowed grace period is 30 minutes (PT30M). The maximum allowed grace period is 90 minutes (PT90M).') +param gracePeriod string = 'PT30M' + +@description('Optional. Specifies the computer name prefix for all of the virtual machines in the scale set.') +@minLength(1) +@maxLength(15) +param vmNamePrefix string = 'vmssvm' + +@description('Optional. Specifies the orchestration mode for the virtual machine scale set.') +@allowed([ + 'Flexible' + 'Uniform' +]) +param orchestrationMode string = 'Flexible' + +@description('Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later.') +param provisionVMAgent bool = true + +@description('Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning.') +param enableAutomaticUpdates bool = true + +@description('Optional. VM guest patching orchestration mode. \'AutomaticByOS\' & \'Manual\' are for Windows only, \'ImageDefault\' for Linux only. Refer to \'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching\'.') +@allowed([ + 'AutomaticByPlatform' + 'AutomaticByOS' + 'Manual' + 'ImageDefault' + '' +]) +param patchMode string = 'AutomaticByPlatform' + +@description('Optional. Enables customer to schedule patching without accidental upgrades.') +param bypassPlatformSafetyChecksOnUserSchedule bool = true + +@description('Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations.') +@allowed([ + 'Always' + 'IfRequired' + 'Never' + 'Unknown' +]) +param rebootSetting string = 'IfRequired' + +@description('Optional. VM guest patching assessment mode. Set it to \'AutomaticByPlatform\' to enable automatically check for updates every 24 hours.') +@allowed([ + 'AutomaticByPlatform' + 'ImageDefault' +]) +param patchAssessmentMode string = 'ImageDefault' + +@description('Optional. Specifies the time zone of the virtual machine. e.g. \'Pacific Standard Time\'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`.') +param timeZone string = '' + +@description('Optional. Specifies additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. - AdditionalUnattendContent object.') +param additionalUnattendContent array = [] + +@description('Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object.') +param winRM object = {} + +@description('Optional. Specifies whether password authentication should be disabled.') +#disable-next-line secure-secrets-in-params // Not a secret +param disablePasswordAuthentication bool = false + +@description('Optional. The list of SSH public keys used to authenticate with linux based VMs.') +param publicKeys array = [] + +@description('Optional. Specifies set of certificates that should be installed onto the virtual machines in the scale set.') +#disable-next-line secure-secrets-in-params // Not a secret +param secrets array = [] + +@description('Optional. Specifies Scheduled Event related configurations.') +param scheduledEventsProfile object = {} + +@description('Optional. Specifies whether the Virtual Machine Scale Set should be overprovisioned.') +param overprovision bool = false + +@description('Optional. When Overprovision is enabled, extensions are launched only on the requested number of VMs which are finally kept. This property will hence ensure that the extensions do not run on the extra overprovisioned VMs.') +param doNotRunExtensionsOnOverprovisionedVMs bool = false + +@description('Optional. Whether to force strictly even Virtual Machine distribution cross x-zones in case there is zone outage.') +param zoneBalance bool = false + +@description('Optional. When true this limits the scale set to a single placement group, of max size 100 virtual machines. NOTE: If singlePlacementGroup is true, it may be modified to false. However, if singlePlacementGroup is false, it may not be modified to true.') +param singlePlacementGroup bool = false + +@description('Optional. Specifies the scale-in policy that decides which virtual machines are chosen for removal when a Virtual Machine Scale Set is scaled-in.') +param scaleInPolicy object = { + rules: [ + 'Default' + ] +} + +@description('Required. The SKU size of the VMs.') +param skuName string + +@description('Optional. The initial instance count of scale set VMs.') +param skuCapacity int = 1 + +@description('Optional. The virtual machine scale set zones. NOTE: Availability zones can only be set when you create the scale set.') +param availabilityZones array = [1, 2, 3] + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Required. The chosen OS type.') +@allowed([ + 'Windows' + 'Linux' +]) +param osType string + +@description('Generated. Do not provide a value! This date value is used to generate a registration token.') +param baseTime string = utcNow('u') + +@description('Optional. SAS token validity length to use to download files from storage accounts. Usage: \'PT8H\' - valid for 8 hours; \'P5D\' - valid for 5 days; \'P1Y\' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours.') +param sasTokenValidityLength string = 'PT8H' + +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType + +var publicKeysFormatted = [ + for publicKey in publicKeys: { + path: publicKey.path + keyData: publicKey.keyData + } +] + +var linuxConfiguration = { + disablePasswordAuthentication: disablePasswordAuthentication + ssh: { + publicKeys: publicKeysFormatted + } + provisionVMAgent: provisionVMAgent + patchSettings: (provisionVMAgent && (patchMode =~ 'AutomaticByPlatform' || patchMode =~ 'ImageDefault')) + ? { + patchMode: patchMode + assessmentMode: patchAssessmentMode + automaticByPlatformSettings: (patchMode =~ 'AutomaticByPlatform') + ? { + bypassPlatformSafetyChecksOnUserSchedule: bypassPlatformSafetyChecksOnUserSchedule + rebootSetting: rebootSetting + } + : null + } + : null +} + +var windowsConfiguration = { + provisionVMAgent: provisionVMAgent + enableAutomaticUpdates: enableAutomaticUpdates + patchSettings: (provisionVMAgent && (patchMode =~ 'AutomaticByPlatform' || patchMode =~ 'AutomaticByOS' || patchMode =~ 'Manual')) + ? { + patchMode: patchMode + assessmentMode: patchAssessmentMode + automaticByPlatformSettings: (patchMode =~ 'AutomaticByPlatform') + ? { + bypassPlatformSafetyChecksOnUserSchedule: bypassPlatformSafetyChecksOnUserSchedule + rebootSetting: rebootSetting + } + : null + } + : null + timeZone: empty(timeZone) ? null : timeZone + additionalUnattendContent: empty(additionalUnattendContent) ? null : additionalUnattendContent + winRM: !empty(winRM) ? { listeners: winRM.listeners } : null +} + +var accountSasProperties = { + signedServices: 'b' + signedPermission: 'r' + signedExpiry: dateTimeAdd(baseTime, sasTokenValidityLength) + signedResourceTypes: 'o' + signedProtocol: 'https' +} + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Data Operator for Managed Disks': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '959f8984-c045-4866-89c7-12bf9737be2e' + ) + 'Desktop Virtualization Power On Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '489581de-a3bd-480d-9518-53dea7416b33' + ) + 'Desktop Virtualization Power On Off Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '40c5ff49-9181-41f8-ae61-143b0e78555e' + ) + 'Desktop Virtualization Virtual Machine Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a959dbd1-f747-45e3-8ba6-dd80f235f97c' + ) + 'DevTest Labs User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '76283e04-6283-4c54-8f91-bcf1374a3c64' + ) + 'Disk Backup Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24' + ) + 'Disk Pool Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '60fc6e62-5479-42d4-8bf4-67625fcc2840' + ) + 'Disk Restore Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b50d9833-a0cb-478e-945f-707fcc997c13' + ) + 'Disk Snapshot Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7efff54f-a5b4-42b5-a1c5-5411624893ce' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) + 'Virtual Machine Administrator Login': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '1c0163c0-47e6-4577-8991-ea5c82e286e4' + ) + 'Virtual Machine Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '9980e02c-c2be-4d73-94e8-173b1dc7cf3c' + ) + 'Virtual Machine User Login': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'fb879df8-f326-4884-b1cf-06f3ad86be52' + ) + 'VM Scanner Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.compute-virtualmachinescaleset.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2024-07-01' = { + name: name + location: location + tags: tags + identity: identity + zones: availabilityZones + properties: { + orchestrationMode: orchestrationMode + proximityPlacementGroup: !empty(proximityPlacementGroupResourceId) + ? { + id: proximityPlacementGroupResourceId + } + : null + upgradePolicy: { + mode: upgradePolicyMode + rollingUpgradePolicy: upgradePolicyMode == 'Rolling' + ? { + enableCrossZoneUpgrade: enableCrossZoneUpgrade + maxBatchInstancePercent: maxBatchInstancePercent + maxSurge: maxSurge + maxUnhealthyInstancePercent: maxUnhealthyInstancePercent + maxUnhealthyUpgradedInstancePercent: maxUnhealthyUpgradedInstancePercent + pauseTimeBetweenBatches: pauseTimeBetweenBatches + prioritizeUnhealthyInstances: prioritizeUnhealthyInstances + rollbackFailedInstancesOnPolicyBreach: rollbackFailedInstancesOnPolicyBreach + } + : null + automaticOSUpgradePolicy: { + enableAutomaticOSUpgrade: enableAutomaticOSUpgrade + disableAutomaticRollback: disableAutomaticRollback + } + } + automaticRepairsPolicy: { + enabled: automaticRepairsPolicyEnabled + gracePeriod: gracePeriod + } + virtualMachineProfile: { + osProfile: { + computerNamePrefix: vmNamePrefix + adminUsername: adminUsername + adminPassword: adminPassword + customData: !empty(customData) ? base64(customData) : null + windowsConfiguration: osType == 'Windows' ? windowsConfiguration : null + linuxConfiguration: osType == 'Linux' ? linuxConfiguration : null + secrets: secrets + } + securityProfile: { + encryptionAtHost: encryptionAtHost ? encryptionAtHost : null + securityType: securityType + uefiSettings: securityType == 'TrustedLaunch' + ? { + secureBootEnabled: secureBootEnabled + vTpmEnabled: vTpmEnabled + } + : null + } + storageProfile: { + imageReference: imageReference + osDisk: { + createOption: osDisk.createOption + diskSizeGB: osDisk.diskSizeGB + caching: osDisk.?caching + writeAcceleratorEnabled: osDisk.?writeAcceleratorEnabled + diffDiskSettings: osDisk.?diffDiskSettings + osType: osDisk.?osType + image: osDisk.?image + vhdContainers: osDisk.?vhdContainers + managedDisk: { + storageAccountType: osDisk.managedDisk.storageAccountType + diskEncryptionSet: contains(osDisk.managedDisk, 'diskEncryptionSet') + ? { + id: osDisk.managedDisk.diskEncryptionSet.id + } + : null + } + } + dataDisks: [ + for (dataDisk, index) in dataDisks: { + lun: index + diskSizeGB: dataDisk.diskSizeGB + createOption: dataDisk.createOption + caching: dataDisk.caching + writeAcceleratorEnabled: osDisk.?writeAcceleratorEnabled + managedDisk: { + storageAccountType: dataDisk.managedDisk.storageAccountType + diskEncryptionSet: contains(dataDisk.managedDisk, 'diskEncryptionSet') + ? { + id: dataDisk.managedDisk.diskEncryptionSet.id + } + : null + } + diskIOPSReadWrite: contains(osDisk, 'diskIOPSReadWrite') ? dataDisk.diskIOPSReadWrite : null + diskMBpsReadWrite: contains(osDisk, 'diskMBpsReadWrite') ? dataDisk.diskMBpsReadWrite : null + } + ] + } + networkProfile: { + networkApiVersion: (orchestrationMode == 'Flexible') ? '2020-11-01' : null + networkInterfaceConfigurations: [ + for (nicConfiguration, index) in nicConfigurations: { + name: '${name}${nicConfiguration.nicSuffix}configuration-${index}' + properties: { + primary: (index == 0) ? true : any(null) + enableAcceleratedNetworking: nicConfiguration.?enableAcceleratedNetworking ?? true + networkSecurityGroup: contains(nicConfiguration, 'nsgId') + ? { + id: nicConfiguration.nsgId + } + : null + ipConfigurations: nicConfiguration.ipConfigurations + } + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: !empty(bootDiagnosticStorageAccountName) ? true : bootDiagnosticEnabled + storageUri: !empty(bootDiagnosticStorageAccountName) + ? 'https://${bootDiagnosticStorageAccountName}${bootDiagnosticStorageAccountUri}' + : null + } + } + extensionProfile: extensionHealthConfig.enabled + ? { + extensions: [ + { + name: 'HealthExtension' + properties: { + publisher: 'Microsoft.ManagedServices' + type: (osType == 'Windows' ? 'ApplicationHealthWindows' : 'ApplicationHealthLinux') + typeHandlerVersion: extensionHealthConfig.?typeHandlerVersion ?? '1.0' + autoUpgradeMinorVersion: extensionHealthConfig.?autoUpgradeMinorVersion ?? false + settings: { + protocol: extensionHealthConfig.?protocol ?? 'http' + port: extensionHealthConfig.?port ?? 80 + requestPath: extensionHealthConfig.?requestPath ?? '/' + } + } + } + ] + } + : null + licenseType: empty(licenseType) ? null : licenseType + priority: vmPriority + evictionPolicy: enableEvictionPolicy ? 'Deallocate' : null + billingProfile: !empty(vmPriority) && null != maxPriceForLowPriorityVm + ? { + maxPrice: maxPriceForLowPriorityVm + } + : null + scheduledEventsProfile: scheduledEventsProfile + } + overprovision: (orchestrationMode == 'Uniform') ? overprovision : null + doNotRunExtensionsOnOverprovisionedVMs: (orchestrationMode == 'Uniform') + ? doNotRunExtensionsOnOverprovisionedVMs + : null + zoneBalance: zoneBalance == 'true' ? zoneBalance : null + platformFaultDomainCount: scaleSetFaultDomain + singlePlacementGroup: singlePlacementGroup + additionalCapabilities: { + ultraSSDEnabled: ultraSSDEnabled + } + scaleInPolicy: scaleInPolicy + } + sku: { + name: skuName + capacity: skuCapacity + } + plan: !empty(plan) ? plan : null +} + +module vmss_domainJoinExtension 'extension/main.bicep' = if (extensionDomainJoinConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VMSS-DomainJoin' + params: { + virtualMachineScaleSetName: vmss.name + name: 'DomainJoin' + publisher: 'Microsoft.Compute' + type: 'JsonADDomainExtension' + typeHandlerVersion: extensionDomainJoinConfig.?typeHandlerVersion ?? '1.3' + autoUpgradeMinorVersion: extensionDomainJoinConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionDomainJoinConfig.?enableAutomaticUpgrade ?? false + settings: extensionDomainJoinConfig.settings + protectedSettings: { + Password: extensionDomainJoinPassword + } + } +} + +module vmss_microsoftAntiMalwareExtension 'extension/main.bicep' = if (extensionAntiMalwareConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VMSS-MicrosoftAntiMalware' + params: { + virtualMachineScaleSetName: vmss.name + name: 'MicrosoftAntiMalware' + publisher: 'Microsoft.Azure.Security' + type: 'IaaSAntimalware' + typeHandlerVersion: extensionAntiMalwareConfig.?typeHandlerVersion ?? '1.3' + autoUpgradeMinorVersion: extensionAntiMalwareConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionAntiMalwareConfig.?enableAutomaticUpgrade ?? false + settings: extensionAntiMalwareConfig.settings + } + dependsOn: [ + vmss_domainJoinExtension + ] +} + +resource vmss_logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' existing = if (!empty(monitoringWorkspaceResourceId)) { + name: last(split((!empty(monitoringWorkspaceResourceId) ? monitoringWorkspaceResourceId : 'law'), '/'))! + scope: az.resourceGroup( + split((!empty(monitoringWorkspaceResourceId) ? monitoringWorkspaceResourceId : '//'), '/')[2], + split((!empty(monitoringWorkspaceResourceId) ? monitoringWorkspaceResourceId : '////'), '/')[4] + ) +} + +module vmss_azureMonitorAgentExtension 'extension/main.bicep' = if (extensionMonitoringAgentConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VMSS-AzureMonitorAgent' + params: { + virtualMachineScaleSetName: vmss.name + name: 'AzureMonitorAgent' + publisher: 'Microsoft.Azure.Monitor' + type: osType == 'Windows' ? 'AzureMonitorWindowsAgent' : 'AzureMonitorLinuxAgent' + typeHandlerVersion: extensionMonitoringAgentConfig.?typeHandlerVersion != null + ? extensionMonitoringAgentConfig.typeHandlerVersion + : (osType == 'Windows' ? '1.22' : '1.29') + autoUpgradeMinorVersion: extensionMonitoringAgentConfig.autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionMonitoringAgentConfig.?enableAutomaticUpgrade ?? false + settings: { + workspaceId: !empty(monitoringWorkspaceResourceId) ? vmss_logAnalyticsWorkspace.properties.customerId : '' + GCS_AUTO_CONFIG: osType == 'Linux' ? true : null + } + protectedSettings: { + workspaceKey: !empty(monitoringWorkspaceResourceId) ? vmss_logAnalyticsWorkspace.listKeys().primarySharedKey : '' + } + } + dependsOn: [ + vmss_microsoftAntiMalwareExtension + ] +} + +module vmss_dependencyAgentExtension 'extension/main.bicep' = if (extensionDependencyAgentConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VMSS-DependencyAgent' + params: { + virtualMachineScaleSetName: vmss.name + name: 'DependencyAgent' + publisher: 'Microsoft.Azure.Monitoring.DependencyAgent' + type: osType == 'Windows' ? 'DependencyAgentWindows' : 'DependencyAgentLinux' + typeHandlerVersion: extensionDependencyAgentConfig.?typeHandlerVersion ?? '9.5' + autoUpgradeMinorVersion: extensionDependencyAgentConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionDependencyAgentConfig.?enableAutomaticUpgrade ?? true + } + dependsOn: [ + vmss_azureMonitorAgentExtension + ] +} + +module vmss_networkWatcherAgentExtension 'extension/main.bicep' = if (extensionNetworkWatcherAgentConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VMSS-NetworkWatcherAgent' + params: { + virtualMachineScaleSetName: vmss.name + name: 'NetworkWatcherAgent' + publisher: 'Microsoft.Azure.NetworkWatcher' + type: osType == 'Windows' ? 'NetworkWatcherAgentWindows' : 'NetworkWatcherAgentLinux' + typeHandlerVersion: extensionNetworkWatcherAgentConfig.?typeHandlerVersion ?? '1.4' + autoUpgradeMinorVersion: extensionNetworkWatcherAgentConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionNetworkWatcherAgentConfig.?enableAutomaticUpgrade ?? false + } + dependsOn: [ + vmss_dependencyAgentExtension + ] +} + +module vmss_desiredStateConfigurationExtension 'extension/main.bicep' = if (extensionDSCConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VMSS-DesiredStateConfiguration' + params: { + virtualMachineScaleSetName: vmss.name + name: 'DesiredStateConfiguration' + publisher: 'Microsoft.Powershell' + type: 'DSC' + typeHandlerVersion: extensionDSCConfig.?typeHandlerVersion ?? '2.77' + autoUpgradeMinorVersion: extensionDSCConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionDSCConfig.?enableAutomaticUpgrade ?? false + settings: extensionDSCConfig.?settings ?? {} + protectedSettings: extensionDSCConfig.?protectedSettings ?? {} + } + dependsOn: [ + vmss_networkWatcherAgentExtension + ] +} + +module vmss_customScriptExtension 'extension/main.bicep' = if (extensionCustomScriptConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VMSS-CustomScriptExtension' + params: { + virtualMachineScaleSetName: vmss.name + name: 'CustomScriptExtension' + publisher: osType == 'Windows' ? 'Microsoft.Compute' : 'Microsoft.Azure.Extensions' + type: osType == 'Windows' ? 'CustomScriptExtension' : 'CustomScript' + typeHandlerVersion: extensionCustomScriptConfig.?typeHandlerVersion ?? (osType == 'Windows' ? '1.10' : '2.1') + autoUpgradeMinorVersion: extensionCustomScriptConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionCustomScriptConfig.?enableAutomaticUpgrade ?? false + settings: { + fileUris: [ + for fileData in extensionCustomScriptConfig.fileData: contains(fileData, 'storageAccountId') + ? '${fileData.uri}?${listAccountSas(fileData.storageAccountId, '2019-04-01', accountSasProperties).accountSasToken}' + : fileData.uri + ] + } + protectedSettings: extensionCustomScriptConfig.?protectedSettings ?? {} + } + dependsOn: [ + vmss_desiredStateConfigurationExtension + ] +} + +module vmss_azureDiskEncryptionExtension 'extension/main.bicep' = if (extensionAzureDiskEncryptionConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VMSS-AzureDiskEncryption' + params: { + virtualMachineScaleSetName: vmss.name + name: 'AzureDiskEncryption' + publisher: 'Microsoft.Azure.Security' + type: osType == 'Windows' ? 'AzureDiskEncryption' : 'AzureDiskEncryptionForLinux' + typeHandlerVersion: extensionAzureDiskEncryptionConfig.?typeHandlerVersion ?? (osType == 'Windows' ? '2.2' : '1.1') + autoUpgradeMinorVersion: extensionAzureDiskEncryptionConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionAzureDiskEncryptionConfig.?enableAutomaticUpgrade ?? false + forceUpdateTag: extensionAzureDiskEncryptionConfig.?forceUpdateTag ?? '1.0' + settings: extensionAzureDiskEncryptionConfig.settings + } + dependsOn: [ + vmss_customScriptExtension + ] +} + +resource vmss_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: vmss +} + +resource vmss_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: vmss + } +] + +resource vmss_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(vmss.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: vmss + } +] + +@description('The resource ID of the virtual machine scale set.') +output resourceId string = vmss.id + +@description('The resource group of the virtual machine scale set.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the virtual machine scale set.') +output name string = vmss.name + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string? = vmss.?identity.?principalId + +@description('The location the resource was deployed into.') +output location string = vmss.location + +// =============== // +// Definitions // +// =============== // + +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[]? +}? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/main.json b/avm/1.1.0/res/compute/virtual-machine-scale-set/main.json new file mode 100644 index 000000000..e48a687ed --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/main.json @@ -0,0 +1,2523 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "12053969454032116821" + }, + "name": "Virtual Machine Scale Sets", + "description": "This module deploys a Virtual Machine Scale Set." + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the VMSS." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "encryptionAtHost": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your virtual machine scale sets." + } + }, + "securityType": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the SecurityType of the virtual machine scale set. It is set as TrustedLaunch to enable UefiSettings." + } + }, + "secureBootEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine scale set. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "vTpmEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine scale set. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "imageReference": { + "type": "object", + "metadata": { + "description": "Required. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image." + } + }, + "plan": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." + } + }, + "osDisk": { + "type": "object", + "metadata": { + "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VM Scale sets." + } + }, + "dataDisks": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VM Scale sets." + } + }, + "ultraSSDEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." + } + }, + "adminUsername": { + "type": "securestring", + "metadata": { + "description": "Required. Administrator username." + } + }, + "adminPassword": { + "type": "securestring", + "metadata": { + "description": "Required. When specifying a Windows Virtual Machine, this value should be passed." + } + }, + "customData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "scaleSetFaultDomain": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Optional. Fault Domain count for each placement group." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a proximity placement group." + } + }, + "nicConfigurations": { + "type": "array", + "metadata": { + "description": "Required. Configures NICs and PIPs." + } + }, + "vmPriority": { + "type": "string", + "defaultValue": "Regular", + "allowedValues": [ + "Regular", + "Low", + "Spot" + ], + "metadata": { + "description": "Optional. Specifies the priority for the virtual machine." + } + }, + "enableEvictionPolicy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy." + } + }, + "maxPriceForLowPriorityVm": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." + } + }, + "licenseType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Windows_Client", + "Windows_Server", + "" + ], + "metadata": { + "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises. This element is only used for images that contain the Windows Server operating system." + } + }, + "extensionDomainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if name is specified. Password of the user specified in user parameter." + } + }, + "extensionDomainJoinConfig": { + "type": "secureObject", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAntiMalwareConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Anti Malware] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionMonitoringAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "autoUpgradeMinorVersion": true + }, + "metadata": { + "description": "Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "monitoringWorkspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the monitoring log analytics workspace." + } + }, + "extensionDependencyAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Dependency Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionNetworkWatcherAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAzureDiskEncryptionConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." + } + }, + "extensionHealthConfig": { + "type": "object", + "defaultValue": { + "enabled": true, + "settings": { + "protocol": "http", + "port": 80, + "requestPath": "/" + } + }, + "metadata": { + "description": "Optional. Turned on by default. The configuration for the [Application Health Monitoring] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionDSCConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "fileData": [] + }, + "metadata": { + "description": "Optional. The configuration for the [Custom Script] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "bootDiagnosticStorageAccountUri": { + "type": "string", + "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", + "metadata": { + "description": "Optional. Storage account boot diagnostic base URI." + } + }, + "bootDiagnosticStorageAccountName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the boot diagnostic storage account. Provide this if you want to use your own storage account for security reasons instead of the recommended Microsoft Managed Storage Account." + } + }, + "bootDiagnosticEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable boot diagnostics to use default managed or secure storage. Defaults set to false." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "upgradePolicyMode": { + "type": "string", + "defaultValue": "Manual", + "allowedValues": [ + "Manual", + "Automatic", + "Rolling" + ], + "metadata": { + "description": "Optional. Specifies the mode of an upgrade to virtual machines in the scale set.' Manual - You control the application of updates to virtual machines in the scale set. You do this by using the manualUpgrade action. ; Automatic - All virtual machines in the scale set are automatically updated at the same time. - Automatic, Manual, Rolling." + } + }, + "enableCrossZoneUpgrade": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Allow VMSS to ignore AZ boundaries when constructing upgrade batches. Take into consideration the Update Domain and maxBatchInstancePercent to determine the batch size." + } + }, + "maxSurge": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Create new virtual machines to upgrade the scale set, rather than updating the existing virtual machines. Existing virtual machines will be deleted once the new virtual machines are created for each batch." + } + }, + "prioritizeUnhealthyInstances": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Upgrade all unhealthy instances in a scale set before any healthy instances." + } + }, + "rollbackFailedInstancesOnPolicyBreach": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Rollback failed instances to previous model if the Rolling Upgrade policy is violated." + } + }, + "maxBatchInstancePercent": { + "type": "int", + "defaultValue": 20, + "metadata": { + "description": "Optional. The maximum percent of total virtual machine instances that will be upgraded simultaneously by the rolling upgrade in one batch. As this is a maximum, unhealthy instances in previous or future batches can cause the percentage of instances in a batch to decrease to ensure higher reliability." + } + }, + "maxUnhealthyInstancePercent": { + "type": "int", + "defaultValue": 20, + "metadata": { + "description": "Optional. The maximum percentage of the total virtual machine instances in the scale set that can be simultaneously unhealthy, either as a result of being upgraded, or by being found in an unhealthy state by the virtual machine health checks before the rolling upgrade aborts. This constraint will be checked prior to starting any batch." + } + }, + "maxUnhealthyUpgradedInstancePercent": { + "type": "int", + "defaultValue": 20, + "metadata": { + "description": "Optional. The maximum percentage of the total virtual machine instances in the scale set that can be simultaneously unhealthy, either as a result of being upgraded, or by being found in an unhealthy state by the virtual machine health checks before the rolling upgrade aborts. This constraint will be checked prior to starting any batch." + } + }, + "pauseTimeBetweenBatches": { + "type": "string", + "defaultValue": "PT0S", + "metadata": { + "description": "Optional. The wait time between completing the update for all virtual machines in one batch and starting the next batch. The time duration should be specified in ISO 8601 format." + } + }, + "enableAutomaticOSUpgrade": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether OS upgrades should automatically be applied to scale set instances in a rolling fashion when a newer version of the OS image becomes available. Default value is false. If this is set to true for Windows based scale sets, enableAutomaticUpdates is automatically set to false and cannot be set to true." + } + }, + "disableAutomaticRollback": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether OS image rollback feature should be disabled." + } + }, + "automaticRepairsPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether automatic repairs should be enabled on the virtual machine scale set." + } + }, + "gracePeriod": { + "type": "string", + "defaultValue": "PT30M", + "metadata": { + "description": "Optional. The amount of time for which automatic repairs are suspended due to a state change on VM. The grace time starts after the state change has completed. This helps avoid premature or accidental repairs. The time duration should be specified in ISO 8601 format. The minimum allowed grace period is 30 minutes (PT30M). The maximum allowed grace period is 90 minutes (PT90M)." + } + }, + "vmNamePrefix": { + "type": "string", + "defaultValue": "vmssvm", + "minLength": 1, + "maxLength": 15, + "metadata": { + "description": "Optional. Specifies the computer name prefix for all of the virtual machines in the scale set." + } + }, + "orchestrationMode": { + "type": "string", + "defaultValue": "Flexible", + "allowedValues": [ + "Flexible", + "Uniform" + ], + "metadata": { + "description": "Optional. Specifies the orchestration mode for the virtual machine scale set." + } + }, + "provisionVMAgent": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." + } + }, + "enableAutomaticUpdates": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." + } + }, + "patchMode": { + "type": "string", + "defaultValue": "AutomaticByPlatform", + "allowedValues": [ + "AutomaticByPlatform", + "AutomaticByOS", + "Manual", + "ImageDefault", + "" + ], + "metadata": { + "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." + } + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables customer to schedule patching without accidental upgrades." + } + }, + "rebootSetting": { + "type": "string", + "defaultValue": "IfRequired", + "allowedValues": [ + "Always", + "IfRequired", + "Never", + "Unknown" + ], + "metadata": { + "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." + } + }, + "patchAssessmentMode": { + "type": "string", + "defaultValue": "ImageDefault", + "allowedValues": [ + "AutomaticByPlatform", + "ImageDefault" + ], + "metadata": { + "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." + } + }, + "additionalUnattendContent": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies additional base-64 encoded XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. - AdditionalUnattendContent object." + } + }, + "winRM": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object." + } + }, + "disablePasswordAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether password authentication should be disabled." + } + }, + "publicKeys": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." + } + }, + "secrets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies set of certificates that should be installed onto the virtual machines in the scale set." + } + }, + "scheduledEventsProfile": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Specifies Scheduled Event related configurations." + } + }, + "overprovision": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the Virtual Machine Scale Set should be overprovisioned." + } + }, + "doNotRunExtensionsOnOverprovisionedVMs": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When Overprovision is enabled, extensions are launched only on the requested number of VMs which are finally kept. This property will hence ensure that the extensions do not run on the extra overprovisioned VMs." + } + }, + "zoneBalance": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to force strictly even Virtual Machine distribution cross x-zones in case there is zone outage." + } + }, + "singlePlacementGroup": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When true this limits the scale set to a single placement group, of max size 100 virtual machines. NOTE: If singlePlacementGroup is true, it may be modified to false. However, if singlePlacementGroup is false, it may not be modified to true." + } + }, + "scaleInPolicy": { + "type": "object", + "defaultValue": { + "rules": [ + "Default" + ] + }, + "metadata": { + "description": "Optional. Specifies the scale-in policy that decides which virtual machines are chosen for removal when a Virtual Machine Scale Set is scaled-in." + } + }, + "skuName": { + "type": "string", + "metadata": { + "description": "Required. The SKU size of the VMs." + } + }, + "skuCapacity": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Optional. The initial instance count of scale set VMs." + } + }, + "availabilityZones": { + "type": "array", + "defaultValue": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. The virtual machine scale set zones. NOTE: Availability zones can only be set when you create the scale set." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. The chosen OS type." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to generate a registration token." + } + }, + "sasTokenValidityLength": { + "type": "string", + "defaultValue": "PT8H", + "metadata": { + "description": "Optional. SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + } + }, + "variables": { + "copy": [ + { + "name": "publicKeysFormatted", + "count": "[length(parameters('publicKeys'))]", + "input": { + "path": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].path]", + "keyData": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].keyData]" + } + }, + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "linuxConfiguration": { + "disablePasswordAuthentication": "[parameters('disablePasswordAuthentication')]", + "ssh": { + "publicKeys": "[variables('publicKeysFormatted')]" + }, + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" + }, + "windowsConfiguration": { + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", + "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", + "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), parameters('additionalUnattendContent'))]", + "winRM": "[if(not(empty(parameters('winRM'))), createObject('listeners', parameters('winRM').listeners), null())]" + }, + "accountSasProperties": { + "signedServices": "b", + "signedPermission": "r", + "signedExpiry": "[dateTimeAdd(parameters('baseTime'), parameters('sasTokenValidityLength'))]", + "signedResourceTypes": "o", + "signedProtocol": "https" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", + "Desktop Virtualization Power On Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33')]", + "Desktop Virtualization Power On Off Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e')]", + "Desktop Virtualization Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')]", + "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", + "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", + "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", + "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", + "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", + "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", + "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]", + "VM Scanner Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.compute-virtualmachinescaleset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "vmss": { + "type": "Microsoft.Compute/virtualMachineScaleSets", + "apiVersion": "2024-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "zones": "[parameters('availabilityZones')]", + "properties": { + "orchestrationMode": "[parameters('orchestrationMode')]", + "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", + "upgradePolicy": { + "mode": "[parameters('upgradePolicyMode')]", + "rollingUpgradePolicy": "[if(equals(parameters('upgradePolicyMode'), 'Rolling'), createObject('enableCrossZoneUpgrade', parameters('enableCrossZoneUpgrade'), 'maxBatchInstancePercent', parameters('maxBatchInstancePercent'), 'maxSurge', parameters('maxSurge'), 'maxUnhealthyInstancePercent', parameters('maxUnhealthyInstancePercent'), 'maxUnhealthyUpgradedInstancePercent', parameters('maxUnhealthyUpgradedInstancePercent'), 'pauseTimeBetweenBatches', parameters('pauseTimeBetweenBatches'), 'prioritizeUnhealthyInstances', parameters('prioritizeUnhealthyInstances'), 'rollbackFailedInstancesOnPolicyBreach', parameters('rollbackFailedInstancesOnPolicyBreach')), null())]", + "automaticOSUpgradePolicy": { + "enableAutomaticOSUpgrade": "[parameters('enableAutomaticOSUpgrade')]", + "disableAutomaticRollback": "[parameters('disableAutomaticRollback')]" + } + }, + "automaticRepairsPolicy": { + "enabled": "[parameters('automaticRepairsPolicyEnabled')]", + "gracePeriod": "[parameters('gracePeriod')]" + }, + "virtualMachineProfile": { + "osProfile": { + "computerNamePrefix": "[parameters('vmNamePrefix')]", + "adminUsername": "[parameters('adminUsername')]", + "adminPassword": "[parameters('adminPassword')]", + "customData": "[if(not(empty(parameters('customData'))), base64(parameters('customData')), null())]", + "windowsConfiguration": "[if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null())]", + "linuxConfiguration": "[if(equals(parameters('osType'), 'Linux'), variables('linuxConfiguration'), null())]", + "secrets": "[parameters('secrets')]" + }, + "securityProfile": { + "encryptionAtHost": "[if(parameters('encryptionAtHost'), parameters('encryptionAtHost'), null())]", + "securityType": "[parameters('securityType')]", + "uefiSettings": "[if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null())]" + }, + "storageProfile": { + "copy": [ + { + "name": "dataDisks", + "count": "[length(parameters('dataDisks'))]", + "input": { + "lun": "[copyIndex('dataDisks')]", + "diskSizeGB": "[parameters('dataDisks')[copyIndex('dataDisks')].diskSizeGB]", + "createOption": "[parameters('dataDisks')[copyIndex('dataDisks')].createOption]", + "caching": "[parameters('dataDisks')[copyIndex('dataDisks')].caching]", + "writeAcceleratorEnabled": "[tryGet(parameters('osDisk'), 'writeAcceleratorEnabled')]", + "managedDisk": { + "storageAccountType": "[parameters('dataDisks')[copyIndex('dataDisks')].managedDisk.storageAccountType]", + "diskEncryptionSet": "[if(contains(parameters('dataDisks')[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSet'), createObject('id', parameters('dataDisks')[copyIndex('dataDisks')].managedDisk.diskEncryptionSet.id), null())]" + }, + "diskIOPSReadWrite": "[if(contains(parameters('osDisk'), 'diskIOPSReadWrite'), parameters('dataDisks')[copyIndex('dataDisks')].diskIOPSReadWrite, null())]", + "diskMBpsReadWrite": "[if(contains(parameters('osDisk'), 'diskMBpsReadWrite'), parameters('dataDisks')[copyIndex('dataDisks')].diskMBpsReadWrite, null())]" + } + } + ], + "imageReference": "[parameters('imageReference')]", + "osDisk": { + "createOption": "[parameters('osDisk').createOption]", + "diskSizeGB": "[parameters('osDisk').diskSizeGB]", + "caching": "[tryGet(parameters('osDisk'), 'caching')]", + "writeAcceleratorEnabled": "[tryGet(parameters('osDisk'), 'writeAcceleratorEnabled')]", + "diffDiskSettings": "[tryGet(parameters('osDisk'), 'diffDiskSettings')]", + "osType": "[tryGet(parameters('osDisk'), 'osType')]", + "image": "[tryGet(parameters('osDisk'), 'image')]", + "vhdContainers": "[tryGet(parameters('osDisk'), 'vhdContainers')]", + "managedDisk": { + "storageAccountType": "[parameters('osDisk').managedDisk.storageAccountType]", + "diskEncryptionSet": "[if(contains(parameters('osDisk').managedDisk, 'diskEncryptionSet'), createObject('id', parameters('osDisk').managedDisk.diskEncryptionSet.id), null())]" + } + } + }, + "networkProfile": { + "copy": [ + { + "name": "networkInterfaceConfigurations", + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "name": "[format('{0}{1}configuration-{2}', parameters('name'), parameters('nicConfigurations')[copyIndex('networkInterfaceConfigurations')].nicSuffix, copyIndex('networkInterfaceConfigurations'))]", + "properties": { + "primary": "[if(equals(copyIndex('networkInterfaceConfigurations'), 0), true(), null())]", + "enableAcceleratedNetworking": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaceConfigurations')], 'enableAcceleratedNetworking'), true())]", + "networkSecurityGroup": "[if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaceConfigurations')], 'nsgId'), createObject('id', parameters('nicConfigurations')[copyIndex('networkInterfaceConfigurations')].nsgId), null())]", + "ipConfigurations": "[parameters('nicConfigurations')[copyIndex('networkInterfaceConfigurations')].ipConfigurations]" + } + } + } + ], + "networkApiVersion": "[if(equals(parameters('orchestrationMode'), 'Flexible'), '2020-11-01', null())]" + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnosticEnabled'))]", + "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" + } + }, + "extensionProfile": "[if(parameters('extensionHealthConfig').enabled, createObject('extensions', createArray(createObject('name', 'HealthExtension', 'properties', createObject('publisher', 'Microsoft.ManagedServices', 'type', if(equals(parameters('osType'), 'Windows'), 'ApplicationHealthWindows', 'ApplicationHealthLinux'), 'typeHandlerVersion', coalesce(tryGet(parameters('extensionHealthConfig'), 'typeHandlerVersion'), '1.0'), 'autoUpgradeMinorVersion', coalesce(tryGet(parameters('extensionHealthConfig'), 'autoUpgradeMinorVersion'), false()), 'settings', createObject('protocol', coalesce(tryGet(parameters('extensionHealthConfig'), 'protocol'), 'http'), 'port', coalesce(tryGet(parameters('extensionHealthConfig'), 'port'), 80), 'requestPath', coalesce(tryGet(parameters('extensionHealthConfig'), 'requestPath'), '/')))))), null())]", + "licenseType": "[if(empty(parameters('licenseType')), null(), parameters('licenseType'))]", + "priority": "[parameters('vmPriority')]", + "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", + "billingProfile": "[if(and(not(empty(parameters('vmPriority'))), not(equals(null(), parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', parameters('maxPriceForLowPriorityVm')), null())]", + "scheduledEventsProfile": "[parameters('scheduledEventsProfile')]" + }, + "overprovision": "[if(equals(parameters('orchestrationMode'), 'Uniform'), parameters('overprovision'), null())]", + "doNotRunExtensionsOnOverprovisionedVMs": "[if(equals(parameters('orchestrationMode'), 'Uniform'), parameters('doNotRunExtensionsOnOverprovisionedVMs'), null())]", + "zoneBalance": "[if(equals(parameters('zoneBalance'), 'true'), parameters('zoneBalance'), null())]", + "platformFaultDomainCount": "[parameters('scaleSetFaultDomain')]", + "singlePlacementGroup": "[parameters('singlePlacementGroup')]", + "additionalCapabilities": { + "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]" + }, + "scaleInPolicy": "[parameters('scaleInPolicy')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacity": "[parameters('skuCapacity')]" + }, + "plan": "[if(not(empty(parameters('plan'))), parameters('plan'), null())]" + }, + "vmss_logAnalyticsWorkspace": { + "condition": "[not(empty(parameters('monitoringWorkspaceResourceId')))]", + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2021-06-01", + "subscriptionId": "[split(if(not(empty(parameters('monitoringWorkspaceResourceId'))), parameters('monitoringWorkspaceResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(if(not(empty(parameters('monitoringWorkspaceResourceId'))), parameters('monitoringWorkspaceResourceId'), '////'), '/')[4]]", + "name": "[last(split(if(not(empty(parameters('monitoringWorkspaceResourceId'))), parameters('monitoringWorkspaceResourceId'), 'law'), '/'))]" + }, + "vmss_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Compute/virtualMachineScaleSets/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "vmss" + ] + }, + "vmss_diagnosticSettings": { + "copy": { + "name": "vmss_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Compute/virtualMachineScaleSets/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "vmss" + ] + }, + "vmss_roleAssignments": { + "copy": { + "name": "vmss_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/virtualMachineScaleSets/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/virtualMachineScaleSets', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "vmss" + ] + }, + "vmss_domainJoinExtension": { + "condition": "[parameters('extensionDomainJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VMSS-DomainJoin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineScaleSetName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DomainJoin" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "JsonADDomainExtension" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[parameters('extensionDomainJoinConfig').settings]" + }, + "protectedSettings": { + "value": { + "Password": "[parameters('extensionDomainJoinPassword')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "1450719033279262836" + }, + "name": "Virtual Machine Scale Set Extensions", + "description": "This module deploys a Virtual Machine Scale Set Extension." + }, + "parameters": { + "virtualMachineScaleSetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine scale set that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine scale set extension." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The ResourceId of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachineScaleSets/extensions', parameters('virtualMachineScaleSetName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "vmss" + ] + }, + "vmss_microsoftAntiMalwareExtension": { + "condition": "[parameters('extensionAntiMalwareConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VMSS-MicrosoftAntiMalware', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineScaleSetName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "MicrosoftAntiMalware" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": { + "value": "IaaSAntimalware" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[parameters('extensionAntiMalwareConfig').settings]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "1450719033279262836" + }, + "name": "Virtual Machine Scale Set Extensions", + "description": "This module deploys a Virtual Machine Scale Set Extension." + }, + "parameters": { + "virtualMachineScaleSetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine scale set that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine scale set extension." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The ResourceId of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachineScaleSets/extensions', parameters('virtualMachineScaleSetName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "vmss", + "vmss_domainJoinExtension" + ] + }, + "vmss_azureMonitorAgentExtension": { + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VMSS-AzureMonitorAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineScaleSetName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "AzureMonitorAgent" + }, + "publisher": { + "value": "Microsoft.Azure.Monitor" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureMonitorWindowsAgent'), createObject('value', 'AzureMonitorLinuxAgent'))]", + "typeHandlerVersion": "[if(not(equals(tryGet(parameters('extensionMonitoringAgentConfig'), 'typeHandlerVersion'), null())), createObject('value', parameters('extensionMonitoringAgentConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '1.22'), createObject('value', '1.29')))]", + "autoUpgradeMinorVersion": { + "value": "[coalesce(parameters('extensionMonitoringAgentConfig').autoUpgradeMinorVersion, true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": { + "workspaceId": "[if(not(empty(parameters('monitoringWorkspaceResourceId'))), reference('vmss_logAnalyticsWorkspace').customerId, '')]", + "GCS_AUTO_CONFIG": "[if(equals(parameters('osType'), 'Linux'), true(), null())]" + } + }, + "protectedSettings": { + "value": { + "workspaceKey": "[if(not(empty(parameters('monitoringWorkspaceResourceId'))), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(if(not(empty(parameters('monitoringWorkspaceResourceId'))), parameters('monitoringWorkspaceResourceId'), '//'), '/')[2], split(if(not(empty(parameters('monitoringWorkspaceResourceId'))), parameters('monitoringWorkspaceResourceId'), '////'), '/')[4]), 'Microsoft.OperationalInsights/workspaces', last(split(if(not(empty(parameters('monitoringWorkspaceResourceId'))), parameters('monitoringWorkspaceResourceId'), 'law'), '/'))), '2021-06-01').primarySharedKey, '')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "1450719033279262836" + }, + "name": "Virtual Machine Scale Set Extensions", + "description": "This module deploys a Virtual Machine Scale Set Extension." + }, + "parameters": { + "virtualMachineScaleSetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine scale set that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine scale set extension." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The ResourceId of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachineScaleSets/extensions', parameters('virtualMachineScaleSetName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "vmss", + "vmss_logAnalyticsWorkspace", + "vmss_microsoftAntiMalwareExtension" + ] + }, + "vmss_dependencyAgentExtension": { + "condition": "[parameters('extensionDependencyAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VMSS-DependencyAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineScaleSetName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DependencyAgent" + }, + "publisher": { + "value": "Microsoft.Azure.Monitoring.DependencyAgent" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.5')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "1450719033279262836" + }, + "name": "Virtual Machine Scale Set Extensions", + "description": "This module deploys a Virtual Machine Scale Set Extension." + }, + "parameters": { + "virtualMachineScaleSetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine scale set that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine scale set extension." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The ResourceId of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachineScaleSets/extensions', parameters('virtualMachineScaleSetName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "vmss", + "vmss_azureMonitorAgentExtension" + ] + }, + "vmss_networkWatcherAgentExtension": { + "condition": "[parameters('extensionNetworkWatcherAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VMSS-NetworkWatcherAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineScaleSetName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "NetworkWatcherAgent" + }, + "publisher": { + "value": "Microsoft.Azure.NetworkWatcher" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "1450719033279262836" + }, + "name": "Virtual Machine Scale Set Extensions", + "description": "This module deploys a Virtual Machine Scale Set Extension." + }, + "parameters": { + "virtualMachineScaleSetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine scale set that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine scale set extension." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The ResourceId of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachineScaleSets/extensions', parameters('virtualMachineScaleSetName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "vmss", + "vmss_dependencyAgentExtension" + ] + }, + "vmss_desiredStateConfigurationExtension": { + "condition": "[parameters('extensionDSCConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VMSS-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineScaleSetName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DesiredStateConfiguration" + }, + "publisher": { + "value": "Microsoft.Powershell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" + }, + "protectedSettings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "1450719033279262836" + }, + "name": "Virtual Machine Scale Set Extensions", + "description": "This module deploys a Virtual Machine Scale Set Extension." + }, + "parameters": { + "virtualMachineScaleSetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine scale set that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine scale set extension." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The ResourceId of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachineScaleSets/extensions', parameters('virtualMachineScaleSetName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "vmss", + "vmss_networkWatcherAgentExtension" + ] + }, + "vmss_customScriptExtension": { + "condition": "[parameters('extensionCustomScriptConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VMSS-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineScaleSetName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "CustomScriptExtension" + }, + "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": { + "copy": [ + { + "name": "fileUris", + "count": "[length(parameters('extensionCustomScriptConfig').fileData)]", + "input": "[if(contains(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')], 'storageAccountId'), format('{0}?{1}', parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri, listAccountSas(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].storageAccountId, '2019-04-01', variables('accountSasProperties')).accountSasToken), parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri)]" + } + ] + } + }, + "protectedSettings": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'protectedSettings'), createObject())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "1450719033279262836" + }, + "name": "Virtual Machine Scale Set Extensions", + "description": "This module deploys a Virtual Machine Scale Set Extension." + }, + "parameters": { + "virtualMachineScaleSetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine scale set that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine scale set extension." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The ResourceId of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachineScaleSets/extensions', parameters('virtualMachineScaleSetName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "vmss", + "vmss_desiredStateConfigurationExtension" + ] + }, + "vmss_azureDiskEncryptionExtension": { + "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VMSS-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineScaleSetName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "AzureDiskEncryption" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[parameters('extensionAzureDiskEncryptionConfig').settings]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "1450719033279262836" + }, + "name": "Virtual Machine Scale Set Extensions", + "description": "This module deploys a Virtual Machine Scale Set Extension." + }, + "parameters": { + "virtualMachineScaleSetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine scale set that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine scale set extension." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachineScaleSets/extensions", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('virtualMachineScaleSetName'), parameters('name'))]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The ResourceId of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachineScaleSets/extensions', parameters('virtualMachineScaleSetName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "vmss", + "vmss_customScriptExtension" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual machine scale set." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachineScaleSets', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the virtual machine scale set." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual machine scale set." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('vmss', '2024-07-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vmss', '2024-07-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.defaults/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.defaults/dependencies.bicep new file mode 100644 index 000000000..2746c5a99 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.defaults/dependencies.bicep @@ -0,0 +1,89 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Deployment Script to create for the SSH Key generation.') +param sshDeploymentScriptName string + +@description('Required. The name of the SSH Key to create.') +param sshKeyName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource msiRGContrRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalType: 'ServicePrincipal' + } +} + +resource sshDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: sshDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.0' + retentionInterval: 'P1D' + arguments: '-SSHKeyName "${sshKeyName}" -ResourceGroupName "${resourceGroup().name}"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/New-SSHKey.ps1') + } + dependsOn: [ + msiRGContrRoleAssignment + ] +} + +resource sshKey 'Microsoft.Compute/sshPublicKeys@2022-03-01' = { + name: sshKeyName + location: location + properties: { + publicKey: sshDeploymentScript.properties.outputs.publicKey + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The Public Key of the created SSH Key.') +output SSHKeyPublicKey string = sshKey.properties.publicKey diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.defaults/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.defaults/main.test.bicep new file mode 100644 index 000000000..780da5e66 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.defaults/main.test.bicep @@ -0,0 +1,106 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults for Linux' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualmachinescalesets-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmsslinmin' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + sshDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}' + sshKeyName: 'dep-${namePrefix}-ssh-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + adminUsername: 'scaleSetAdmin' + adminPassword: password + imageReference: { + publisher: 'Canonical' + offer: '0001-com-ubuntu-server-jammy' + sku: '22_04-lts-gen2' + version: 'latest' + } + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Linux' + skuName: 'Standard_B12ms' + disablePasswordAuthentication: true + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: nestedDependencies.outputs.subnetResourceId + } + publicIPAddressConfiguration: { + name: '${namePrefix}-pip-${serviceShort}' + } + } + } + ] + nicSuffix: '-nic01' + } + ] + publicKeys: [ + { + keyData: nestedDependencies.outputs.SSHKeyPublicKey + path: '/home/scaleSetAdmin/.ssh/authorized_keys' + } + ] + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.max/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.max/dependencies.bicep new file mode 100644 index 000000000..845329720 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.max/dependencies.bicep @@ -0,0 +1,199 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Deployment Script used to upload data to the Storage Account.') +param storageUploadDeploymentScriptName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Deployment Script to create for the SSH Key generation.') +param sshDeploymentScriptName string + +@description('Required. The name of the SSH Key to create.') +param sshKeyName string + +var storageAccountCSEFileName = 'scriptExtensionMasterInstaller.ps1' +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'encryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource msiRGContrRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalType: 'ServicePrincipal' + } +} + +resource msiKVCryptoUserRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(keyVault::key.id, 'Key Vault Crypto User', managedIdentity.id) + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + + resource blobService 'blobServices@2021-09-01' = { + name: 'default' + + resource container 'containers@2021-09-01' = { + name: 'scripts' + } + } +} + +resource storageUpload 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: storageUploadDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.0' + retentionInterval: 'P1D' + arguments: '-StorageAccountName "${storageAccount.name}" -ResourceGroupName "${resourceGroup().name}" -ContainerName "${storageAccount::blobService::container.name}" -FileName "${storageAccountCSEFileName}"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Set-BlobContent.ps1') + } + dependsOn: [ + msiRGContrRoleAssignment + ] +} + +resource sshDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: sshDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.0' + retentionInterval: 'P1D' + arguments: '-SSHKeyName "${sshKeyName}" -ResourceGroupName "${resourceGroup().name}"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/New-SSHKey.ps1') + } + dependsOn: [ + msiRGContrRoleAssignment + ] +} + +resource sshKey 'Microsoft.Compute/sshPublicKeys@2022-03-01' = { + name: sshKeyName + location: location + properties: { + publicKey: sshDeploymentScript.properties.outputs.publicKey + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The URL of the created Key Vault.') +output keyVaultUrl string = keyVault.properties.vaultUri + +@description('The URL of the created Key Vault Encryption Key.') +output keyVaultEncryptionKeyUrl string = keyVault::key.properties.keyUriWithVersion + +@description('The name of the created Storage Account.') +output storageAccountName string = storageAccount.name + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id + +@description('The URL of the Custom Script Extension in the created Storage Account') +output storageAccountCSEFileUrl string = '${storageAccount.properties.primaryEndpoints.blob}${storageAccount::blobService::container.name}/${storageAccountCSEFileName}' + +@description('The Public Key of the created SSH Key.') +output SSHKeyPublicKey string = sshKey.properties.publicKey diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.max/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.max/main.test.bicep new file mode 100644 index 000000000..595774a15 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.max/main.test.bicep @@ -0,0 +1,238 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set for Linux' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualmachinescalesets-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmsslinmax' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + storageAccountName: take('dep${namePrefix}sa${serviceShort}01', 24) + storageUploadDeploymentScriptName: 'dep-${namePrefix}-sads-${serviceShort}' + sshDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}' + sshKeyName: 'dep-${namePrefix}-ssh-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: take('dep${namePrefix}diasa${serviceShort}01', 24) + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + adminUsername: 'scaleSetAdmin' + adminPassword: password + imageReference: { + publisher: 'Canonical' + offer: '0001-com-ubuntu-server-jammy' + sku: '22_04-lts-gen2' + version: 'latest' + } + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Linux' + skuName: 'Standard_B12ms' + availabilityZones: [ + '2' + ] + bootDiagnosticEnabled: true + bootDiagnosticStorageAccountName: nestedDependencies.outputs.storageAccountName + dataDisks: [ + { + caching: 'ReadOnly' + createOption: 'Empty' + diskSizeGB: '256' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + { + caching: 'ReadOnly' + createOption: 'Empty' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + disablePasswordAuthentication: true + encryptionAtHost: false + extensionCustomScriptConfig: { + enabled: true + fileData: [ + { + storageAccountId: nestedDependencies.outputs.storageAccountResourceId + uri: nestedDependencies.outputs.storageAccountCSEFileUrl + } + ] + protectedSettings: { + commandToExecute: 'sudo apt-get update' + } + } + extensionDependencyAgentConfig: { + enabled: true + } + extensionAzureDiskEncryptionConfig: { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: nestedDependencies.outputs.keyVaultEncryptionKeyUrl + KeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + KeyVaultURL: nestedDependencies.outputs.keyVaultUrl + ResizeOSDisk: 'false' + VolumeType: 'All' + } + } + extensionMonitoringAgentConfig: { + enabled: true + autoUpgradeMinorVersion: true + } + extensionNetworkWatcherAgentConfig: { + enabled: true + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: nestedDependencies.outputs.subnetResourceId + } + publicIPAddressConfiguration: { + name: '${namePrefix}-pip-${serviceShort}' + } + } + } + ] + nicSuffix: '-nic01' + } + ] + publicKeys: [ + { + keyData: nestedDependencies.outputs.SSHKeyPublicKey + path: '/home/scaleSetAdmin/.ssh/authorized_keys' + } + ] + roleAssignments: [ + { + name: '8abf72f9-e918-4adc-b20b-c783b8799065' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + scaleSetFaultDomain: 1 + skuCapacity: 1 + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + upgradePolicyMode: 'Manual' + vmNamePrefix: 'vmsslinvm' + vmPriority: 'Regular' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/dependencies.bicep new file mode 100644 index 000000000..dec16728f --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/dependencies.bicep @@ -0,0 +1,154 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Disk Encryption Set to create.') +param diskEncryptionSetName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Deployment Script to create for the SSH Key generation.') +param sshDeploymentScriptName string + +@description('Required. The name of the SSH Key to create.') +param sshKeyName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource diskEncryptionSet 'Microsoft.Compute/diskEncryptionSets@2021-04-01' = { + name: diskEncryptionSetName + location: location + identity: { + type: 'SystemAssigned' + } + properties: { + activeKey: { + sourceVault: { + id: keyVault.id + } + keyUrl: keyVault::key.properties.keyUriWithVersion + } + encryptionType: 'EncryptionAtRestWithPlatformAndCustomerKeys' + } +} + +resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(keyVault::key.id, 'Key Vault Crypto User', diskEncryptionSet.id) + scope: keyVault + properties: { + principalId: diskEncryptionSet.identity.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'e147488a-f6f5-4113-8e2d-b22465e65bf6' + ) // Key Vault Crypto Service Encryption User + principalType: 'ServicePrincipal' + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource msiRGContrRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalType: 'ServicePrincipal' + } +} + +resource sshDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: sshDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.0' + retentionInterval: 'P1D' + arguments: '-SSHKeyName "${sshKeyName}" -ResourceGroupName "${resourceGroup().name}"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/New-SSHKey.ps1') + } + dependsOn: [ + msiRGContrRoleAssignment + ] +} + +resource sshKey 'Microsoft.Compute/sshPublicKeys@2022-03-01' = { + name: sshKeyName + location: location + properties: { + publicKey: sshDeploymentScript.properties.outputs.publicKey + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Disk Encryption Set.') +output diskEncryptionSetResourceId string = diskEncryptionSet.id + +@description('The Public Key of the created SSH Key.') +output SSHKeyPublicKey string = sshKey.properties.publicKey diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/main.test.bicep new file mode 100644 index 000000000..451b30d41 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/linux.ssecmk/main.test.bicep @@ -0,0 +1,131 @@ +targetScope = 'subscription' + +metadata name = 'Using disk encryption set for the VM.' +metadata description = 'This instance deploys the module with disk enryption set.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualmachinescalesets-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmsslcmk' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep${namePrefix}kv${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + diskEncryptionSetName: 'dep-${namePrefix}-des-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + sshDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}' + sshKeyName: 'dep-${namePrefix}-ssh-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + extensionMonitoringAgentConfig: { + enabled: true + autoUpgradeMinorVersion: true + } + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + adminUsername: 'scaleSetAdmin' + adminPassword: password + imageReference: { + publisher: 'Canonical' + offer: '0001-com-ubuntu-server-jammy' + sku: '22_04-lts-gen2' + version: 'latest' + } + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: nestedDependencies.outputs.subnetResourceId + } + publicIPAddressConfiguration: { + name: '${namePrefix}-pip-${serviceShort}' + } + } + } + ] + nicSuffix: '-nic01' + } + ] + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + diskEncryptionSet: { + id: nestedDependencies.outputs.diskEncryptionSetResourceId + } + } + } + dataDisks: [ + { + caching: 'ReadOnly' + createOption: 'Empty' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + diskEncryptionSet: { + id: nestedDependencies.outputs.diskEncryptionSetResourceId + } + } + } + ] + osType: 'Linux' + skuName: 'Standard_B12ms' + disablePasswordAuthentication: true + publicKeys: [ + { + keyData: nestedDependencies.outputs.SSHKeyPublicKey + path: '/home/scaleSetAdmin/.ssh/authorized_keys' + } + ] + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.defaults/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.defaults/dependencies.bicep new file mode 100644 index 000000000..1166415e5 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.defaults/dependencies.bicep @@ -0,0 +1,30 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.defaults/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.defaults/main.test.bicep new file mode 100644 index 000000000..7ece80db0 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.defaults/main.test.bicep @@ -0,0 +1,96 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults for Windows' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualmachinescalesets-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmsswinmin' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + adminUsername: 'localAdminUser' + adminPassword: password + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + skuName: 'Standard_B12ms' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: nestedDependencies.outputs.subnetResourceId + } + publicIPAddressConfiguration: { + name: '${namePrefix}-pip-${serviceShort}' + } + } + } + ] + nicSuffix: '-nic01' + } + ] + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/dependencies.bicep new file mode 100644 index 000000000..f67798fc2 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/dependencies.bicep @@ -0,0 +1,161 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Deployment Script used to upload data to the Storage Account.') +param storageUploadDeploymentScriptName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var storageAccountCSEFileName = 'scriptExtensionMasterInstaller.ps1' +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'encryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource msiRGContrRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalType: 'ServicePrincipal' + } +} + +resource msiKVCryptoUserRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(keyVault::key.id, 'Key Vault Crypto User', managedIdentity.id) + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + + resource blobService 'blobServices@2021-09-01' = { + name: 'default' + + resource container 'containers@2021-09-01' = { + name: 'scripts' + } + } +} + +resource storageUpload 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: storageUploadDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.0' + retentionInterval: 'P1D' + arguments: '-StorageAccountName "${storageAccount.name}" -ResourceGroupName "${resourceGroup().name}" -ContainerName "${storageAccount::blobService::container.name}" -FileName "${storageAccountCSEFileName}"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Set-BlobContent.ps1') + } + dependsOn: [ + msiRGContrRoleAssignment + ] +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The URL of the created Key Vault.') +output keyVaultUrl string = keyVault.properties.vaultUri + +@description('The URL of the created Key Vault Encryption Key.') +output keyVaultEncryptionKeyUrl string = keyVault::key.properties.keyUriWithVersion + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id + +@description('The URL of the Custom Script Extension in the created Storage Account') +output storageAccountCSEFileUrl string = '${storageAccount.properties.primaryEndpoints.blob}${storageAccount::blobService::container.name}/${storageAccountCSEFileName}' + +@description('The name of the Custom Script Extension in the created Storage Account.') +output storageAccountCSEFileName string = storageAccountCSEFileName diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/main.test.bicep new file mode 100644 index 000000000..cd0342624 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.max/main.test.bicep @@ -0,0 +1,234 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set for Windows' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualmachinescalesets-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmsswinmax' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + storageAccountName: take('dep${namePrefix}sa${serviceShort}01', 24) + storageUploadDeploymentScriptName: 'dep-${namePrefix}-sads-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: take('dep${namePrefix}diasa${serviceShort}01', 24) + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + adminUsername: 'localAdminUser' + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + skuName: 'Standard_B12ms' + adminPassword: password + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + encryptionAtHost: false + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: true + Exclusions: { + Extensions: '.log;.ldf' + Paths: 'D:\\IISlogs;D:\\DatabaseLogs' + Processes: 'mssence.svc' + } + RealtimeProtectionEnabled: true + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + } + extensionCustomScriptConfig: { + enabled: true + fileData: [ + { + storageAccountId: nestedDependencies.outputs.storageAccountResourceId + uri: nestedDependencies.outputs.storageAccountCSEFileUrl + } + ] + protectedSettings: { + commandToExecute: 'powershell -ExecutionPolicy Unrestricted -Command "& ./${nestedDependencies.outputs.storageAccountCSEFileName}"' + } + } + extensionDependencyAgentConfig: { + enabled: true + } + extensionAzureDiskEncryptionConfig: { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: nestedDependencies.outputs.keyVaultEncryptionKeyUrl + KeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + KeyVaultURL: nestedDependencies.outputs.keyVaultUrl + ResizeOSDisk: 'false' + VolumeType: 'All' + } + } + extensionDSCConfig: { + enabled: true + } + extensionMonitoringAgentConfig: { + enabled: true + autoUpgradeMinorVersion: true + } + extensionNetworkWatcherAgentConfig: { + enabled: true + } + extensionHealthConfig: { + enabled: true + settings: { + protocol: 'http' + port: 80 + requestPath: '/' + } + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: nestedDependencies.outputs.subnetResourceId + } + publicIPAddressConfiguration: { + name: '${namePrefix}-pip-${serviceShort}' + } + } + } + ] + nicSuffix: '-nic01' + } + ] + roleAssignments: [ + { + name: '1910de8c-4dab-4189-96bb-2feb68350fb8' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + skuCapacity: 1 + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + upgradePolicyMode: 'Manual' + vmNamePrefix: 'vmsswinvm' + vmPriority: 'Regular' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.waf-aligned/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.waf-aligned/dependencies.bicep new file mode 100644 index 000000000..f67798fc2 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.waf-aligned/dependencies.bicep @@ -0,0 +1,161 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Deployment Script used to upload data to the Storage Account.') +param storageUploadDeploymentScriptName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var storageAccountCSEFileName = 'scriptExtensionMasterInstaller.ps1' +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'encryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource msiRGContrRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalType: 'ServicePrincipal' + } +} + +resource msiKVCryptoUserRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(keyVault::key.id, 'Key Vault Crypto User', managedIdentity.id) + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + + resource blobService 'blobServices@2021-09-01' = { + name: 'default' + + resource container 'containers@2021-09-01' = { + name: 'scripts' + } + } +} + +resource storageUpload 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: storageUploadDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.0' + retentionInterval: 'P1D' + arguments: '-StorageAccountName "${storageAccount.name}" -ResourceGroupName "${resourceGroup().name}" -ContainerName "${storageAccount::blobService::container.name}" -FileName "${storageAccountCSEFileName}"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Set-BlobContent.ps1') + } + dependsOn: [ + msiRGContrRoleAssignment + ] +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The URL of the created Key Vault.') +output keyVaultUrl string = keyVault.properties.vaultUri + +@description('The URL of the created Key Vault Encryption Key.') +output keyVaultEncryptionKeyUrl string = keyVault::key.properties.keyUriWithVersion + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id + +@description('The URL of the Custom Script Extension in the created Storage Account') +output storageAccountCSEFileUrl string = '${storageAccount.properties.primaryEndpoints.blob}${storageAccount::blobService::container.name}/${storageAccountCSEFileName}' + +@description('The name of the Custom Script Extension in the created Storage Account.') +output storageAccountCSEFileName string = storageAccountCSEFileName diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.waf-aligned/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.waf-aligned/main.test.bicep new file mode 100644 index 000000000..ec8882535 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/tests/e2e/windows.waf-aligned/main.test.bicep @@ -0,0 +1,200 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework for Windows.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualmachinescalesets-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmsswinwaf' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + storageAccountName: take('dep${namePrefix}sa${serviceShort}01', 24) + storageUploadDeploymentScriptName: 'dep-${namePrefix}-sads-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: take('dep${namePrefix}diasa${serviceShort}01', 24) + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + adminUsername: 'localAdminUser' + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + osDisk: { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + skuName: 'Standard_B12ms' + adminPassword: password + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + encryptionAtHost: false // Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your virtual machine scale sets. + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: true + Exclusions: { + Extensions: '.log;.ldf' + Paths: 'D:\\IISlogs;D:\\DatabaseLogs' + Processes: 'mssence.svc' + } + RealtimeProtectionEnabled: true + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + } + extensionCustomScriptConfig: { + enabled: true + fileData: [ + { + storageAccountId: nestedDependencies.outputs.storageAccountResourceId + uri: nestedDependencies.outputs.storageAccountCSEFileUrl + } + ] + protectedSettings: { + commandToExecute: 'powershell -ExecutionPolicy Unrestricted -Command "& ./${nestedDependencies.outputs.storageAccountCSEFileName}"' + } + } + extensionDependencyAgentConfig: { + enabled: true + } + extensionAzureDiskEncryptionConfig: { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: nestedDependencies.outputs.keyVaultEncryptionKeyUrl + KeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + KeyVaultURL: nestedDependencies.outputs.keyVaultUrl + ResizeOSDisk: 'false' + VolumeType: 'All' + } + } + extensionDSCConfig: { + enabled: true + } + extensionMonitoringAgentConfig: { + enabled: true + autoUpgradeMinorVersion: true + } + extensionNetworkWatcherAgentConfig: { + enabled: true + } + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: nestedDependencies.outputs.subnetResourceId + } + publicIPAddressConfiguration: { + name: '${namePrefix}-pip-${serviceShort}' + } + } + } + ] + nicSuffix: '-nic01' + } + ] + skuCapacity: 1 + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + upgradePolicyMode: 'Manual' + vmNamePrefix: 'vmsswinvm' + vmPriority: 'Regular' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine-scale-set/version.json b/avm/1.1.0/res/compute/virtual-machine-scale-set/version.json new file mode 100644 index 000000000..e42c3d9e5 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine-scale-set/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.6", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/virtual-machine/README.md b/avm/1.1.0/res/compute/virtual-machine/README.md new file mode 100644 index 000000000..614223721 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/README.md @@ -0,0 +1,6745 @@ +# Virtual Machines `[Microsoft.Compute/virtualMachines]` + +This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Automanage/configurationProfileAssignments` | [2022-05-04](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Automanage/2022-05-04/configurationProfileAssignments) | +| `Microsoft.Compute/disks` | [2024-03-02](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-03-02/disks) | +| `Microsoft.Compute/virtualMachines` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-07-01/virtualMachines) | +| `Microsoft.Compute/virtualMachines/extensions` | [2022-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-11-01/virtualMachines/extensions) | +| `Microsoft.DevTestLab/schedules` | [2018-09-15](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DevTestLab/2018-09-15/schedules) | +| `Microsoft.GuestConfiguration/guestConfigurationAssignments` | [2020-06-25](https://learn.microsoft.com/en-us/azure/templates/Microsoft.GuestConfiguration/2020-06-25/guestConfigurationAssignments) | +| `Microsoft.Insights/dataCollectionRuleAssociations` | [2023-03-11](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2023-03-11/dataCollectionRuleAssociations) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Maintenance/configurationAssignments` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Maintenance/2023-04-01/configurationAssignments) | +| `Microsoft.Network/networkInterfaces` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkInterfaces) | +| `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | +| `Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.RecoveryServices/2023-01-01/vaults/backupFabrics/protectionContainers/protectedItems) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/compute/virtual-machine:`. + +- [Using automanage for the VM.](#example-1-using-automanage-for-the-vm) +- [Using only defaults for Linux](#example-2-using-only-defaults-for-linux) +- [Using large parameter set for Linux](#example-3-using-large-parameter-set-for-linux) +- [WAF-aligned](#example-4-waf-aligned) +- [Using only defaults for Windows](#example-5-using-only-defaults-for-windows) +- [Using guest configuration for Windows](#example-6-using-guest-configuration-for-windows) +- [Using a host pool to register the VM](#example-7-using-a-host-pool-to-register-the-vm) +- [Using large parameter set for Windows](#example-8-using-large-parameter-set-for-windows) +- [Deploy a VM with nVidia graphic card](#example-9-deploy-a-vm-with-nvidia-graphic-card) +- [Deploying Windows VM with premium SSDv2 data disk](#example-10-deploying-windows-vm-with-premium-ssdv2-data-disk) +- [Using disk encryption set for the VM.](#example-11-using-disk-encryption-set-for-the-vm) +- [Adding the VM to a VMSS.](#example-12-adding-the-vm-to-a-vmss) + +### Example 1: _Using automanage for the VM._ + +This instance deploys the module with registering to an automation account. + + +

+ +via Bicep module + +```bicep +module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { + name: 'virtualMachineDeployment' + params: { + // Required parameters + adminUsername: 'localAdminUser' + imageReference: { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' + } + name: 'cvmlinatmg' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [ + 1 + 2 + 3 + ] + } + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Linux' + vmSize: 'Standard_D2s_v3' + zone: 0 + // Non-required parameters + configurationProfile: '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction' + disablePasswordAuthentication: true + location: '' + publicKeys: [ + { + keyData: '' + path: '/home/localAdminUser/.ssh/authorized_keys' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminUsername": { + "value": "localAdminUser" + }, + "imageReference": { + "value": { + "offer": "0001-com-ubuntu-server-jammy", + "publisher": "Canonical", + "sku": "22_04-lts-gen2", + "version": "latest" + } + }, + "name": { + "value": "cvmlinatmg" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig01", + "pipConfiguration": { + "publicIpNameSuffix": "-pip-01", + "zones": [ + 1, + 2, + 3 + ] + }, + "subnetResourceId": "" + } + ], + "nicSuffix": "-nic-01" + } + ] + }, + "osDisk": { + "value": { + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Linux" + }, + "vmSize": { + "value": "Standard_D2s_v3" + }, + "zone": { + "value": 0 + }, + // Non-required parameters + "configurationProfile": { + "value": "/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction" + }, + "disablePasswordAuthentication": { + "value": true + }, + "location": { + "value": "" + }, + "publicKeys": { + "value": [ + { + "keyData": "", + "path": "/home/localAdminUser/.ssh/authorized_keys" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' +} +param name = 'cvmlinatmg' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [ + 1 + 2 + 3 + ] + } + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Linux' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param configurationProfile = '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction' +param disablePasswordAuthentication = true +param location = '' +param publicKeys = [ + { + keyData: '' + path: '/home/localAdminUser/.ssh/authorized_keys' + } +] +``` + +
+

+ +### Example 2: _Using only defaults for Linux_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { + name: 'virtualMachineDeployment' + params: { + // Required parameters + adminUsername: 'localAdminUser' + imageReference: { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' + } + name: 'cvmlinmin' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + pipConfiguration: { + name: 'pip-01' + } + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Linux' + vmSize: 'Standard_D2s_v3' + zone: 0 + // Non-required parameters + disablePasswordAuthentication: true + location: '' + publicKeys: [ + { + keyData: '' + path: '/home/localAdminUser/.ssh/authorized_keys' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminUsername": { + "value": "localAdminUser" + }, + "imageReference": { + "value": { + "offer": "0001-com-ubuntu-server-jammy", + "publisher": "Canonical", + "sku": "22_04-lts-gen2", + "version": "latest" + } + }, + "name": { + "value": "cvmlinmin" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig01", + "pipConfiguration": { + "name": "pip-01" + }, + "subnetResourceId": "" + } + ], + "nicSuffix": "-nic-01" + } + ] + }, + "osDisk": { + "value": { + "caching": "ReadWrite", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Linux" + }, + "vmSize": { + "value": "Standard_D2s_v3" + }, + "zone": { + "value": 0 + }, + // Non-required parameters + "disablePasswordAuthentication": { + "value": true + }, + "location": { + "value": "" + }, + "publicKeys": { + "value": [ + { + "keyData": "", + "path": "/home/localAdminUser/.ssh/authorized_keys" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' +} +param name = 'cvmlinmin' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + pipConfiguration: { + name: 'pip-01' + } + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Linux' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param disablePasswordAuthentication = true +param location = '' +param publicKeys = [ + { + keyData: '' + path: '/home/localAdminUser/.ssh/authorized_keys' + } +] +``` + +
+

+ +### Example 3: _Using large parameter set for Linux_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { + name: 'virtualMachineDeployment' + params: { + // Required parameters + adminUsername: 'localAdministrator' + imageReference: { + offer: '0001-com-ubuntu-server-focal' + publisher: 'Canonical' + sku: '' + version: 'latest' + } + name: 'cvmlinmax' + nicConfigurations: [ + { + deleteOption: 'Delete' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + roleAssignments: [ + { + name: '696e6067-3ddc-4b71-bf97-9caebeba441a' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + zones: [ + 1 + 2 + 3 + ] + } + subnetResourceId: '' + } + ] + name: 'nic-test-01' + roleAssignments: [ + { + name: 'ff72f58d-a3cf-42fd-9c27-c61906bdddfe' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + ] + osDisk: { + caching: 'ReadOnly' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'osdisk01' + } + osType: 'Linux' + vmSize: 'Standard_D2s_v3' + zone: 1 + // Non-required parameters + backupPolicyName: '' + backupVaultName: '' + backupVaultResourceGroup: '' + computerName: 'linvm1' + dataDisks: [ + { + caching: 'ReadWrite' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'datadisk01' + } + { + caching: 'ReadWrite' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'datadisk02' + } + ] + disablePasswordAuthentication: true + enableAutomaticUpdates: true + encryptionAtHost: false + extensionAadJoinConfig: { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionAzureDiskEncryptionConfig: { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + VolumeType: 'All' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionCustomScriptConfig: { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionCustomScriptProtectedSetting: { + commandToExecute: '' + } + extensionDependencyAgentConfig: { + enableAMA: true + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionDSCConfig: { + enabled: false + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionMonitoringAgentConfig: { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: '' + name: 'SendMetricsToLAW' + } + ] + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionNetworkWatcherAgentConfig: { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] + } + patchMode: 'AutomaticByPlatform' + publicKeys: [ + { + keyData: '' + path: '/home/localAdministrator/.ssh/authorized_keys' + } + ] + rebootSetting: 'IfRequired' + roleAssignments: [ + { + name: 'eb01de52-d2be-4272-a7b9-13de6c399e27' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminUsername": { + "value": "localAdministrator" + }, + "imageReference": { + "value": { + "offer": "0001-com-ubuntu-server-focal", + "publisher": "Canonical", + "sku": "", + "version": "latest" + } + }, + "name": { + "value": "cvmlinmax" + }, + "nicConfigurations": { + "value": [ + { + "deleteOption": "Delete", + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "ipConfigurations": [ + { + "applicationSecurityGroups": [ + { + "id": "" + } + ], + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "loadBalancerBackendAddressPools": [ + { + "id": "" + } + ], + "name": "ipconfig01", + "pipConfiguration": { + "publicIpNameSuffix": "-pip-01", + "roleAssignments": [ + { + "name": "696e6067-3ddc-4b71-bf97-9caebeba441a", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "zones": [ + 1, + 2, + 3 + ] + }, + "subnetResourceId": "" + } + ], + "name": "nic-test-01", + "roleAssignments": [ + { + "name": "ff72f58d-a3cf-42fd-9c27-c61906bdddfe", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + } + ] + }, + "osDisk": { + "value": { + "caching": "ReadOnly", + "createOption": "FromImage", + "deleteOption": "Delete", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + }, + "name": "osdisk01" + } + }, + "osType": { + "value": "Linux" + }, + "vmSize": { + "value": "Standard_D2s_v3" + }, + "zone": { + "value": 1 + }, + // Non-required parameters + "backupPolicyName": { + "value": "" + }, + "backupVaultName": { + "value": "" + }, + "backupVaultResourceGroup": { + "value": "" + }, + "computerName": { + "value": "linvm1" + }, + "dataDisks": { + "value": [ + { + "caching": "ReadWrite", + "createOption": "Empty", + "deleteOption": "Delete", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + }, + "name": "datadisk01" + }, + { + "caching": "ReadWrite", + "createOption": "Empty", + "deleteOption": "Delete", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + }, + "name": "datadisk02" + } + ] + }, + "disablePasswordAuthentication": { + "value": true + }, + "enableAutomaticUpdates": { + "value": true + }, + "encryptionAtHost": { + "value": false + }, + "extensionAadJoinConfig": { + "value": { + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionAzureDiskEncryptionConfig": { + "value": { + "enabled": true, + "settings": { + "EncryptionOperation": "EnableEncryption", + "KekVaultResourceId": "", + "KeyEncryptionAlgorithm": "RSA-OAEP", + "KeyEncryptionKeyURL": "", + "KeyVaultResourceId": "", + "KeyVaultURL": "", + "ResizeOSDisk": "false", + "VolumeType": "All" + }, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionCustomScriptConfig": { + "value": { + "enabled": true, + "fileData": [ + { + "storageAccountId": "", + "uri": "" + } + ], + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionCustomScriptProtectedSetting": { + "value": { + "commandToExecute": "" + } + }, + "extensionDependencyAgentConfig": { + "value": { + "enableAMA": true, + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionDSCConfig": { + "value": { + "enabled": false, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionMonitoringAgentConfig": { + "value": { + "dataCollectionRuleAssociations": [ + { + "dataCollectionRuleResourceId": "", + "name": "SendMetricsToLAW" + } + ], + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionNetworkWatcherAgentConfig": { + "value": { + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "" + ] + } + }, + "patchMode": { + "value": "AutomaticByPlatform" + }, + "publicKeys": { + "value": [ + { + "keyData": "", + "path": "/home/localAdministrator/.ssh/authorized_keys" + } + ] + }, + "rebootSetting": { + "value": "IfRequired" + }, + "roleAssignments": { + "value": [ + { + "name": "eb01de52-d2be-4272-a7b9-13de6c399e27", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdministrator' +param imageReference = { + offer: '0001-com-ubuntu-server-focal' + publisher: 'Canonical' + sku: '' + version: 'latest' +} +param name = 'cvmlinmax' +param nicConfigurations = [ + { + deleteOption: 'Delete' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + roleAssignments: [ + { + name: '696e6067-3ddc-4b71-bf97-9caebeba441a' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + zones: [ + 1 + 2 + 3 + ] + } + subnetResourceId: '' + } + ] + name: 'nic-test-01' + roleAssignments: [ + { + name: 'ff72f58d-a3cf-42fd-9c27-c61906bdddfe' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } +] +param osDisk = { + caching: 'ReadOnly' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'osdisk01' +} +param osType = 'Linux' +param vmSize = 'Standard_D2s_v3' +param zone = 1 +// Non-required parameters +param backupPolicyName = '' +param backupVaultName = '' +param backupVaultResourceGroup = '' +param computerName = 'linvm1' +param dataDisks = [ + { + caching: 'ReadWrite' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'datadisk01' + } + { + caching: 'ReadWrite' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'datadisk02' + } +] +param disablePasswordAuthentication = true +param enableAutomaticUpdates = true +param encryptionAtHost = false +param extensionAadJoinConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionAzureDiskEncryptionConfig = { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + VolumeType: 'All' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionCustomScriptConfig = { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionCustomScriptProtectedSetting = { + commandToExecute: '' +} +param extensionDependencyAgentConfig = { + enableAMA: true + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionDSCConfig = { + enabled: false + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionMonitoringAgentConfig = { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: '' + name: 'SendMetricsToLAW' + } + ] + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionNetworkWatcherAgentConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param patchMode = 'AutomaticByPlatform' +param publicKeys = [ + { + keyData: '' + path: '/home/localAdministrator/.ssh/authorized_keys' + } +] +param rebootSetting = 'IfRequired' +param roleAssignments = [ + { + name: 'eb01de52-d2be-4272-a7b9-13de6c399e27' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 4: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework for Windows. + + +

+ +via Bicep module + +```bicep +module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { + name: 'virtualMachineDeployment' + params: { + // Required parameters + adminUsername: 'VMAdmin' + imageReference: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2019-datacenter' + version: 'latest' + } + name: 'cvmwinwaf' + nicConfigurations: [ + { + deleteOption: 'Delete' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + zones: [ + 1 + 2 + 3 + ] + } + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + } + ] + osDisk: { + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + zone: 2 + // Non-required parameters + adminPassword: '' + backupPolicyName: '' + backupVaultName: '' + backupVaultResourceGroup: '' + bypassPlatformSafetyChecksOnUserSchedule: true + computerName: 'winvm1' + dataDisks: [ + { + caching: 'ReadOnly' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + { + caching: 'ReadOnly' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + ] + enableAutomaticUpdates: true + encryptionAtHost: false + extensionAadJoinConfig: { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: { + Extensions: '.ext1;.ext2' + Paths: 'c:\\excluded-path-1;c:\\excluded-path-2' + Processes: 'excludedproc1.exe;excludedproc2.exe' + } + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionAzureDiskEncryptionConfig: { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + VolumeType: 'All' + } + } + extensionCustomScriptConfig: { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionCustomScriptProtectedSetting: { + commandToExecute: '' + } + extensionDependencyAgentConfig: { + enableAMA: true + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionDSCConfig: { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionMonitoringAgentConfig: { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: '' + name: 'SendMetricsToLAW' + } + ] + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionNetworkWatcherAgentConfig: { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + maintenanceConfigurationResourceId: '' + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] + } + patchMode: 'AutomaticByPlatform' + proximityPlacementGroupResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminUsername": { + "value": "VMAdmin" + }, + "imageReference": { + "value": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2019-datacenter", + "version": "latest" + } + }, + "name": { + "value": "cvmwinwaf" + }, + "nicConfigurations": { + "value": [ + { + "deleteOption": "Delete", + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "ipConfigurations": [ + { + "applicationSecurityGroups": [ + { + "id": "" + } + ], + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "loadBalancerBackendAddressPools": [ + { + "id": "" + } + ], + "name": "ipconfig01", + "pipConfiguration": { + "publicIpNameSuffix": "-pip-01", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "zones": [ + 1, + 2, + 3 + ] + }, + "subnetResourceId": "" + } + ], + "nicSuffix": "-nic-01", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ] + } + ] + }, + "osDisk": { + "value": { + "caching": "ReadWrite", + "createOption": "FromImage", + "deleteOption": "Delete", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Windows" + }, + "vmSize": { + "value": "Standard_D2s_v3" + }, + "zone": { + "value": 2 + }, + // Non-required parameters + "adminPassword": { + "value": "" + }, + "backupPolicyName": { + "value": "" + }, + "backupVaultName": { + "value": "" + }, + "backupVaultResourceGroup": { + "value": "" + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "value": true + }, + "computerName": { + "value": "winvm1" + }, + "dataDisks": { + "value": [ + { + "caching": "ReadOnly", + "createOption": "Empty", + "deleteOption": "Delete", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + }, + { + "caching": "ReadOnly", + "createOption": "Empty", + "deleteOption": "Delete", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + ] + }, + "enableAutomaticUpdates": { + "value": true + }, + "encryptionAtHost": { + "value": false + }, + "extensionAadJoinConfig": { + "value": { + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionAntiMalwareConfig": { + "value": { + "enabled": true, + "settings": { + "AntimalwareEnabled": "true", + "Exclusions": { + "Extensions": ".ext1;.ext2", + "Paths": "c:\\excluded-path-1;c:\\excluded-path-2", + "Processes": "excludedproc1.exe;excludedproc2.exe" + }, + "RealtimeProtectionEnabled": "true", + "ScheduledScanSettings": { + "day": "7", + "isEnabled": "true", + "scanType": "Quick", + "time": "120" + } + }, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionAzureDiskEncryptionConfig": { + "value": { + "enabled": true, + "settings": { + "EncryptionOperation": "EnableEncryption", + "KekVaultResourceId": "", + "KeyEncryptionAlgorithm": "RSA-OAEP", + "KeyEncryptionKeyURL": "", + "KeyVaultResourceId": "", + "KeyVaultURL": "", + "ResizeOSDisk": "false", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + }, + "VolumeType": "All" + } + } + }, + "extensionCustomScriptConfig": { + "value": { + "enabled": true, + "fileData": [ + { + "storageAccountId": "", + "uri": "" + } + ], + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionCustomScriptProtectedSetting": { + "value": { + "commandToExecute": "" + } + }, + "extensionDependencyAgentConfig": { + "value": { + "enableAMA": true, + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionDSCConfig": { + "value": { + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionMonitoringAgentConfig": { + "value": { + "dataCollectionRuleAssociations": [ + { + "dataCollectionRuleResourceId": "", + "name": "SendMetricsToLAW" + } + ], + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionNetworkWatcherAgentConfig": { + "value": { + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "maintenanceConfigurationResourceId": { + "value": "" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "" + ] + } + }, + "patchMode": { + "value": "AutomaticByPlatform" + }, + "proximityPlacementGroupResourceId": { + "value": "" + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'VMAdmin' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2019-datacenter' + version: 'latest' +} +param name = 'cvmwinwaf' +param nicConfigurations = [ + { + deleteOption: 'Delete' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + zones: [ + 1 + 2 + 3 + ] + } + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + } +] +param osDisk = { + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 2 +// Non-required parameters +param adminPassword = '' +param backupPolicyName = '' +param backupVaultName = '' +param backupVaultResourceGroup = '' +param bypassPlatformSafetyChecksOnUserSchedule = true +param computerName = 'winvm1' +param dataDisks = [ + { + caching: 'ReadOnly' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + { + caching: 'ReadOnly' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } +] +param enableAutomaticUpdates = true +param encryptionAtHost = false +param extensionAadJoinConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionAntiMalwareConfig = { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: { + Extensions: '.ext1;.ext2' + Paths: 'c:\\excluded-path-1;c:\\excluded-path-2' + Processes: 'excludedproc1.exe;excludedproc2.exe' + } + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionAzureDiskEncryptionConfig = { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + VolumeType: 'All' + } +} +param extensionCustomScriptConfig = { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionCustomScriptProtectedSetting = { + commandToExecute: '' +} +param extensionDependencyAgentConfig = { + enableAMA: true + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionDSCConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionMonitoringAgentConfig = { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: '' + name: 'SendMetricsToLAW' + } + ] + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionNetworkWatcherAgentConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param maintenanceConfigurationResourceId = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param patchMode = 'AutomaticByPlatform' +param proximityPlacementGroupResourceId = '' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 5: _Using only defaults for Windows_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { + name: 'virtualMachineDeployment' + params: { + // Required parameters + adminUsername: 'localAdminUser' + imageReference: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + name: 'cvmwinmin' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + zone: 0 + // Non-required parameters + adminPassword: '' + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminUsername": { + "value": "localAdminUser" + }, + "imageReference": { + "value": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition", + "version": "latest" + } + }, + "name": { + "value": "cvmwinmin" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig01", + "subnetResourceId": "" + } + ], + "nicSuffix": "-nic-01" + } + ] + }, + "osDisk": { + "value": { + "caching": "ReadWrite", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Windows" + }, + "vmSize": { + "value": "Standard_D2s_v3" + }, + "zone": { + "value": 0 + }, + // Non-required parameters + "adminPassword": { + "value": "" + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmwinmin' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param location = '' +``` + +
+

+ +### Example 6: _Using guest configuration for Windows_ + +This instance deploys the module with the a guest configuration. + + +

+ +via Bicep module + +```bicep +module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { + name: 'virtualMachineDeployment' + params: { + // Required parameters + adminUsername: 'localAdminUser' + imageReference: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + name: 'cvmwinguest' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [] + } + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + zone: 0 + // Non-required parameters + adminPassword: '' + extensionGuestConfigurationExtension: { + enabled: true + } + guestConfiguration: { + assignmentType: 'ApplyAndMonitor' + configurationParameter: [ + { + name: 'Minimum Password Length;ExpectedValue' + value: '16' + } + { + name: 'Minimum Password Length;RemediateValue' + value: '16' + } + { + name: 'Maximum Password Age;ExpectedValue' + value: '75' + } + { + name: 'Maximum Password Age;RemediateValue' + value: '75' + } + ] + name: 'AzureWindowsBaseline' + version: '1.*' + } + location: '' + managedIdentities: { + systemAssigned: true + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminUsername": { + "value": "localAdminUser" + }, + "imageReference": { + "value": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition", + "version": "latest" + } + }, + "name": { + "value": "cvmwinguest" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig01", + "pipConfiguration": { + "publicIpNameSuffix": "-pip-01", + "zones": [] + }, + "subnetResourceId": "" + } + ], + "nicSuffix": "-nic-01" + } + ] + }, + "osDisk": { + "value": { + "caching": "ReadWrite", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Windows" + }, + "vmSize": { + "value": "Standard_D2s_v3" + }, + "zone": { + "value": 0 + }, + // Non-required parameters + "adminPassword": { + "value": "" + }, + "extensionGuestConfigurationExtension": { + "value": { + "enabled": true + } + }, + "guestConfiguration": { + "value": { + "assignmentType": "ApplyAndMonitor", + "configurationParameter": [ + { + "name": "Minimum Password Length;ExpectedValue", + "value": "16" + }, + { + "name": "Minimum Password Length;RemediateValue", + "value": "16" + }, + { + "name": "Maximum Password Age;ExpectedValue", + "value": "75" + }, + { + "name": "Maximum Password Age;RemediateValue", + "value": "75" + } + ], + "name": "AzureWindowsBaseline", + "version": "1.*" + } + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmwinguest' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [] + } + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param extensionGuestConfigurationExtension = { + enabled: true +} +param guestConfiguration = { + assignmentType: 'ApplyAndMonitor' + configurationParameter: [ + { + name: 'Minimum Password Length;ExpectedValue' + value: '16' + } + { + name: 'Minimum Password Length;RemediateValue' + value: '16' + } + { + name: 'Maximum Password Age;ExpectedValue' + value: '75' + } + { + name: 'Maximum Password Age;RemediateValue' + value: '75' + } + ] + name: 'AzureWindowsBaseline' + version: '1.*' +} +param location = '' +param managedIdentities = { + systemAssigned: true +} +``` + +
+

+ +### Example 7: _Using a host pool to register the VM_ + +This instance deploys the module and registers it in a host pool. + + +

+ +via Bicep module + +```bicep +module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { + name: 'virtualMachineDeployment' + params: { + // Required parameters + adminUsername: 'localAdminUser' + imageReference: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + name: 'cvmwinhp' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + zone: 0 + // Non-required parameters + adminPassword: '' + extensionAadJoinConfig: { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionHostPoolRegistration: { + configurationFunction: 'Configuration.ps1\\AddSessionHost' + enabled: true + hostPoolName: '' + modulesUrl: '' + registrationInfoToken: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + location: '' + managedIdentities: { + systemAssigned: true + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminUsername": { + "value": "localAdminUser" + }, + "imageReference": { + "value": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition", + "version": "latest" + } + }, + "name": { + "value": "cvmwinhp" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig01", + "subnetResourceId": "" + } + ], + "nicSuffix": "-nic-01" + } + ] + }, + "osDisk": { + "value": { + "caching": "ReadWrite", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Windows" + }, + "vmSize": { + "value": "Standard_D2s_v3" + }, + "zone": { + "value": 0 + }, + // Non-required parameters + "adminPassword": { + "value": "" + }, + "extensionAadJoinConfig": { + "value": { + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionHostPoolRegistration": { + "value": { + "configurationFunction": "Configuration.ps1\\AddSessionHost", + "enabled": true, + "hostPoolName": "", + "modulesUrl": "", + "registrationInfoToken": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmwinhp' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param extensionAadJoinConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionHostPoolRegistration = { + configurationFunction: 'Configuration.ps1\\AddSessionHost' + enabled: true + hostPoolName: '' + modulesUrl: '' + registrationInfoToken: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param location = '' +param managedIdentities = { + systemAssigned: true +} +``` + +
+

+ +### Example 8: _Using large parameter set for Windows_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { + name: 'virtualMachineDeployment' + params: { + // Required parameters + adminUsername: 'VMAdmin' + imageReference: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2019-datacenter' + version: 'latest' + } + name: 'cvmwinmax' + nicConfigurations: [ + { + deleteOption: 'Delete' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + enableIPForwarding: true + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + pipConfiguration: { + publicIPAddressResourceId: '' + roleAssignments: [ + { + name: 'e962e7c1-261a-4afd-b5ad-17a640a0b7bc' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + subnetResourceId: '' + } + ] + name: 'nic-test-01' + roleAssignments: [ + { + name: '95fc1cc2-05ed-4f5a-a22c-a6ca852df7e7' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + ] + osDisk: { + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'osdisk01' + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + zone: 2 + // Non-required parameters + adminPassword: '' + autoShutdownConfig: { + dailyRecurrenceTime: '19:00' + notificationEmail: 'test@contoso.com' + notificationLocale: 'en' + notificationStatus: 'Enabled' + notificationTimeInMinutes: 30 + status: 'Enabled' + timeZone: 'UTC' + } + backupPolicyName: '' + backupVaultName: '' + backupVaultResourceGroup: '' + computerName: 'winvm1' + dataDisks: [ + { + caching: 'None' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + lun: 0 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'datadisk01' + } + { + caching: 'None' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + lun: 1 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'datadisk02' + } + ] + enableAutomaticUpdates: true + encryptionAtHost: false + extensionAadJoinConfig: { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: { + Extensions: '.ext1;.ext2' + Paths: 'c:\\excluded-path-1;c:\\excluded-path-2' + Processes: 'excludedproc1.exe;excludedproc2.exe' + } + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionAzureDiskEncryptionConfig: { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + VolumeType: 'All' + } + } + extensionCustomScriptConfig: { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionCustomScriptProtectedSetting: { + commandToExecute: '' + } + extensionDependencyAgentConfig: { + enableAMA: true + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionDSCConfig: { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionMonitoringAgentConfig: { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: '' + name: 'SendMetricsToLAW' + } + ] + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + extensionNetworkWatcherAgentConfig: { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] + } + patchMode: 'AutomaticByPlatform' + proximityPlacementGroupResourceId: '' + rebootSetting: 'IfRequired' + roleAssignments: [ + { + name: 'c70e8c48-6945-4607-9695-1098ba5a86ed' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminUsername": { + "value": "VMAdmin" + }, + "imageReference": { + "value": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2019-datacenter", + "version": "latest" + } + }, + "name": { + "value": "cvmwinmax" + }, + "nicConfigurations": { + "value": [ + { + "deleteOption": "Delete", + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "enableIPForwarding": true, + "ipConfigurations": [ + { + "applicationSecurityGroups": [ + { + "id": "" + } + ], + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "loadBalancerBackendAddressPools": [ + { + "id": "" + } + ], + "name": "ipconfig01", + "pipConfiguration": { + "publicIPAddressResourceId": "", + "roleAssignments": [ + { + "name": "e962e7c1-261a-4afd-b5ad-17a640a0b7bc", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "subnetResourceId": "" + } + ], + "name": "nic-test-01", + "roleAssignments": [ + { + "name": "95fc1cc2-05ed-4f5a-a22c-a6ca852df7e7", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + } + ] + }, + "osDisk": { + "value": { + "caching": "ReadWrite", + "createOption": "FromImage", + "deleteOption": "Delete", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + }, + "name": "osdisk01" + } + }, + "osType": { + "value": "Windows" + }, + "vmSize": { + "value": "Standard_D2s_v3" + }, + "zone": { + "value": 2 + }, + // Non-required parameters + "adminPassword": { + "value": "" + }, + "autoShutdownConfig": { + "value": { + "dailyRecurrenceTime": "19:00", + "notificationEmail": "test@contoso.com", + "notificationLocale": "en", + "notificationStatus": "Enabled", + "notificationTimeInMinutes": 30, + "status": "Enabled", + "timeZone": "UTC" + } + }, + "backupPolicyName": { + "value": "" + }, + "backupVaultName": { + "value": "" + }, + "backupVaultResourceGroup": { + "value": "" + }, + "computerName": { + "value": "winvm1" + }, + "dataDisks": { + "value": [ + { + "caching": "None", + "createOption": "Empty", + "deleteOption": "Delete", + "diskSizeGB": 128, + "lun": 0, + "managedDisk": { + "storageAccountType": "Premium_LRS" + }, + "name": "datadisk01" + }, + { + "caching": "None", + "createOption": "Empty", + "deleteOption": "Delete", + "diskSizeGB": 128, + "lun": 1, + "managedDisk": { + "storageAccountType": "Premium_LRS" + }, + "name": "datadisk02" + } + ] + }, + "enableAutomaticUpdates": { + "value": true + }, + "encryptionAtHost": { + "value": false + }, + "extensionAadJoinConfig": { + "value": { + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionAntiMalwareConfig": { + "value": { + "enabled": true, + "settings": { + "AntimalwareEnabled": "true", + "Exclusions": { + "Extensions": ".ext1;.ext2", + "Paths": "c:\\excluded-path-1;c:\\excluded-path-2", + "Processes": "excludedproc1.exe;excludedproc2.exe" + }, + "RealtimeProtectionEnabled": "true", + "ScheduledScanSettings": { + "day": "7", + "isEnabled": "true", + "scanType": "Quick", + "time": "120" + } + }, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionAzureDiskEncryptionConfig": { + "value": { + "enabled": true, + "settings": { + "EncryptionOperation": "EnableEncryption", + "KekVaultResourceId": "", + "KeyEncryptionAlgorithm": "RSA-OAEP", + "KeyEncryptionKeyURL": "", + "KeyVaultResourceId": "", + "KeyVaultURL": "", + "ResizeOSDisk": "false", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + }, + "VolumeType": "All" + } + } + }, + "extensionCustomScriptConfig": { + "value": { + "enabled": true, + "fileData": [ + { + "storageAccountId": "", + "uri": "" + } + ], + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionCustomScriptProtectedSetting": { + "value": { + "commandToExecute": "" + } + }, + "extensionDependencyAgentConfig": { + "value": { + "enableAMA": true, + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionDSCConfig": { + "value": { + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionMonitoringAgentConfig": { + "value": { + "dataCollectionRuleAssociations": [ + { + "dataCollectionRuleResourceId": "", + "name": "SendMetricsToLAW" + } + ], + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "extensionNetworkWatcherAgentConfig": { + "value": { + "enabled": true, + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "" + ] + } + }, + "patchMode": { + "value": "AutomaticByPlatform" + }, + "proximityPlacementGroupResourceId": { + "value": "" + }, + "rebootSetting": { + "value": "IfRequired" + }, + "roleAssignments": { + "value": [ + { + "name": "c70e8c48-6945-4607-9695-1098ba5a86ed", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'VMAdmin' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2019-datacenter' + version: 'latest' +} +param name = 'cvmwinmax' +param nicConfigurations = [ + { + deleteOption: 'Delete' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + enableIPForwarding: true + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + pipConfiguration: { + publicIPAddressResourceId: '' + roleAssignments: [ + { + name: 'e962e7c1-261a-4afd-b5ad-17a640a0b7bc' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + subnetResourceId: '' + } + ] + name: 'nic-test-01' + roleAssignments: [ + { + name: '95fc1cc2-05ed-4f5a-a22c-a6ca852df7e7' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } +] +param osDisk = { + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'osdisk01' +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 2 +// Non-required parameters +param adminPassword = '' +param autoShutdownConfig = { + dailyRecurrenceTime: '19:00' + notificationEmail: 'test@contoso.com' + notificationLocale: 'en' + notificationStatus: 'Enabled' + notificationTimeInMinutes: 30 + status: 'Enabled' + timeZone: 'UTC' +} +param backupPolicyName = '' +param backupVaultName = '' +param backupVaultResourceGroup = '' +param computerName = 'winvm1' +param dataDisks = [ + { + caching: 'None' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + lun: 0 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'datadisk01' + } + { + caching: 'None' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + lun: 1 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'datadisk02' + } +] +param enableAutomaticUpdates = true +param encryptionAtHost = false +param extensionAadJoinConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionAntiMalwareConfig = { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: { + Extensions: '.ext1;.ext2' + Paths: 'c:\\excluded-path-1;c:\\excluded-path-2' + Processes: 'excludedproc1.exe;excludedproc2.exe' + } + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionAzureDiskEncryptionConfig = { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + VolumeType: 'All' + } +} +param extensionCustomScriptConfig = { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionCustomScriptProtectedSetting = { + commandToExecute: '' +} +param extensionDependencyAgentConfig = { + enableAMA: true + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionDSCConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionMonitoringAgentConfig = { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: '' + name: 'SendMetricsToLAW' + } + ] + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionNetworkWatcherAgentConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param patchMode = 'AutomaticByPlatform' +param proximityPlacementGroupResourceId = '' +param rebootSetting = 'IfRequired' +param roleAssignments = [ + { + name: 'c70e8c48-6945-4607-9695-1098ba5a86ed' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 9: _Deploy a VM with nVidia graphic card_ + +This instance deploys the module for a VM with dedicated nVidia graphic card. + + +

+ +via Bicep module + +```bicep +module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { + name: 'virtualMachineDeployment' + params: { + // Required parameters + adminUsername: 'localAdminUser' + imageReference: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + name: 'cvmwinnv' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_NV6ads_A10_v5' + zone: 0 + // Non-required parameters + adminPassword: '' + extensionNvidiaGpuDriverWindows: { + enabled: true + } + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminUsername": { + "value": "localAdminUser" + }, + "imageReference": { + "value": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition", + "version": "latest" + } + }, + "name": { + "value": "cvmwinnv" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig01", + "subnetResourceId": "" + } + ], + "nicSuffix": "-nic-01" + } + ] + }, + "osDisk": { + "value": { + "caching": "ReadWrite", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Windows" + }, + "vmSize": { + "value": "Standard_NV6ads_A10_v5" + }, + "zone": { + "value": 0 + }, + // Non-required parameters + "adminPassword": { + "value": "" + }, + "extensionNvidiaGpuDriverWindows": { + "value": { + "enabled": true + } + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmwinnv' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_NV6ads_A10_v5' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param extensionNvidiaGpuDriverWindows = { + enabled: true +} +param location = '' +``` + +
+

+ +### Example 10: _Deploying Windows VM with premium SSDv2 data disk_ + +This instance deploys the module with premium SSDv2 data disk. + + +

+ +via Bicep module + +```bicep +module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { + name: 'virtualMachineDeployment' + params: { + // Required parameters + adminUsername: 'localAdminUser' + imageReference: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + name: 'cvmwinssdv2' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + zone: 1 + // Non-required parameters + adminPassword: '' + dataDisks: [ + { + caching: 'None' + diskIOPSReadWrite: 3000 + diskMBpsReadWrite: 125 + diskSizeGB: 1024 + managedDisk: { + storageAccountType: 'PremiumV2_LRS' + } + } + ] + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminUsername": { + "value": "localAdminUser" + }, + "imageReference": { + "value": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition", + "version": "latest" + } + }, + "name": { + "value": "cvmwinssdv2" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig01", + "subnetResourceId": "" + } + ], + "nicSuffix": "-nic-01" + } + ] + }, + "osDisk": { + "value": { + "caching": "ReadWrite", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Windows" + }, + "vmSize": { + "value": "Standard_D2s_v3" + }, + "zone": { + "value": 1 + }, + // Non-required parameters + "adminPassword": { + "value": "" + }, + "dataDisks": { + "value": [ + { + "caching": "None", + "diskIOPSReadWrite": 3000, + "diskMBpsReadWrite": 125, + "diskSizeGB": 1024, + "managedDisk": { + "storageAccountType": "PremiumV2_LRS" + } + } + ] + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmwinssdv2' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 1 +// Non-required parameters +param adminPassword = '' +param dataDisks = [ + { + caching: 'None' + diskIOPSReadWrite: 3000 + diskMBpsReadWrite: 125 + diskSizeGB: 1024 + managedDisk: { + storageAccountType: 'PremiumV2_LRS' + } + } +] +param location = '' +``` + +
+

+ +### Example 11: _Using disk encryption set for the VM._ + +This instance deploys the module with disk enryption set. + + +

+ +via Bicep module + +```bicep +module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { + name: 'virtualMachineDeployment' + params: { + // Required parameters + adminUsername: 'VMAdministrator' + imageReference: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2019-datacenter' + version: 'latest' + } + name: 'cvmwincmk' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + diskSizeGB: 128 + managedDisk: { + diskEncryptionSet: { + id: '' + } + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + zone: 0 + // Non-required parameters + adminPassword: '' + dataDisks: [ + { + diskSizeGB: 128 + managedDisk: { + diskEncryptionSet: { + id: '' + } + storageAccountType: 'Premium_LRS' + } + } + ] + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminUsername": { + "value": "VMAdministrator" + }, + "imageReference": { + "value": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2019-datacenter", + "version": "latest" + } + }, + "name": { + "value": "cvmwincmk" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig01", + "subnetResourceId": "" + } + ], + "nicSuffix": "-nic-01" + } + ] + }, + "osDisk": { + "value": { + "diskSizeGB": 128, + "managedDisk": { + "diskEncryptionSet": { + "id": "" + }, + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Windows" + }, + "vmSize": { + "value": "Standard_D2s_v3" + }, + "zone": { + "value": 0 + }, + // Non-required parameters + "adminPassword": { + "value": "" + }, + "dataDisks": { + "value": [ + { + "diskSizeGB": 128, + "managedDisk": { + "diskEncryptionSet": { + "id": "" + }, + "storageAccountType": "Premium_LRS" + } + } + ] + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'VMAdministrator' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2019-datacenter' + version: 'latest' +} +param name = 'cvmwincmk' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + diskSizeGB: 128 + managedDisk: { + diskEncryptionSet: { + id: '' + } + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param dataDisks = [ + { + diskSizeGB: 128 + managedDisk: { + diskEncryptionSet: { + id: '' + } + storageAccountType: 'Premium_LRS' + } + } +] +param location = '' +``` + +
+

+ +### Example 12: _Adding the VM to a VMSS._ + +This instance deploys the module with the minimum set of required parameters and adds it to a VMSS. + + +

+ +via Bicep module + +```bicep +module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { + name: 'virtualMachineDeployment' + params: { + // Required parameters + adminUsername: 'localAdminUser' + imageReference: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + name: 'cvmwinvmss' + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + zone: 0 + // Non-required parameters + adminPassword: '' + location: '' + virtualMachineScaleSetResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminUsername": { + "value": "localAdminUser" + }, + "imageReference": { + "value": { + "offer": "WindowsServer", + "publisher": "MicrosoftWindowsServer", + "sku": "2022-datacenter-azure-edition", + "version": "latest" + } + }, + "name": { + "value": "cvmwinvmss" + }, + "nicConfigurations": { + "value": [ + { + "ipConfigurations": [ + { + "name": "ipconfig01", + "subnetResourceId": "" + } + ], + "nicSuffix": "-nic-01" + } + ] + }, + "osDisk": { + "value": { + "caching": "ReadWrite", + "diskSizeGB": 128, + "managedDisk": { + "storageAccountType": "Premium_LRS" + } + } + }, + "osType": { + "value": "Windows" + }, + "vmSize": { + "value": "Standard_D2s_v3" + }, + "zone": { + "value": 0 + }, + // Non-required parameters + "adminPassword": { + "value": "" + }, + "location": { + "value": "" + }, + "virtualMachineScaleSetResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmwinvmss' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param location = '' +param virtualMachineScaleSetResourceId = '' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`adminUsername`](#parameter-adminusername) | securestring | Administrator username. | +| [`imageReference`](#parameter-imagereference) | object | OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. | +| [`name`](#parameter-name) | string | The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory. | +| [`nicConfigurations`](#parameter-nicconfigurations) | array | Configures NICs and PIPs. | +| [`osDisk`](#parameter-osdisk) | object | Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs. | +| [`osType`](#parameter-ostype) | string | The chosen OS type. | +| [`vmSize`](#parameter-vmsize) | string | Specifies the size for the VMs. | +| [`zone`](#parameter-zone) | int | If set to 1, 2 or 3, the availability zone for all VMs is hardcoded to that value. If zero, then availability zones is not used. Cannot be used in combination with availability set nor scale set. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`additionalUnattendContent`](#parameter-additionalunattendcontent) | array | Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied. | +| [`adminPassword`](#parameter-adminpassword) | securestring | When specifying a Windows Virtual Machine, this value should be passed. | +| [`allowExtensionOperations`](#parameter-allowextensionoperations) | bool | Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine. | +| [`autoShutdownConfig`](#parameter-autoshutdownconfig) | object | The configuration for auto-shutdown. | +| [`availabilitySetResourceId`](#parameter-availabilitysetresourceid) | string | Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set. | +| [`backupPolicyName`](#parameter-backuppolicyname) | string | Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault. | +| [`backupVaultName`](#parameter-backupvaultname) | string | Recovery service vault name to add VMs to backup. | +| [`backupVaultResourceGroup`](#parameter-backupvaultresourcegroup) | string | Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default. | +| [`bootDiagnostics`](#parameter-bootdiagnostics) | bool | Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled. | +| [`bootDiagnosticStorageAccountName`](#parameter-bootdiagnosticstorageaccountname) | string | Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided. | +| [`bootDiagnosticStorageAccountUri`](#parameter-bootdiagnosticstorageaccounturi) | string | Storage account boot diagnostic base URI. | +| [`bypassPlatformSafetyChecksOnUserSchedule`](#parameter-bypassplatformsafetychecksonuserschedule) | bool | Enables customer to schedule patching without accidental upgrades. | +| [`certificatesToBeInstalled`](#parameter-certificatestobeinstalled) | array | Specifies set of certificates that should be installed onto the virtual machine. | +| [`computerName`](#parameter-computername) | string | Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name. | +| [`configurationProfile`](#parameter-configurationprofile) | string | The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile. | +| [`customData`](#parameter-customdata) | string | Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format. | +| [`dataDisks`](#parameter-datadisks) | array | Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs. | +| [`dedicatedHostId`](#parameter-dedicatedhostid) | string | Specifies resource ID about the dedicated host that the virtual machine resides in. | +| [`disablePasswordAuthentication`](#parameter-disablepasswordauthentication) | bool | Specifies whether password authentication should be disabled. | +| [`enableAutomaticUpdates`](#parameter-enableautomaticupdates) | bool | Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning. | +| [`enableEvictionPolicy`](#parameter-enableevictionpolicy) | bool | Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy. | +| [`enableHotpatching`](#parameter-enablehotpatching) | bool | Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`encryptionAtHost`](#parameter-encryptionathost) | bool | This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs. | +| [`extensionAadJoinConfig`](#parameter-extensionaadjoinconfig) | object | The configuration for the [AAD Join] extension. Must at least contain the ["enabled": true] property to be executed. To enroll in Intune, add the setting mdmId: "0000000a-0000-0000-c000-000000000000". | +| [`extensionAntiMalwareConfig`](#parameter-extensionantimalwareconfig) | object | The configuration for the [Anti Malware] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionAzureDiskEncryptionConfig`](#parameter-extensionazurediskencryptionconfig) | object | The configuration for the [Azure Disk Encryption] extension. Must at least contain the ["enabled": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys. | +| [`extensionCustomScriptConfig`](#parameter-extensioncustomscriptconfig) | object | The configuration for the [Custom Script] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionCustomScriptProtectedSetting`](#parameter-extensioncustomscriptprotectedsetting) | secureObject | An object that contains the extension specific protected settings. | +| [`extensionDependencyAgentConfig`](#parameter-extensiondependencyagentconfig) | object | The configuration for the [Dependency Agent] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionDomainJoinConfig`](#parameter-extensiondomainjoinconfig) | secureObject | The configuration for the [Domain Join] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionDomainJoinPassword`](#parameter-extensiondomainjoinpassword) | securestring | Required if name is specified. Password of the user specified in user parameter. | +| [`extensionDSCConfig`](#parameter-extensiondscconfig) | object | The configuration for the [Desired State Configuration] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionGuestConfigurationExtension`](#parameter-extensionguestconfigurationextension) | object | The configuration for the [Guest Configuration] extension. Must at least contain the ["enabled": true] property to be executed. Needs a managed identy. | +| [`extensionGuestConfigurationExtensionProtectedSettings`](#parameter-extensionguestconfigurationextensionprotectedsettings) | secureObject | An object that contains the extension specific protected settings. | +| [`extensionHostPoolRegistration`](#parameter-extensionhostpoolregistration) | object | The configuration for the [Host Pool Registration] extension. Must at least contain the ["enabled": true] property to be executed. Needs a managed identy. | +| [`extensionMonitoringAgentConfig`](#parameter-extensionmonitoringagentconfig) | object | The configuration for the [Monitoring Agent] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionNetworkWatcherAgentConfig`](#parameter-extensionnetworkwatcheragentconfig) | object | The configuration for the [Network Watcher Agent] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`extensionNvidiaGpuDriverWindows`](#parameter-extensionnvidiagpudriverwindows) | object | The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the ["enabled": true] property to be executed. | +| [`galleryApplications`](#parameter-galleryapplications) | array | Specifies the gallery applications that should be made available to the VM/VMSS. | +| [`guestConfiguration`](#parameter-guestconfiguration) | object | The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled. | +| [`licenseType`](#parameter-licensetype) | string | Specifies that the image or disk that is being used was licensed on-premises. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`maintenanceConfigurationResourceId`](#parameter-maintenanceconfigurationresourceid) | string | The resource Id of a maintenance configuration for this VM. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = "True". | +| [`maxPriceForLowPriorityVm`](#parameter-maxpriceforlowpriorityvm) | string | Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars. | +| [`patchAssessmentMode`](#parameter-patchassessmentmode) | string | VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours. | +| [`patchMode`](#parameter-patchmode) | string | VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'. | +| [`plan`](#parameter-plan) | object | Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use. | +| [`priority`](#parameter-priority) | string | Specifies the priority for the virtual machine. | +| [`provisionVMAgent`](#parameter-provisionvmagent) | bool | Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later. | +| [`proximityPlacementGroupResourceId`](#parameter-proximityplacementgroupresourceid) | string | Resource ID of a proximity placement group. | +| [`publicKeys`](#parameter-publickeys) | array | The list of SSH public keys used to authenticate with linux based VMs. | +| [`rebootSetting`](#parameter-rebootsetting) | string | Specifies the reboot setting for all AutomaticByPlatform patch installation operations. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`sasTokenValidityLength`](#parameter-sastokenvaliditylength) | string | SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours. | +| [`secureBootEnabled`](#parameter-securebootenabled) | bool | Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings. | +| [`securityType`](#parameter-securitytype) | string | Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`timeZone`](#parameter-timezone) | string | Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`. | +| [`ultraSSDEnabled`](#parameter-ultrassdenabled) | bool | The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled. | +| [`userData`](#parameter-userdata) | string | UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here. | +| [`virtualMachineScaleSetResourceId`](#parameter-virtualmachinescalesetresourceid) | string | Resource ID of a virtual machine scale set, where the VM should be added. | +| [`vTpmEnabled`](#parameter-vtpmenabled) | bool | Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings. | +| [`winRM`](#parameter-winrm) | array | Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object. | + +**Generated parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`baseTime`](#parameter-basetime) | string | Do not provide a value! This date value is used to generate a registration token. | + +### Parameter: `adminUsername` + +Administrator username. + +- Required: Yes +- Type: securestring + +### Parameter: `imageReference` + +OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image. + +- Required: Yes +- Type: object + +### Parameter: `name` + +The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory. + +- Required: Yes +- Type: string + +### Parameter: `nicConfigurations` + +Configures NICs and PIPs. + +- Required: Yes +- Type: array + +### Parameter: `osDisk` + +Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`managedDisk`](#parameter-osdiskmanageddisk) | object | The managed disk parameters. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`caching`](#parameter-osdiskcaching) | string | Specifies the caching requirements. | +| [`createOption`](#parameter-osdiskcreateoption) | string | Specifies how the virtual machine should be created. | +| [`deleteOption`](#parameter-osdiskdeleteoption) | string | Specifies whether data disk should be deleted or detached upon VM deletion. | +| [`diskSizeGB`](#parameter-osdiskdisksizegb) | int | Specifies the size of an empty data disk in gigabytes. | +| [`name`](#parameter-osdiskname) | string | The disk name. | + +### Parameter: `osDisk.managedDisk` + +The managed disk parameters. + +- Required: Yes +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`diskEncryptionSetResourceId`](#parameter-osdiskmanageddiskdiskencryptionsetresourceid) | string | Specifies the customer managed disk encryption set resource id for the managed disk. | +| [`storageAccountType`](#parameter-osdiskmanageddiskstorageaccounttype) | string | Specifies the storage account type for the managed disk. | + +### Parameter: `osDisk.managedDisk.diskEncryptionSetResourceId` + +Specifies the customer managed disk encryption set resource id for the managed disk. + +- Required: No +- Type: string + +### Parameter: `osDisk.managedDisk.storageAccountType` + +Specifies the storage account type for the managed disk. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Premium_LRS' + 'Premium_ZRS' + 'PremiumV2_LRS' + 'Standard_LRS' + 'StandardSSD_LRS' + 'StandardSSD_ZRS' + 'UltraSSD_LRS' + ] + ``` + +### Parameter: `osDisk.caching` + +Specifies the caching requirements. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'None' + 'ReadOnly' + 'ReadWrite' + ] + ``` + +### Parameter: `osDisk.createOption` + +Specifies how the virtual machine should be created. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Attach' + 'Empty' + 'FromImage' + ] + ``` + +### Parameter: `osDisk.deleteOption` + +Specifies whether data disk should be deleted or detached upon VM deletion. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Delete' + 'Detach' + ] + ``` + +### Parameter: `osDisk.diskSizeGB` + +Specifies the size of an empty data disk in gigabytes. + +- Required: No +- Type: int + +### Parameter: `osDisk.name` + +The disk name. + +- Required: No +- Type: string + +### Parameter: `osType` + +The chosen OS type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `vmSize` + +Specifies the size for the VMs. + +- Required: Yes +- Type: string + +### Parameter: `zone` + +If set to 1, 2 or 3, the availability zone for all VMs is hardcoded to that value. If zero, then availability zones is not used. Cannot be used in combination with availability set nor scale set. + +- Required: Yes +- Type: int +- Allowed: + ```Bicep + [ + 0 + 1 + 2 + 3 + ] + ``` + +### Parameter: `additionalUnattendContent` + +Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `adminPassword` + +When specifying a Windows Virtual Machine, this value should be passed. + +- Required: No +- Type: securestring +- Default: `''` + +### Parameter: `allowExtensionOperations` + +Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `autoShutdownConfig` + +The configuration for auto-shutdown. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `availabilitySetResourceId` + +Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `backupPolicyName` + +Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault. + +- Required: No +- Type: string +- Default: `'DefaultPolicy'` + +### Parameter: `backupVaultName` + +Recovery service vault name to add VMs to backup. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `backupVaultResourceGroup` + +Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default. + +- Required: No +- Type: string +- Default: `[resourceGroup().name]` + +### Parameter: `bootDiagnostics` + +Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `bootDiagnosticStorageAccountName` + +Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `bootDiagnosticStorageAccountUri` + +Storage account boot diagnostic base URI. + +- Required: No +- Type: string +- Default: `[format('.blob.{0}/', environment().suffixes.storage)]` + +### Parameter: `bypassPlatformSafetyChecksOnUserSchedule` + +Enables customer to schedule patching without accidental upgrades. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `certificatesToBeInstalled` + +Specifies set of certificates that should be installed onto the virtual machine. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `computerName` + +Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name. + +- Required: No +- Type: string +- Default: `[parameters('name')]` + +### Parameter: `configurationProfile` + +The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `customData` + +Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `dataDisks` + +Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`diskSizeGB`](#parameter-datadisksdisksizegb) | int | Specifies the size of an empty data disk in gigabytes. | +| [`managedDisk`](#parameter-datadisksmanageddisk) | object | The managed disk parameters. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`caching`](#parameter-datadiskscaching) | string | Specifies the caching requirements. | +| [`createOption`](#parameter-datadiskscreateoption) | string | Specifies how the virtual machine should be created. | +| [`deleteOption`](#parameter-datadisksdeleteoption) | string | Specifies whether data disk should be deleted or detached upon VM deletion. | +| [`diskIOPSReadWrite`](#parameter-datadisksdiskiopsreadwrite) | int | The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes. | +| [`diskMBpsReadWrite`](#parameter-datadisksdiskmbpsreadwrite) | int | The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10. | +| [`lun`](#parameter-datadiskslun) | int | Specifies the logical unit number of the data disk. | +| [`name`](#parameter-datadisksname) | string | The disk name. | + +### Parameter: `dataDisks.diskSizeGB` + +Specifies the size of an empty data disk in gigabytes. + +- Required: Yes +- Type: int + +### Parameter: `dataDisks.managedDisk` + +The managed disk parameters. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageAccountType`](#parameter-datadisksmanageddiskstorageaccounttype) | string | Specifies the storage account type for the managed disk. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`diskEncryptionSetResourceId`](#parameter-datadisksmanageddiskdiskencryptionsetresourceid) | string | Specifies the customer managed disk encryption set resource id for the managed disk. | +| [`id`](#parameter-datadisksmanageddiskid) | string | Specifies the customer managed disk id for the managed disk. | + +### Parameter: `dataDisks.managedDisk.storageAccountType` + +Specifies the storage account type for the managed disk. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Premium_LRS' + 'Premium_ZRS' + 'PremiumV2_LRS' + 'Standard_LRS' + 'StandardSSD_LRS' + 'StandardSSD_ZRS' + 'UltraSSD_LRS' + ] + ``` + +### Parameter: `dataDisks.managedDisk.diskEncryptionSetResourceId` + +Specifies the customer managed disk encryption set resource id for the managed disk. + +- Required: No +- Type: string + +### Parameter: `dataDisks.managedDisk.id` + +Specifies the customer managed disk id for the managed disk. + +- Required: No +- Type: string + +### Parameter: `dataDisks.caching` + +Specifies the caching requirements. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'None' + 'ReadOnly' + 'ReadWrite' + ] + ``` + +### Parameter: `dataDisks.createOption` + +Specifies how the virtual machine should be created. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Attach' + 'Empty' + 'FromImage' + ] + ``` + +### Parameter: `dataDisks.deleteOption` + +Specifies whether data disk should be deleted or detached upon VM deletion. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Delete' + 'Detach' + ] + ``` + +### Parameter: `dataDisks.diskIOPSReadWrite` + +The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes. + +- Required: No +- Type: int + +### Parameter: `dataDisks.diskMBpsReadWrite` + +The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10. + +- Required: No +- Type: int + +### Parameter: `dataDisks.lun` + +Specifies the logical unit number of the data disk. + +- Required: No +- Type: int + +### Parameter: `dataDisks.name` + +The disk name. + +- Required: No +- Type: string + +### Parameter: `dedicatedHostId` + +Specifies resource ID about the dedicated host that the virtual machine resides in. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `disablePasswordAuthentication` + +Specifies whether password authentication should be disabled. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableAutomaticUpdates` + +Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableEvictionPolicy` + +Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableHotpatching` + +Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `encryptionAtHost` + +This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `extensionAadJoinConfig` + +The configuration for the [AAD Join] extension. Must at least contain the ["enabled": true] property to be executed. To enroll in Intune, add the setting mdmId: "0000000a-0000-0000-c000-000000000000". + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `extensionAntiMalwareConfig` + +The configuration for the [Anti Malware] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: `[if(equals(parameters('osType'), 'Windows'), createObject('enabled', true()), createObject('enabled', false()))]` + +### Parameter: `extensionAzureDiskEncryptionConfig` + +The configuration for the [Azure Disk Encryption] extension. Must at least contain the ["enabled": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `extensionCustomScriptConfig` + +The configuration for the [Custom Script] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + fileData: [] + } + ``` + +### Parameter: `extensionCustomScriptProtectedSetting` + +An object that contains the extension specific protected settings. + +- Required: No +- Type: secureObject +- Default: `{}` + +### Parameter: `extensionDependencyAgentConfig` + +The configuration for the [Dependency Agent] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `extensionDomainJoinConfig` + +The configuration for the [Domain Join] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: secureObject +- Default: `{}` + +### Parameter: `extensionDomainJoinPassword` + +Required if name is specified. Password of the user specified in user parameter. + +- Required: No +- Type: securestring +- Default: `''` + +### Parameter: `extensionDSCConfig` + +The configuration for the [Desired State Configuration] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `extensionGuestConfigurationExtension` + +The configuration for the [Guest Configuration] extension. Must at least contain the ["enabled": true] property to be executed. Needs a managed identy. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `extensionGuestConfigurationExtensionProtectedSettings` + +An object that contains the extension specific protected settings. + +- Required: No +- Type: secureObject +- Default: `{}` + +### Parameter: `extensionHostPoolRegistration` + +The configuration for the [Host Pool Registration] extension. Must at least contain the ["enabled": true] property to be executed. Needs a managed identy. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `extensionMonitoringAgentConfig` + +The configuration for the [Monitoring Agent] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + dataCollectionRuleAssociations: [] + enabled: false + } + ``` + +### Parameter: `extensionNetworkWatcherAgentConfig` + +The configuration for the [Network Watcher Agent] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `extensionNvidiaGpuDriverWindows` + +The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the ["enabled": true] property to be executed. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabled: false + } + ``` + +### Parameter: `galleryApplications` + +Specifies the gallery applications that should be made available to the VM/VMSS. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `guestConfiguration` + +The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `licenseType` + +Specifies that the image or disk that is being used was licensed on-premises. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'RHEL_BYOS' + 'SLES_BYOS' + 'Windows_Client' + 'Windows_Server' + ] + ``` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `maintenanceConfigurationResourceId` + +The resource Id of a maintenance configuration for this VM. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = "True". + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: No +- Type: array + +### Parameter: `maxPriceForLowPriorityVm` + +Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `patchAssessmentMode` + +VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours. + +- Required: No +- Type: string +- Default: `'ImageDefault'` +- Allowed: + ```Bicep + [ + 'AutomaticByPlatform' + 'ImageDefault' + ] + ``` + +### Parameter: `patchMode` + +VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'AutomaticByOS' + 'AutomaticByPlatform' + 'ImageDefault' + 'Manual' + ] + ``` + +### Parameter: `plan` + +Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `priority` + +Specifies the priority for the virtual machine. + +- Required: No +- Type: string +- Default: `'Regular'` +- Allowed: + ```Bicep + [ + 'Low' + 'Regular' + 'Spot' + ] + ``` + +### Parameter: `provisionVMAgent` + +Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `proximityPlacementGroupResourceId` + +Resource ID of a proximity placement group. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `publicKeys` + +The list of SSH public keys used to authenticate with linux based VMs. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `rebootSetting` + +Specifies the reboot setting for all AutomaticByPlatform patch installation operations. + +- Required: No +- Type: string +- Default: `'IfRequired'` +- Allowed: + ```Bicep + [ + 'Always' + 'IfRequired' + 'Never' + 'Unknown' + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Operator for Managed Disks'` + - `'Desktop Virtualization Power On Contributor'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'DevTest Labs User'` + - `'Disk Backup Reader'` + - `'Disk Pool Operator'` + - `'Disk Restore Operator'` + - `'Disk Snapshot Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Virtual Machine Administrator Login'` + - `'Virtual Machine Contributor'` + - `'Virtual Machine User Login'` + - `'VM Scanner Operator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `sasTokenValidityLength` + +SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours. + +- Required: No +- Type: string +- Default: `'PT8H'` + +### Parameter: `secureBootEnabled` + +Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `securityType` + +Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'ConfidentialVM' + 'TrustedLaunch' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `timeZone` + +Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `ultraSSDEnabled` + +The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `userData` + +UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `virtualMachineScaleSetResourceId` + +Resource ID of a virtual machine scale set, where the VM should be added. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `vTpmEnabled` + +Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `winRM` + +Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `baseTime` + +Do not provide a value! This date value is used to generate a registration token. + +- Required: No +- Type: string +- Default: `[utcNow('u')]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the VM. | +| `resourceGroupName` | string | The name of the resource group the VM was created in. | +| `resourceId` | string | The resource ID of the VM. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/network-interface:0.4.0` | Remote reference | +| `br/public:avm/res/network/public-ip-address:0.6.0` | Remote reference | + +## Notes + +Inside the `nicConfigurations` section and there inside the `ipConfigurations`, a `pipConfiguration` can be defined. For a new puplic IP address, the naming can either be set with the `name` or the `publicIpNameSuffix`. Per default a newly created PIP will have its `zones` parameter set to `[1,2,3]`. You can override it, for example with `[]`. If an existing PIP should be used, only set the `publicIPAddressResourceId`. + +### Automanage considerations + +Enabling automanage triggers the creation of additional resources outside of the specific virtual machine deployment, such as: +- an `Automanage-Automate-` in the same Virtual Machine Resource Group and linking to the log analytics workspace leveraged by Azure Security Center. +- a `DefaultResourceGroup-` resource group hosting a recovery services vault `DefaultBackupVault-` where virtual machine backups are stored +For further details on automanage please refer to [Automanage virtual machines](https://learn.microsoft.com/en-us/azure/automanage/automanage-virtual-machines). + +### Parameter Usage: `imageReference` + +#### Marketplace images + +

+ +Parameter JSON format + +```json +"imageReference": { + "value": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2022-datacenter-azure-edition", + "version": "latest" + } +} +``` + +
+
+ +Bicep format + +```bicep +imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +``` + +
+

+ +#### Custom images + +

+ +Parameter JSON format + +```json +"imageReference": { + "value": { + "id": "/subscriptions/12345-6789-1011-1213-15161718/resourceGroups/rg-name/providers/Microsoft.Compute/images/imagename" + } +} +``` + +
+ +
+ +Bicep format + +```bicep +imageReference: { + id: '/subscriptions/12345-6789-1011-1213-15161718/resourceGroups/rg-name/providers/Microsoft.Compute/images/imagename' +} +``` + +
+

+ +### Parameter Usage: `plan` + +

+ +Parameter JSON format + +```json +"plan": { + "value": { + "name": "qvsa-25", + "product": "qualys-virtual-scanner", + "publisher": "qualysguard" + } +} +``` + +
+ +
+ +Bicep format + +```bicep +plan: { + name: 'qvsa-25' + product: 'qualys-virtual-scanner' + publisher: 'qualysguard' +} +``` + +
+

+ +### Parameter Usage: `osDisk` + +

+ +Parameter JSON format + +```json +"osDisk": { + "value": { + "createOption": "fromImage", + "deleteOption": "Delete", // Optional. Can be 'Delete' or 'Detach' + "diskSizeGB": "128", + "managedDisk": { + "storageAccountType": "Premium_LRS", + "diskEncryptionSet": { // Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs. + "id": "/subscriptions//resourceGroups//providers/Microsoft.Compute/diskEncryptionSets/" + } + } + } +} +``` + +
+ +
+ +Bicep format + +```bicep +osDisk: { + createOption: 'fromImage' + deleteOption: 'Delete' // Optional. Can be 'Delete' or 'Detach' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + diskEncryptionSet: { // Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs. + id: '/subscriptions//resourceGroups//providers/Microsoft.Compute/diskEncryptionSets/' + } + } +} +``` + +
+

+ +### Parameter Usage: `dataDisks` + +

+ +Parameter JSON format + +```json +"dataDisks": { + "value": [ + { + "caching": "ReadOnly", + "createOption": "Empty", + "deleteOption": "Delete", // Optional. Can be 'Delete' or 'Detach' + "diskSizeGB": "256", + "managedDisk": { + "storageAccountType": "Premium_LRS", + "diskEncryptionSet": { // Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs. + "id": "/subscriptions//resourceGroups//providers/Microsoft.Compute/diskEncryptionSets/" + } + } + }, + { + "caching": "ReadOnly", + "createOption": "Empty", + "diskSizeGB": "128", + "managedDisk": { + "storageAccountType": "Premium_LRS", + "diskEncryptionSet": { // Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs. + "id": "/subscriptions//resourceGroups//providers/Microsoft.Compute/diskEncryptionSets/" + } + } + } + ] +} +``` + +
+ +
+ +Bicep format + +```bicep +dataDisks: [ + { + caching: 'ReadOnly' + createOption: 'Empty' + deleteOption: 'Delete' // Optional. Can be 'Delete' or 'Detach' + diskSizeGB: '256' + managedDisk: { + storageAccountType: 'Premium_LRS' + diskEncryptionSet: { // Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs. + id: '/subscriptions//resourceGroups//providers/Microsoft.Compute/diskEncryptionSets/' + } + } + } + { + caching: 'ReadOnly' + createOption: 'Empty' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + diskEncryptionSet: { // Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs. + id: '/subscriptions//resourceGroups//providers/Microsoft.Compute/diskEncryptionSets/' + } + } + } +] +``` + +
+

+ +### Parameter Usage: `nicConfigurations` + +Comments: +- The field `nicSuffix` and `subnetResourceId` are mandatory. +- If `enablePublicIP` is set to true, then `publicIpNameSuffix` is also mandatory. +- Each IP config needs to have the mandatory field `name`. +- If not disabled, `enableAcceleratedNetworking` is considered `true` by default and requires the VM to be deployed with a supported OS and VM size. + +

+ +Parameter JSON format + +```json +"nicConfigurations": { + "value": [ + { + "nicSuffix": "-nic-01", + "deleteOption": "Delete", // Optional. Can be 'Delete' or 'Detach' + "ipConfigurations": [ + { + "name": "ipconfig1", + "subnetResourceId": "/subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/", + "pipConfiguration": { + "publicIpNameSuffix": "-pip-01", + "roleAssignments": [ + { + "roleDefinitionIdOrName": "Reader", + "principalIds": [ + "" + ] + } + ] + } + }, + { + "name": "ipconfig2", + "subnetResourceId": "/subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/", + } + ], + "nsgId": "/subscriptions//resourceGroups//providers/Microsoft.Network/networkSecurityGroups/", + "roleAssignments": [ + { + "roleDefinitionIdOrName": "Reader", + "principalIds": [ + "" + ] + } + ] + }, + { + "nicSuffix": "-nic-02", + "ipConfigurations": [ + { + "name": "ipconfig1", + "subnetResourceId": "/subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/", + "pipConfiguration": { + "publicIpNameSuffix": "-pip-02" + } + }, + { + "name": "ipconfig2", + "subnetResourceId": "/subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/", + "privateIPAllocationMethod": "Static", + "privateIPAddress": "10.0.0.9" + } + ] + } + ] +} +``` + +
+ +
+ +Bicep format + +```bicep +nicConfigurations: { + value: [ + { + nicSuffix: '-nic-01' + deleteOption: 'Delete' // Optional. Can be 'Delete' or 'Detach' + ipConfigurations: [ + { + name: 'ipconfig1' + subnetResourceId: '/subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalIds: [ + '' + ] + } + ] + } + } + { + name: 'ipconfig2' + subnetResourceId: '/subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/' + } + ] + nsgId: '/subscriptions//resourceGroups//providers/Microsoft.Network/networkSecurityGroups/' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalIds: [ + '' + ] + } + ] + } + { + nicSuffix: '-nic-02' + ipConfigurations: [ + { + name: 'ipconfig1' + subnetResourceId: '/subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/' + pipConfiguration: { + publicIpNameSuffix: '-pip-02' + } + } + { + name: 'ipconfig2' + subnetResourceId: '/subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/' + privateIPAllocationMethod: 'Static' + privateIPAddress: '10.0.0.9' + } + ] + } + ] +} +``` + +
+

+ +### Parameter Usage: `configurationProfileAssignments` + +

+ +Parameter JSON format + +```json +"configurationProfileAssignments": { + "value": [ + "/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction", + "/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest" + ] +} +``` + +
+ +
+ +Bicep format + +```bicep +configurationProfileAssignments: [ + '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction' + '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' +] +``` + +
+

+ +### Parameter Usage: `extensionDomainJoinConfig` + +

+ +Parameter JSON format + +```json +"extensionDomainJoinConfig": { + "value": { + "enabled": true, + "settings": { + "name": "contoso.com", + "user": "test.user@testcompany.com", + "ouPath": "OU=testOU; DC=contoso; DC=com", + "restart": true, + "options": 3 + } + } +}, +"extensionDomainJoinPassword": { + "reference": { + "keyVault": { + "id": "/subscriptions/</resourceGroups/myRG/providers/Microsoft.KeyVault/vaults/myKvlt" + }, + "secretName": "domainJoinUser02-Password" + } +} +``` + +
+ +
+ +Bicep format + +```bicep +extensionDomainJoinConfig: { + enabled: true + settings: { + name: 'contoso.com' + user: 'test.user@testcompany.com' + ouPath: 'OU=testOU; DC=contoso; DC=com' + restart: true + options: 3 + } +} +resource kv1 'Microsoft.KeyVault/vaults@2019-09-01' existing = { + name: 'adp-#_namePrefix_#-az-kv-x-001' + scope: resourceGroup('[[subscriptionId]]','validation-rg') +} +extensionDomainJoinPassword: kv1.getSecret('domainJoinUser02-Password') +``` + +
+

+ +### Parameter Usage: `extensionAntiMalwareConfig` + +Only for OSType Windows + +

+ +Parameter JSON format + +```json +"extensionAntiMalwareConfig": { + "value": { + "enabled": true, + "settings": { + "AntimalwareEnabled": true, + "Exclusions": { + "Extensions": ".log;.ldf", + "Paths": "D:\\IISlogs;D:\\DatabaseLogs", + "Processes": "mssence.svc" + }, + "RealtimeProtectionEnabled": true, + "ScheduledScanSettings": { + "isEnabled": "true", + "scanType": "Quick", + "day": "7", + "time": "120" + } + } + } +} +``` + +
+ +
+ +Bicep format + +```bicep +extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: true + Exclusions: { + Extensions: '.log;.ldf' + Paths: 'D:\\IISlogs;D:\\DatabaseLogs' + Processes: 'mssence.svc' + } + RealtimeProtectionEnabled: true + ScheduledScanSettings: { + isEnabled: 'true' + scanType: 'Quick' + day: '7' + time: '120' + } + } +} +``` + +
+

+ +### Parameter Usage: `extensionAzureDiskEncryptionConfig` + +

+ +Parameter JSON format + +```json +"extensionAzureDiskEncryptionConfig": { + // Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys. + "value": { + "enabled": true, + "settings": { + "EncryptionOperation": "EnableEncryption", + "KeyVaultURL": "https://mykeyvault.vault.azure.net/", + "KeyVaultResourceId": "/subscriptions/[[subscriptionId]]/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-sxx-az-kv-x-001", + "KeyEncryptionKeyURL": "https://mykeyvault.vault.azure.net/keys/keyEncryptionKey/bc3bb46d95c64367975d722f473eeae5", // ID must be updated for new keys + "KekVaultResourceId": "/subscriptions/[[subscriptionId]]/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-sxx-az-kv-x-001", + "KeyEncryptionAlgorithm": "RSA-OAEP", //'RSA-OAEP'/'RSA-OAEP-256'/'RSA1_5' + "VolumeType": "All", //'OS'/'Data'/'All' + "ResizeOSDisk": "false" + } + } +} +``` + +
+ +
+ +Bicep format + +```bicep +extensionAzureDiskEncryptionConfig: { + // Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys. + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KeyVaultURL: 'https://mykeyvault.vault.azure.net/' + KeyVaultResourceId: '/subscriptions/[[subscriptionId]]/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-sxx-az-kv-x-001' + KeyEncryptionKeyURL: 'https://mykeyvault.vault.azure.net/keys/keyEncryptionKey/bc3bb46d95c64367975d722f473eeae5' // ID must be updated for new keys + KekVaultResourceId: '/subscriptions/[[subscriptionId]]/resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/adp-sxx-az-kv-x-001' + KeyEncryptionAlgorithm: 'RSA-OAEP' //'RSA-OAEP'/'RSA-OAEP-256'/'RSA1_5' + VolumeType: 'All' //'OS'/'Data'/'All' + ResizeOSDisk: 'false' + } +} +``` + +
+

+ +### Parameter Usage: `extensionDSCConfig` + +

+ +Parameter JSON format + +```json +"extensionDSCConfig": { + "value": { + { + "enabled": true, + "settings": { + "wmfVersion": "latest", + "configuration": { + "url": "http://validURLToConfigLocation", + "script": "ConfigurationScript.ps1", + "function": "ConfigurationFunction" + }, + "configurationArguments": { + "argument1": "Value1", + "argument2": "Value2" + }, + "configurationData": { + "url": "https://foo.psd1" + }, + "privacy": { + "dataCollection": "enable" + }, + "advancedOptions": { + "forcePullAndApply": false, + "downloadMappings": { + "specificDependencyKey": "https://myCustomDependencyLocation" + } + } + }, + "protectedSettings": { + "configurationArguments": { + "mySecret": "MyPlaceholder" + }, + "configurationUrlSasToken": "MyPlaceholder", + "configurationDataUrlSasToken": "MyPlaceholder" + } + } + } +} +``` + +
+ +
+ +Bicep format + +```bicep +extensionDSCConfig: { + { + enabled: true + settings: { + wmfVersion: 'latest' + configuration: { + url: 'http://validURLToConfigLocation' + script: 'ConfigurationScript.ps1' + function: 'ConfigurationFunction' + } + configurationArguments: { + argument1: 'Value1' + argument2: 'Value2' + } + configurationData: { + url: 'https://foo.psd1' + } + privacy: { + dataCollection: 'enable' + } + advancedOptions: { + forcePullAndApply: false + downloadMappings: { + specificDependencyKey: 'https://myCustomDependencyLocation' + } + } + } + protectedSettings: { + configurationArguments: { + mySecret: 'MyPlaceholder' + } + configurationUrlSasToken: 'MyPlaceholder' + configurationDataUrlSasToken: 'MyPlaceholder' + } + } +} +``` + +
+

+ +### Parameter Usage: `extensionCustomScriptConfig` + +

+ +Parameter JSON format + +```json +"extensionCustomScriptConfig": { + "value": { + "enabled": true, + "fileData": [ + //storage accounts with SAS token requirement + { + "uri": "https://mystorageaccount.blob.core.windows.net/avdscripts/File1.ps1", + "storageAccountId": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/rgName/providers/Microsoft.Storage/storageAccounts/storageAccountName" + }, + { + "uri": "https://mystorageaccount.blob.core.windows.net/avdscripts/File2.ps1", + "storageAccountId": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/rgName/providers/Microsoft.Storage/storageAccounts/storageAccountName" + }, + //storage account with public container (no SAS token is required) OR other public URL (not a storage account) + { + "uri": "https://github.com/myProject/File3.ps1", + "storageAccountId": "" + } + ], + "settings": { + "commandToExecute": "powershell -ExecutionPolicy Unrestricted -File testscript.ps1" + } + } +} +``` + +
+ +
+ +Bicep format + +```bicep +extensionCustomScriptConfig: { + enabled: true + fileData: [ + //storage accounts with SAS token requirement + { + uri: 'https://mystorageaccount.blob.core.windows.net/avdscripts/File1.ps1' + storageAccountId: '/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/rgName/providers/Microsoft.Storage/storageAccounts/storageAccountName' + } + { + uri: 'https://mystorageaccount.blob.core.windows.net/avdscripts/File2.ps1' + storageAccountId: '/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/rgName/providers/Microsoft.Storage/storageAccounts/storageAccountName' + } + //storage account with public container (no SAS token is required) OR other public URL (not a storage account) + { + uri: 'https://github.com/myProject/File3.ps1' + storageAccountId: '' + } + ] + settings: { + commandToExecute: 'powershell -ExecutionPolicy Unrestricted -File testscript.ps1' + } +} +``` + +
+

+ +### Parameter Usage: `extensionCustomScriptProtectedSetting` + +This is used if you are going to use secrets or other sensitive information that you don't want to be visible in the deployment and logs. + +

+ +Parameter JSON format + +```json +"extensionCustomScriptProtectedSetting": { + "value": [ + { + "commandToExecute": "mycommandToRun -someParam MYSECRET" + } + ] +} +``` + +
+ +
+ +Bicep format + +```bicep +extensionCustomScriptProtectedSetting: [ + { + commandToExecute: 'mycommandToRun -someParam MYSECRET' + } +] +``` + +
+

+ +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/compute/virtual-machine/extension/README.md b/avm/1.1.0/res/compute/virtual-machine/extension/README.md new file mode 100644 index 000000000..6a60f47fa --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/extension/README.md @@ -0,0 +1,150 @@ +# Virtual Machine Extensions `[Microsoft.Compute/virtualMachines/extensions]` + +This module deploys a Virtual Machine Extension. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Compute/virtualMachines/extensions` | [2022-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-11-01/virtualMachines/extensions) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`autoUpgradeMinorVersion`](#parameter-autoupgrademinorversion) | bool | Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. | +| [`enableAutomaticUpgrade`](#parameter-enableautomaticupgrade) | bool | Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. | +| [`name`](#parameter-name) | string | The name of the virtual machine extension. | +| [`publisher`](#parameter-publisher) | string | The name of the extension handler publisher. | +| [`type`](#parameter-type) | string | Specifies the type of the extension; an example is "CustomScriptExtension". | +| [`typeHandlerVersion`](#parameter-typehandlerversion) | string | Specifies the version of the script handler. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`virtualMachineName`](#parameter-virtualmachinename) | string | The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`forceUpdateTag`](#parameter-forceupdatetag) | string | How the extension handler should be forced to update even if the extension configuration has not changed. | +| [`location`](#parameter-location) | string | The location the extension is deployed to. | +| [`protectedSettings`](#parameter-protectedsettings) | secureObject | Any object that contains the extension specific protected settings. | +| [`settings`](#parameter-settings) | object | Any object that contains the extension specific settings. | +| [`supressFailures`](#parameter-supressfailures) | bool | Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `autoUpgradeMinorVersion` + +Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true. + +- Required: Yes +- Type: bool + +### Parameter: `enableAutomaticUpgrade` + +Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available. + +- Required: Yes +- Type: bool + +### Parameter: `name` + +The name of the virtual machine extension. + +- Required: Yes +- Type: string + +### Parameter: `publisher` + +The name of the extension handler publisher. + +- Required: Yes +- Type: string + +### Parameter: `type` + +Specifies the type of the extension; an example is "CustomScriptExtension". + +- Required: Yes +- Type: string + +### Parameter: `typeHandlerVersion` + +Specifies the version of the script handler. + +- Required: Yes +- Type: string + +### Parameter: `virtualMachineName` + +The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `forceUpdateTag` + +How the extension handler should be forced to update even if the extension configuration has not changed. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `location` + +The location the extension is deployed to. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `protectedSettings` + +Any object that contains the extension specific protected settings. + +- Required: No +- Type: secureObject +- Default: `{}` + +### Parameter: `settings` + +Any object that contains the extension specific settings. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `supressFailures` + +Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the extension. | +| `resourceGroupName` | string | The name of the Resource Group the extension was created in. | +| `resourceId` | string | The resource ID of the extension. | diff --git a/avm/1.1.0/res/compute/virtual-machine/extension/main.bicep b/avm/1.1.0/res/compute/virtual-machine/extension/main.bicep new file mode 100644 index 000000000..f409336d7 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/extension/main.bicep @@ -0,0 +1,76 @@ +metadata name = 'Virtual Machine Extensions' +metadata description = 'This module deploys a Virtual Machine Extension.' + +@description('Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment.') +param virtualMachineName string + +@description('Required. The name of the virtual machine extension.') +param name string + +@description('Optional. The location the extension is deployed to.') +param location string = resourceGroup().location + +@description('Required. The name of the extension handler publisher.') +param publisher string + +@description('Required. Specifies the type of the extension; an example is "CustomScriptExtension".') +param type string + +@description('Required. Specifies the version of the script handler.') +param typeHandlerVersion string + +@description('Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true.') +param autoUpgradeMinorVersion bool + +@description('Optional. How the extension handler should be forced to update even if the extension configuration has not changed.') +param forceUpdateTag string = '' + +@description('Optional. Any object that contains the extension specific settings.') +param settings object = {} + +@description('Optional. Any object that contains the extension specific protected settings.') +@secure() +param protectedSettings object = {} + +@description('Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false.') +param supressFailures bool = false + +@description('Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available.') +param enableAutomaticUpgrade bool + +@description('Optional. Tags of the resource.') +param tags object? + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-11-01' existing = { + name: virtualMachineName +} + +resource extension 'Microsoft.Compute/virtualMachines/extensions@2022-11-01' = { + name: name + parent: virtualMachine + location: location + tags: tags + properties: { + publisher: publisher + type: type + typeHandlerVersion: typeHandlerVersion + autoUpgradeMinorVersion: autoUpgradeMinorVersion + enableAutomaticUpgrade: enableAutomaticUpgrade + forceUpdateTag: !empty(forceUpdateTag) ? forceUpdateTag : null + settings: !empty(settings) ? settings : null + protectedSettings: !empty(protectedSettings) ? protectedSettings : null + suppressFailures: supressFailures + } +} + +@description('The name of the extension.') +output name string = extension.name + +@description('The resource ID of the extension.') +output resourceId string = extension.id + +@description('The name of the Resource Group the extension was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = extension.location diff --git a/avm/1.1.0/res/compute/virtual-machine/extension/main.json b/avm/1.1.0/res/compute/virtual-machine/extension/main.json new file mode 100644 index 000000000..7bbd7e373 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/extension/main.json @@ -0,0 +1,156 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "17394804773765276039" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/virtual-machine/main.bicep b/avm/1.1.0/res/compute/virtual-machine/main.bicep new file mode 100644 index 000000000..63aca7262 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/main.bicep @@ -0,0 +1,1169 @@ +metadata name = 'Virtual Machines' +metadata description = 'This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.' + +@description('Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory.') +param name string + +@description('Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name.') +param computerName string = name + +@description('Required. Specifies the size for the VMs.') +param vmSize string + +@description('Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs.') +param encryptionAtHost bool = true + +@description('Optional. Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set.') +@allowed([ + '' + 'ConfidentialVM' + 'TrustedLaunch' +]) +param securityType string = '' + +@description('Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings.') +param secureBootEnabled bool = false + +@description('Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings.') +param vTpmEnabled bool = false + +@description('Required. OS image reference. In case of marketplace images, it\'s the combination of the publisher, offer, sku, version attributes. In case of custom images it\'s the resource ID of the custom image.') +param imageReference object + +@description('Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use.') +param plan object = {} + +@description('Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs.') +param osDisk osDiskType + +@description('Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs.') +param dataDisks dataDisksType + +@description('Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled.') +param ultraSSDEnabled bool = false + +@description('Required. Administrator username.') +@secure() +param adminUsername string + +@description('Optional. When specifying a Windows Virtual Machine, this value should be passed.') +@secure() +param adminPassword string = '' + +@description('Optional. UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here.') +param userData string = '' + +@description('Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format.') +param customData string = '' + +@description('Optional. Specifies set of certificates that should be installed onto the virtual machine.') +param certificatesToBeInstalled array = [] + +@description('Optional. Specifies the priority for the virtual machine.') +@allowed([ + 'Regular' + 'Low' + 'Spot' +]) +param priority string = 'Regular' + +@description('Optional. Specifies the eviction policy for the low priority virtual machine. Will result in \'Deallocate\' eviction policy.') +param enableEvictionPolicy bool = false + +@description('Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars.') +param maxPriceForLowPriorityVm string = '' + +@description('Optional. Specifies resource ID about the dedicated host that the virtual machine resides in.') +param dedicatedHostId string = '' + +@description('Optional. Specifies that the image or disk that is being used was licensed on-premises.') +@allowed([ + 'RHEL_BYOS' + 'SLES_BYOS' + 'Windows_Client' + 'Windows_Server' + '' +]) +param licenseType string = '' + +@description('Optional. The list of SSH public keys used to authenticate with linux based VMs.') +param publicKeys array = [] + +@description('Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = "True".') +param managedIdentities managedIdentitiesType + +@description('Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled.') +param bootDiagnostics bool = false + +@description('Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided.') +param bootDiagnosticStorageAccountName string = '' + +@description('Optional. Storage account boot diagnostic base URI.') +param bootDiagnosticStorageAccountUri string = '.blob.${environment().suffixes.storage}/' + +@description('Optional. Resource ID of a proximity placement group.') +param proximityPlacementGroupResourceId string = '' + +@description('Optional. Resource ID of a virtual machine scale set, where the VM should be added.') +param virtualMachineScaleSetResourceId string = '' + +@description('Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set.') +param availabilitySetResourceId string = '' + +@description('Optional. Specifies the gallery applications that should be made available to the VM/VMSS.') +param galleryApplications array = [] + +@description('Required. If set to 1, 2 or 3, the availability zone for all VMs is hardcoded to that value. If zero, then availability zones is not used. Cannot be used in combination with availability set nor scale set.') +@allowed([ + 0 + 1 + 2 + 3 +]) +param zone int + +// External resources +@description('Required. Configures NICs and PIPs.') +param nicConfigurations array + +@description('Optional. Recovery service vault name to add VMs to backup.') +param backupVaultName string = '' + +@description('Optional. Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default.') +param backupVaultResourceGroup string = resourceGroup().name + +@description('Optional. Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault.') +param backupPolicyName string = 'DefaultPolicy' + +@description('Optional. The configuration for auto-shutdown.') +param autoShutdownConfig object = {} + +@description('Optional. The resource Id of a maintenance configuration for this VM.') +param maintenanceConfigurationResourceId string = '' + +// Child resources +@description('Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine.') +param allowExtensionOperations bool = true + +@description('Optional. Required if name is specified. Password of the user specified in user parameter.') +@secure() +param extensionDomainJoinPassword string = '' + +@description('Optional. The configuration for the [Domain Join] extension. Must at least contain the ["enabled": true] property to be executed.') +@secure() +param extensionDomainJoinConfig object = {} + +@description('Optional. The configuration for the [AAD Join] extension. Must at least contain the ["enabled": true] property to be executed. To enroll in Intune, add the setting mdmId: "0000000a-0000-0000-c000-000000000000".') +param extensionAadJoinConfig object = { + enabled: false +} + +@description('Optional. The configuration for the [Anti Malware] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionAntiMalwareConfig object = osType == 'Windows' + ? { + enabled: true + } + : { enabled: false } + +@description('Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionMonitoringAgentConfig object = { + enabled: false + dataCollectionRuleAssociations: [] +} + +@description('Optional. The configuration for the [Dependency Agent] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionDependencyAgentConfig object = { + enabled: false +} + +@description('Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionNetworkWatcherAgentConfig object = { + enabled: false +} + +@description('Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the ["enabled": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys.') +param extensionAzureDiskEncryptionConfig object = { + enabled: false +} + +@description('Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionDSCConfig object = { + enabled: false +} + +@description('Optional. The configuration for the [Custom Script] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionCustomScriptConfig object = { + enabled: false + fileData: [] +} + +@description('Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the ["enabled": true] property to be executed.') +param extensionNvidiaGpuDriverWindows object = { + enabled: false +} + +@description('Optional. The configuration for the [Host Pool Registration] extension. Must at least contain the ["enabled": true] property to be executed. Needs a managed identy.') +param extensionHostPoolRegistration object = { + enabled: false +} + +@description('Optional. The configuration for the [Guest Configuration] extension. Must at least contain the ["enabled": true] property to be executed. Needs a managed identy.') +param extensionGuestConfigurationExtension object = { + enabled: false +} + +@description('Optional. The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled.') +param guestConfiguration object = {} + +@description('Optional. An object that contains the extension specific protected settings.') +@secure() +param extensionCustomScriptProtectedSetting object = {} + +@description('Optional. An object that contains the extension specific protected settings.') +@secure() +param extensionGuestConfigurationExtensionProtectedSettings object = {} + +// Shared parameters +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Generated. Do not provide a value! This date value is used to generate a registration token.') +param baseTime string = utcNow('u') + +@description('Optional. SAS token validity length to use to download files from storage accounts. Usage: \'PT8H\' - valid for 8 hours; \'P5D\' - valid for 5 days; \'P1Y\' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours.') +param sasTokenValidityLength string = 'PT8H' + +@description('Required. The chosen OS type.') +@allowed([ + 'Windows' + 'Linux' +]) +param osType string + +@description('Optional. Specifies whether password authentication should be disabled.') +#disable-next-line secure-secrets-in-params // Not a secret +param disablePasswordAuthentication bool = false + +@description('Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later.') +param provisionVMAgent bool = true + +@description('Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning.') +param enableAutomaticUpdates bool = true + +@description('Optional. VM guest patching orchestration mode. \'AutomaticByOS\' & \'Manual\' are for Windows only, \'ImageDefault\' for Linux only. Refer to \'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching\'.') +@allowed([ + 'AutomaticByPlatform' + 'AutomaticByOS' + 'Manual' + 'ImageDefault' + '' +]) +param patchMode string = '' + +@description('Optional. Enables customer to schedule patching without accidental upgrades.') +param bypassPlatformSafetyChecksOnUserSchedule bool = true + +@description('Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations.') +@allowed([ + 'Always' + 'IfRequired' + 'Never' + 'Unknown' +]) +param rebootSetting string = 'IfRequired' + +@description('Optional. VM guest patching assessment mode. Set it to \'AutomaticByPlatform\' to enable automatically check for updates every 24 hours.') +@allowed([ + 'AutomaticByPlatform' + 'ImageDefault' +]) +param patchAssessmentMode string = 'ImageDefault' + +@description('Optional. Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the \'provisionVMAgent\' must be set to true and \'patchMode\' must be set to \'AutomaticByPlatform\'.') +param enableHotpatching bool = false + +@description('Optional. Specifies the time zone of the virtual machine. e.g. \'Pacific Standard Time\'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`.') +param timeZone string = '' + +@description('Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied.') +param additionalUnattendContent array = [] + +@description('Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object.') +param winRM array = [] + +@description('Optional. The configuration profile of automanage. Either \'/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction\', \'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest\' or the resource Id of custom profile.') +param configurationProfile string = '' + +var publicKeysFormatted = [ + for publicKey in publicKeys: { + path: publicKey.path + keyData: publicKey.keyData + } +] + +var linuxConfiguration = { + disablePasswordAuthentication: disablePasswordAuthentication + ssh: { + publicKeys: publicKeysFormatted + } + provisionVMAgent: provisionVMAgent + patchSettings: (provisionVMAgent && (patchMode =~ 'AutomaticByPlatform' || patchMode =~ 'ImageDefault')) + ? { + patchMode: patchMode + assessmentMode: patchAssessmentMode + automaticByPlatformSettings: (patchMode =~ 'AutomaticByPlatform') + ? { + bypassPlatformSafetyChecksOnUserSchedule: bypassPlatformSafetyChecksOnUserSchedule + rebootSetting: rebootSetting + } + : null + } + : null +} + +var windowsConfiguration = { + provisionVMAgent: provisionVMAgent + enableAutomaticUpdates: enableAutomaticUpdates + patchSettings: (provisionVMAgent && (patchMode =~ 'AutomaticByPlatform' || patchMode =~ 'AutomaticByOS' || patchMode =~ 'Manual')) + ? { + patchMode: patchMode + assessmentMode: patchAssessmentMode + enableHotpatching: (patchMode =~ 'AutomaticByPlatform') ? enableHotpatching : false + automaticByPlatformSettings: (patchMode =~ 'AutomaticByPlatform') + ? { + bypassPlatformSafetyChecksOnUserSchedule: bypassPlatformSafetyChecksOnUserSchedule + rebootSetting: rebootSetting + } + : null + } + : null + timeZone: empty(timeZone) ? null : timeZone + additionalUnattendContent: empty(additionalUnattendContent) ? null : additionalUnattendContent + winRM: !empty(winRM) + ? { + listeners: winRM + } + : null +} + +var accountSasProperties = { + signedServices: 'b' + signedPermission: 'r' + signedExpiry: dateTimeAdd(baseTime, sasTokenValidityLength) + signedResourceTypes: 'o' + signedProtocol: 'https' +} + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +// If AADJoin Extension is enabled then we automatically enable SystemAssigned (required by AADJoin), otherwise we follow the usual logic. +var identity = !empty(managedIdentities) + ? { + type: (extensionAadJoinConfig.enabled ? true : (managedIdentities.?systemAssigned ?? false)) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Data Operator for Managed Disks': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '959f8984-c045-4866-89c7-12bf9737be2e' + ) + 'Desktop Virtualization Power On Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '489581de-a3bd-480d-9518-53dea7416b33' + ) + 'Desktop Virtualization Power On Off Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '40c5ff49-9181-41f8-ae61-143b0e78555e' + ) + 'Desktop Virtualization Virtual Machine Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a959dbd1-f747-45e3-8ba6-dd80f235f97c' + ) + 'DevTest Labs User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '76283e04-6283-4c54-8f91-bcf1374a3c64' + ) + 'Disk Backup Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24' + ) + 'Disk Pool Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '60fc6e62-5479-42d4-8bf4-67625fcc2840' + ) + 'Disk Restore Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b50d9833-a0cb-478e-945f-707fcc997c13' + ) + 'Disk Snapshot Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7efff54f-a5b4-42b5-a1c5-5411624893ce' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) + 'Virtual Machine Administrator Login': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '1c0163c0-47e6-4577-8991-ea5c82e286e4' + ) + 'Virtual Machine Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '9980e02c-c2be-4d73-94e8-173b1dc7cf3c' + ) + 'Virtual Machine User Login': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'fb879df8-f326-4884-b1cf-06f3ad86be52' + ) + 'VM Scanner Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.compute-virtualmachine.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +module vm_nic 'modules/nic-configuration.bicep' = [ + for (nicConfiguration, index) in nicConfigurations: { + name: '${uniqueString(deployment().name, location)}-VM-Nic-${index}' + params: { + networkInterfaceName: nicConfiguration.?name ?? '${name}${nicConfiguration.?nicSuffix}' + virtualMachineName: name + location: location + enableIPForwarding: nicConfiguration.?enableIPForwarding ?? false + enableAcceleratedNetworking: nicConfiguration.?enableAcceleratedNetworking ?? true + dnsServers: contains(nicConfiguration, 'dnsServers') + ? (!empty(nicConfiguration.dnsServers) ? nicConfiguration.dnsServers : []) + : [] + networkSecurityGroupResourceId: nicConfiguration.?networkSecurityGroupResourceId ?? '' + ipConfigurations: nicConfiguration.ipConfigurations + lock: nicConfiguration.?lock ?? lock + tags: nicConfiguration.?tags ?? tags + diagnosticSettings: nicConfiguration.?diagnosticSettings + roleAssignments: nicConfiguration.?roleAssignments + enableTelemetry: nicConfiguration.?enableTelemetry ?? enableTelemetry + } + } +] + +resource managedDataDisks 'Microsoft.Compute/disks@2024-03-02' = [ + for (dataDisk, index) in dataDisks ?? []: { + location: location + name: dataDisk.?name ?? '${name}-disk-data-${padLeft((index + 1), 2, '0')}' + sku: { + name: dataDisk.managedDisk.storageAccountType + } + properties: { + diskSizeGB: dataDisk.diskSizeGB + creationData: { + createOption: dataDisk.?createoption ?? 'Empty' + } + diskIOPSReadWrite: dataDisk.?diskIOPSReadWrite + diskMBpsReadWrite: dataDisk.?diskMBpsReadWrite + } + zones: zone != 0 ? array(string(zone)) : null + } +] + +resource vm 'Microsoft.Compute/virtualMachines@2024-07-01' = { + name: name + location: location + identity: identity + tags: tags + zones: zone != 0 ? array(string(zone)) : null + plan: !empty(plan) ? plan : null + properties: { + hardwareProfile: { + vmSize: vmSize + } + securityProfile: { + encryptionAtHost: encryptionAtHost ? encryptionAtHost : null + securityType: securityType + uefiSettings: securityType == 'TrustedLaunch' + ? { + secureBootEnabled: secureBootEnabled + vTpmEnabled: vTpmEnabled + } + : null + } + storageProfile: { + imageReference: imageReference + osDisk: { + name: osDisk.?name ?? '${name}-disk-os-01' + createOption: osDisk.?createOption ?? 'FromImage' + deleteOption: osDisk.?deleteOption ?? 'Delete' + diskSizeGB: osDisk.diskSizeGB + caching: osDisk.?caching ?? 'ReadOnly' + managedDisk: { + storageAccountType: osDisk.managedDisk.storageAccountType + diskEncryptionSet: { + id: osDisk.managedDisk.?diskEncryptionSetResourceId + } + } + } + dataDisks: [ + for (dataDisk, index) in dataDisks ?? []: { + lun: dataDisk.?lun ?? index + name: dataDisk.?name ?? '${name}-disk-data-${padLeft((index + 1), 2, '0')}' + diskSizeGB: dataDisk.diskSizeGB + createOption: (managedDataDisks[index].?id != null) ? 'Attach' : dataDisk.?createoption ?? 'Empty' + deleteOption: dataDisk.?deleteOption ?? 'Delete' + caching: dataDisk.?caching ?? 'ReadOnly' + managedDisk: { + storageAccountType: dataDisk.managedDisk.storageAccountType + id: managedDataDisks[index].?id + diskEncryptionSet: { + id: dataDisk.managedDisk.?diskEncryptionSetResourceId + } + } + } + ] + } + additionalCapabilities: { + ultraSSDEnabled: ultraSSDEnabled + } + osProfile: { + computerName: computerName + adminUsername: adminUsername + adminPassword: adminPassword + customData: !empty(customData) ? base64(customData) : null + windowsConfiguration: osType == 'Windows' ? windowsConfiguration : null + linuxConfiguration: osType == 'Linux' ? linuxConfiguration : null + secrets: certificatesToBeInstalled + allowExtensionOperations: allowExtensionOperations + } + networkProfile: { + networkInterfaces: [ + for (nicConfiguration, index) in nicConfigurations: { + properties: { + deleteOption: nicConfiguration.?deleteOption ?? 'Delete' + primary: index == 0 ? true : false + } + #disable-next-line use-resource-id-functions // It's a reference from inside a loop which makes resolving it using a resource reference particulary difficult. + id: az.resourceId( + 'Microsoft.Network/networkInterfaces', + nicConfiguration.?name ?? '${name}${nicConfiguration.?nicSuffix}' + ) + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: !empty(bootDiagnosticStorageAccountName) ? true : bootDiagnostics + storageUri: !empty(bootDiagnosticStorageAccountName) + ? 'https://${bootDiagnosticStorageAccountName}${bootDiagnosticStorageAccountUri}' + : null + } + } + applicationProfile: !empty(galleryApplications) + ? { + galleryApplications: galleryApplications + } + : null + availabilitySet: !empty(availabilitySetResourceId) + ? { + id: availabilitySetResourceId + } + : null + proximityPlacementGroup: !empty(proximityPlacementGroupResourceId) + ? { + id: proximityPlacementGroupResourceId + } + : null + virtualMachineScaleSet: !empty(virtualMachineScaleSetResourceId) + ? { + id: virtualMachineScaleSetResourceId + } + : null + priority: priority + evictionPolicy: enableEvictionPolicy ? 'Deallocate' : null + #disable-next-line BCP036 + billingProfile: !empty(priority) && !empty(maxPriceForLowPriorityVm) + ? { + maxPrice: json(maxPriceForLowPriorityVm) + } + : null + host: !empty(dedicatedHostId) + ? { + id: dedicatedHostId + } + : null + licenseType: !empty(licenseType) ? licenseType : null + userData: !empty(userData) ? base64(userData) : null + } + dependsOn: [ + vm_nic + ] +} + +resource vm_configurationAssignment 'Microsoft.Maintenance/configurationAssignments@2023-04-01' = if (!empty(maintenanceConfigurationResourceId)) { + name: '${vm.name}assignment' + location: location + properties: { + maintenanceConfigurationId: maintenanceConfigurationResourceId + resourceId: vm.id + } + scope: vm +} + +resource vm_configurationProfileAssignment 'Microsoft.Automanage/configurationProfileAssignments@2022-05-04' = if (!empty(configurationProfile)) { + name: 'default' + properties: { + configurationProfile: configurationProfile + } + scope: vm +} + +resource vm_autoShutdownConfiguration 'Microsoft.DevTestLab/schedules@2018-09-15' = if (!empty(autoShutdownConfig)) { + name: 'shutdown-computevm-${vm.name}' + location: location + properties: { + status: autoShutdownConfig.?status ?? 'Disabled' + targetResourceId: vm.id + taskType: 'ComputeVmShutdownTask' + dailyRecurrence: { + time: autoShutdownConfig.?dailyRecurrenceTime ?? '19:00' + } + timeZoneId: autoShutdownConfig.?timeZone ?? 'UTC' + notificationSettings: contains(autoShutdownConfig, 'notificationStatus') + ? { + status: autoShutdownConfig.?notificationStatus ?? 'Disabled' + emailRecipient: autoShutdownConfig.?notificationEmail ?? '' + notificationLocale: autoShutdownConfig.?notificationLocale ?? 'en' + webhookUrl: autoShutdownConfig.?notificationWebhookUrl ?? '' + timeInMinutes: autoShutdownConfig.?notificationTimeInMinutes ?? 30 + } + : null + } +} + +module vm_aadJoinExtension 'extension/main.bicep' = if (extensionAadJoinConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VM-AADLogin' + params: { + virtualMachineName: vm.name + name: 'AADLogin' + location: location + publisher: 'Microsoft.Azure.ActiveDirectory' + type: osType == 'Windows' ? 'AADLoginForWindows' : 'AADSSHLoginforLinux' + typeHandlerVersion: extensionAadJoinConfig.?typeHandlerVersion ?? (osType == 'Windows' ? '2.0' : '1.0') + autoUpgradeMinorVersion: extensionAadJoinConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionAadJoinConfig.?enableAutomaticUpgrade ?? false + settings: extensionAadJoinConfig.?settings ?? {} + supressFailures: extensionAadJoinConfig.?supressFailures ?? false + tags: extensionAadJoinConfig.?tags ?? tags + } +} + +module vm_domainJoinExtension 'extension/main.bicep' = if (contains(extensionDomainJoinConfig, 'enabled') && extensionDomainJoinConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VM-DomainJoin' + params: { + virtualMachineName: vm.name + name: 'DomainJoin' + location: location + publisher: 'Microsoft.Compute' + type: 'JsonADDomainExtension' + typeHandlerVersion: extensionDomainJoinConfig.?typeHandlerVersion ?? '1.3' + autoUpgradeMinorVersion: extensionDomainJoinConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionDomainJoinConfig.?enableAutomaticUpgrade ?? false + settings: extensionDomainJoinConfig.settings + supressFailures: extensionDomainJoinConfig.?supressFailures ?? false + tags: extensionDomainJoinConfig.?tags ?? tags + protectedSettings: { + Password: extensionDomainJoinPassword + } + } + dependsOn: [ + vm_aadJoinExtension + ] +} + +module vm_microsoftAntiMalwareExtension 'extension/main.bicep' = if (extensionAntiMalwareConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VM-MicrosoftAntiMalware' + params: { + virtualMachineName: vm.name + name: 'MicrosoftAntiMalware' + location: location + publisher: 'Microsoft.Azure.Security' + type: 'IaaSAntimalware' + typeHandlerVersion: extensionAntiMalwareConfig.?typeHandlerVersion ?? '1.3' + autoUpgradeMinorVersion: extensionAntiMalwareConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionAntiMalwareConfig.?enableAutomaticUpgrade ?? false + settings: extensionAntiMalwareConfig.?settings ?? { + AntimalwareEnabled: 'true' + Exclusions: {} + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + supressFailures: extensionAntiMalwareConfig.?supressFailures ?? false + tags: extensionAntiMalwareConfig.?tags ?? tags + } + dependsOn: [ + vm_domainJoinExtension + ] +} + +module vm_azureMonitorAgentExtension 'extension/main.bicep' = if (extensionMonitoringAgentConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VM-AzureMonitorAgent' + params: { + virtualMachineName: vm.name + name: 'AzureMonitorAgent' + location: location + publisher: 'Microsoft.Azure.Monitor' + type: osType == 'Windows' ? 'AzureMonitorWindowsAgent' : 'AzureMonitorLinuxAgent' + typeHandlerVersion: extensionMonitoringAgentConfig.?typeHandlerVersion ?? (osType == 'Windows' ? '1.22' : '1.29') + autoUpgradeMinorVersion: extensionMonitoringAgentConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionMonitoringAgentConfig.?enableAutomaticUpgrade ?? false + supressFailures: extensionMonitoringAgentConfig.?supressFailures ?? false + tags: extensionMonitoringAgentConfig.?tags ?? tags + } + dependsOn: [ + vm_microsoftAntiMalwareExtension + ] +} + +resource vm_dataCollectionRuleAssociations 'Microsoft.Insights/dataCollectionRuleAssociations@2023-03-11' = [ + for (dataCollectionRuleAssociation, index) in extensionMonitoringAgentConfig.dataCollectionRuleAssociations: if (extensionMonitoringAgentConfig.enabled) { + name: dataCollectionRuleAssociation.name + scope: vm + properties: { + dataCollectionRuleId: dataCollectionRuleAssociation.dataCollectionRuleResourceId + } + dependsOn: [ + vm_azureMonitorAgentExtension + ] + } +] + +module vm_dependencyAgentExtension 'extension/main.bicep' = if (extensionDependencyAgentConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VM-DependencyAgent' + params: { + virtualMachineName: vm.name + name: 'DependencyAgent' + location: location + publisher: 'Microsoft.Azure.Monitoring.DependencyAgent' + type: osType == 'Windows' ? 'DependencyAgentWindows' : 'DependencyAgentLinux' + typeHandlerVersion: extensionDependencyAgentConfig.?typeHandlerVersion ?? '9.10' + autoUpgradeMinorVersion: extensionDependencyAgentConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionDependencyAgentConfig.?enableAutomaticUpgrade ?? true + settings: { + enableAMA: extensionDependencyAgentConfig.?enableAMA ?? true + } + supressFailures: extensionDependencyAgentConfig.?supressFailures ?? false + tags: extensionDependencyAgentConfig.?tags ?? tags + } + dependsOn: [ + vm_azureMonitorAgentExtension + ] +} + +module vm_networkWatcherAgentExtension 'extension/main.bicep' = if (extensionNetworkWatcherAgentConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VM-NetworkWatcherAgent' + params: { + virtualMachineName: vm.name + name: 'NetworkWatcherAgent' + location: location + publisher: 'Microsoft.Azure.NetworkWatcher' + type: osType == 'Windows' ? 'NetworkWatcherAgentWindows' : 'NetworkWatcherAgentLinux' + typeHandlerVersion: extensionNetworkWatcherAgentConfig.?typeHandlerVersion ?? '1.4' + autoUpgradeMinorVersion: extensionNetworkWatcherAgentConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionNetworkWatcherAgentConfig.?enableAutomaticUpgrade ?? false + supressFailures: extensionNetworkWatcherAgentConfig.?supressFailures ?? false + tags: extensionNetworkWatcherAgentConfig.?tags ?? tags + } + dependsOn: [ + vm_dependencyAgentExtension + ] +} + +module vm_desiredStateConfigurationExtension 'extension/main.bicep' = if (extensionDSCConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VM-DesiredStateConfiguration' + params: { + virtualMachineName: vm.name + name: 'DesiredStateConfiguration' + location: location + publisher: 'Microsoft.Powershell' + type: 'DSC' + typeHandlerVersion: extensionDSCConfig.?typeHandlerVersion ?? '2.77' + autoUpgradeMinorVersion: extensionDSCConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionDSCConfig.?enableAutomaticUpgrade ?? false + settings: extensionDSCConfig.?settings ?? {} + supressFailures: extensionDSCConfig.?supressFailures ?? false + tags: extensionDSCConfig.?tags ?? tags + protectedSettings: extensionDSCConfig.?protectedSettings ?? {} + } + dependsOn: [ + vm_networkWatcherAgentExtension + ] +} + +module vm_customScriptExtension 'extension/main.bicep' = if (extensionCustomScriptConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VM-CustomScriptExtension' + params: { + virtualMachineName: vm.name + name: 'CustomScriptExtension' + location: location + publisher: osType == 'Windows' ? 'Microsoft.Compute' : 'Microsoft.Azure.Extensions' + type: osType == 'Windows' ? 'CustomScriptExtension' : 'CustomScript' + typeHandlerVersion: extensionCustomScriptConfig.?typeHandlerVersion ?? (osType == 'Windows' ? '1.10' : '2.1') + autoUpgradeMinorVersion: extensionCustomScriptConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionCustomScriptConfig.?enableAutomaticUpgrade ?? false + settings: { + fileUris: [ + for fileData in extensionCustomScriptConfig.fileData: contains(fileData, 'storageAccountId') + ? '${fileData.uri}?${listAccountSas(fileData.storageAccountId, '2019-04-01', accountSasProperties).accountSasToken}' + : fileData.uri + ] + } + supressFailures: extensionCustomScriptConfig.?supressFailures ?? false + tags: extensionCustomScriptConfig.?tags ?? tags + protectedSettings: extensionCustomScriptProtectedSetting + } + dependsOn: [ + vm_desiredStateConfigurationExtension + ] +} + +module vm_azureDiskEncryptionExtension 'extension/main.bicep' = if (extensionAzureDiskEncryptionConfig.enabled) { + name: '${uniqueString(deployment().name, location)}-VM-AzureDiskEncryption' + params: { + virtualMachineName: vm.name + name: 'AzureDiskEncryption' + location: location + publisher: 'Microsoft.Azure.Security' + type: osType == 'Windows' ? 'AzureDiskEncryption' : 'AzureDiskEncryptionForLinux' + typeHandlerVersion: extensionAzureDiskEncryptionConfig.?typeHandlerVersion ?? (osType == 'Windows' ? '2.2' : '1.1') + autoUpgradeMinorVersion: extensionAzureDiskEncryptionConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionAzureDiskEncryptionConfig.?enableAutomaticUpgrade ?? false + forceUpdateTag: extensionAzureDiskEncryptionConfig.?forceUpdateTag ?? '1.0' + settings: extensionAzureDiskEncryptionConfig.?settings ?? {} + supressFailures: extensionAzureDiskEncryptionConfig.?supressFailures ?? false + tags: extensionAzureDiskEncryptionConfig.?tags ?? tags + } + dependsOn: [ + vm_customScriptExtension + ] +} + +module vm_nvidiaGpuDriverWindowsExtension 'extension/main.bicep' = if (extensionNvidiaGpuDriverWindows.enabled) { + name: '${uniqueString(deployment().name, location)}-VM-NvidiaGpuDriverWindows' + params: { + virtualMachineName: vm.name + name: 'NvidiaGpuDriverWindows' + location: location + publisher: 'Microsoft.HpcCompute' + type: 'NvidiaGpuDriverWindows' + typeHandlerVersion: extensionNvidiaGpuDriverWindows.?typeHandlerVersion ?? '1.4' + autoUpgradeMinorVersion: extensionNvidiaGpuDriverWindows.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionNvidiaGpuDriverWindows.?enableAutomaticUpgrade ?? false + supressFailures: extensionNvidiaGpuDriverWindows.?supressFailures ?? false + tags: extensionNvidiaGpuDriverWindows.?tags ?? tags + } + dependsOn: [ + vm_azureDiskEncryptionExtension + ] +} + +module vm_hostPoolRegistrationExtension 'extension/main.bicep' = if (extensionHostPoolRegistration.enabled) { + name: '${uniqueString(deployment().name, location)}-VM-HostPoolRegistration' + params: { + virtualMachineName: vm.name + name: 'HostPoolRegistration' + location: location + publisher: 'Microsoft.PowerShell' + type: 'DSC' + typeHandlerVersion: extensionHostPoolRegistration.?typeHandlerVersion ?? '2.77' + autoUpgradeMinorVersion: extensionHostPoolRegistration.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionHostPoolRegistration.?enableAutomaticUpgrade ?? false + settings: { + modulesUrl: extensionHostPoolRegistration.modulesUrl + configurationFunction: extensionHostPoolRegistration.configurationFunction + properties: { + hostPoolName: extensionHostPoolRegistration.hostPoolName + registrationInfoToken: extensionHostPoolRegistration.registrationInfoToken + aadJoin: true + } + supressFailures: extensionHostPoolRegistration.?supressFailures ?? false + } + tags: extensionHostPoolRegistration.?tags ?? tags + } + dependsOn: [ + vm_nvidiaGpuDriverWindowsExtension + ] +} + +module vm_azureGuestConfigurationExtension 'extension/main.bicep' = if (extensionGuestConfigurationExtension.enabled) { + name: '${uniqueString(deployment().name, location)}-VM-GuestConfiguration' + params: { + virtualMachineName: vm.name + name: osType == 'Windows' ? 'AzurePolicyforWindows' : 'AzurePolicyforLinux' + location: location + publisher: 'Microsoft.GuestConfiguration' + type: osType == 'Windows' ? 'ConfigurationforWindows' : 'ConfigurationForLinux' + typeHandlerVersion: extensionGuestConfigurationExtension.?typeHandlerVersion ?? (osType == 'Windows' ? '1.0' : '1.0') + autoUpgradeMinorVersion: extensionGuestConfigurationExtension.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionGuestConfigurationExtension.?enableAutomaticUpgrade ?? true + forceUpdateTag: extensionGuestConfigurationExtension.?forceUpdateTag ?? '1.0' + settings: extensionGuestConfigurationExtension.?settings ?? {} + supressFailures: extensionGuestConfigurationExtension.?supressFailures ?? false + protectedSettings: extensionGuestConfigurationExtensionProtectedSettings + tags: extensionGuestConfigurationExtension.?tags ?? tags + } + dependsOn: [ + vm_hostPoolRegistrationExtension + ] +} + +resource AzureWindowsBaseline 'Microsoft.GuestConfiguration/guestConfigurationAssignments@2020-06-25' = if (!empty(guestConfiguration)) { + name: 'AzureWindowsBaseline' + scope: vm + dependsOn: [ + vm_azureGuestConfigurationExtension + ] + location: location + properties: { + guestConfiguration: guestConfiguration + } +} + +module vm_backup 'modules/protected-item.bicep' = if (!empty(backupVaultName)) { + name: '${uniqueString(deployment().name, location)}-VM-Backup' + params: { + name: 'vm;iaasvmcontainerv2;${resourceGroup().name};${vm.name}' + location: location + policyId: az.resourceId('Microsoft.RecoveryServices/vaults/backupPolicies', backupVaultName, backupPolicyName) + protectedItemType: 'Microsoft.Compute/virtualMachines' + protectionContainerName: 'iaasvmcontainer;iaasvmcontainerv2;${resourceGroup().name};${vm.name}' + recoveryVaultName: backupVaultName + sourceResourceId: vm.id + } + scope: az.resourceGroup(backupVaultResourceGroup) + dependsOn: [ + vm_azureGuestConfigurationExtension + ] +} + +resource vm_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: vm +} + +resource vm_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(vm.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: vm + } +] + +@description('The name of the VM.') +output name string = vm.name + +@description('The resource ID of the VM.') +output resourceId string = vm.id + +@description('The name of the resource group the VM was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string? = vm.?identity.?principalId + +@description('The location the resource was deployed into.') +output location string = vm.location + +// =============== // +// Definitions // +// =============== // + +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[]? +}? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type osDiskType = { + @description('Optional. The disk name.') + name: string? + + @description('Optional. Specifies the size of an empty data disk in gigabytes.') + diskSizeGB: int? + + @description('Optional. Specifies how the virtual machine should be created.') + createOption: 'Attach' | 'Empty' | 'FromImage'? + + @description('Optional. Specifies whether data disk should be deleted or detached upon VM deletion.') + deleteOption: 'Delete' | 'Detach'? + + @description('Optional. Specifies the caching requirements.') + caching: 'None' | 'ReadOnly' | 'ReadWrite'? + + @description('Required. The managed disk parameters.') + managedDisk: { + @description('Optional. Specifies the storage account type for the managed disk.') + storageAccountType: + | 'PremiumV2_LRS' + | 'Premium_LRS' + | 'Premium_ZRS' + | 'StandardSSD_LRS' + | 'StandardSSD_ZRS' + | 'Standard_LRS' + | 'UltraSSD_LRS'? + + @description('Optional. Specifies the customer managed disk encryption set resource id for the managed disk.') + diskEncryptionSetResourceId: string? + } +} + +type dataDisksType = { + @description('Optional. The disk name.') + name: string? + + @description('Optional. Specifies the logical unit number of the data disk.') + lun: int? + + @description('Required. Specifies the size of an empty data disk in gigabytes.') + diskSizeGB: int + + @description('Optional. Specifies how the virtual machine should be created.') + createOption: 'Attach' | 'Empty' | 'FromImage'? + + @description('Optional. Specifies whether data disk should be deleted or detached upon VM deletion.') + deleteOption: 'Delete' | 'Detach'? + + @description('Optional. Specifies the caching requirements.') + caching: 'None' | 'ReadOnly' | 'ReadWrite'? + + @description('Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes.') + diskIOPSReadWrite: int? + + @description('Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10.') + diskMBpsReadWrite: int? + + @description('Required. The managed disk parameters.') + managedDisk: { + @description('Required. Specifies the storage account type for the managed disk.') + storageAccountType: + | 'PremiumV2_LRS' + | 'Premium_LRS' + | 'Premium_ZRS' + | 'StandardSSD_LRS' + | 'StandardSSD_ZRS' + | 'Standard_LRS' + | 'UltraSSD_LRS' + + @description('Optional. Specifies the customer managed disk encryption set resource id for the managed disk.') + diskEncryptionSetResourceId: string? + + @description('Optional. Specifies the customer managed disk id for the managed disk.') + id: string? + } +}[]? diff --git a/avm/1.1.0/res/compute/virtual-machine/main.json b/avm/1.1.0/res/compute/virtual-machine/main.json new file mode 100644 index 000000000..04fbf9f84 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/main.json @@ -0,0 +1,5535 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "11202694269777473963" + }, + "name": "Virtual Machines", + "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs." + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "osDiskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } + }, + "diskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the size of an empty data disk in gigabytes." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + } + } + }, + "dataDisksType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } + }, + "lun": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the logical unit number of the data disk." + } + }, + "diskSizeGB": { + "type": "int", + "metadata": { + "description": "Required. Specifies the size of an empty data disk in gigabytes." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } + }, + "diskIOPSReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes." + } + }, + "diskMBpsReadWrite": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "metadata": { + "description": "Required. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + }, + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk id for the managed disk." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." + } + }, + "computerName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." + } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "Required. Specifies the size for the VMs." + } + }, + "encryptionAtHost": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "securityType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "ConfidentialVM", + "TrustedLaunch" + ], + "metadata": { + "description": "Optional. Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set." + } + }, + "secureBootEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "vTpmEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "imageReference": { + "type": "object", + "metadata": { + "description": "Required. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image." + } + }, + "plan": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." + } + }, + "osDisk": { + "$ref": "#/definitions/osDiskType", + "metadata": { + "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "dataDisks": { + "$ref": "#/definitions/dataDisksType", + "metadata": { + "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "ultraSSDEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." + } + }, + "adminUsername": { + "type": "securestring", + "metadata": { + "description": "Required. Administrator username." + } + }, + "adminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. When specifying a Windows Virtual Machine, this value should be passed." + } + }, + "userData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here." + } + }, + "customData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." + } + }, + "certificatesToBeInstalled": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." + } + }, + "priority": { + "type": "string", + "defaultValue": "Regular", + "allowedValues": [ + "Regular", + "Low", + "Spot" + ], + "metadata": { + "description": "Optional. Specifies the priority for the virtual machine." + } + }, + "enableEvictionPolicy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy." + } + }, + "maxPriceForLowPriorityVm": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." + } + }, + "dedicatedHostId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." + } + }, + "licenseType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "RHEL_BYOS", + "SLES_BYOS", + "Windows_Client", + "Windows_Server", + "" + ], + "metadata": { + "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." + } + }, + "publicKeys": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." + } + }, + "bootDiagnostics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." + } + }, + "bootDiagnosticStorageAccountName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." + } + }, + "bootDiagnosticStorageAccountUri": { + "type": "string", + "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", + "metadata": { + "description": "Optional. Storage account boot diagnostic base URI." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a proximity placement group." + } + }, + "virtualMachineScaleSetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." + } + }, + "availabilitySetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." + } + }, + "galleryApplications": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies the gallery applications that should be made available to the VM/VMSS." + } + }, + "zone": { + "type": "int", + "allowedValues": [ + 0, + 1, + 2, + 3 + ], + "metadata": { + "description": "Required. If set to 1, 2 or 3, the availability zone for all VMs is hardcoded to that value. If zero, then availability zones is not used. Cannot be used in combination with availability set nor scale set." + } + }, + "nicConfigurations": { + "type": "array", + "metadata": { + "description": "Required. Configures NICs and PIPs." + } + }, + "backupVaultName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Recovery service vault name to add VMs to backup." + } + }, + "backupVaultResourceGroup": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "DefaultPolicy", + "metadata": { + "description": "Optional. Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault." + } + }, + "autoShutdownConfig": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for auto-shutdown." + } + }, + "maintenanceConfigurationResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource Id of a maintenance configuration for this VM." + } + }, + "allowExtensionOperations": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." + } + }, + "extensionDomainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if name is specified. Password of the user specified in user parameter." + } + }, + "extensionDomainJoinConfig": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAadJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." + } + }, + "extensionAntiMalwareConfig": { + "type": "object", + "defaultValue": "[if(equals(parameters('osType'), 'Windows'), createObject('enabled', true()), createObject('enabled', false()))]", + "metadata": { + "description": "Optional. The configuration for the [Anti Malware] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionMonitoringAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "dataCollectionRuleAssociations": [] + }, + "metadata": { + "description": "Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionDependencyAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Dependency Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionNetworkWatcherAgentConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAzureDiskEncryptionConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." + } + }, + "extensionDSCConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "fileData": [] + }, + "metadata": { + "description": "Optional. The configuration for the [Custom Script] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionNvidiaGpuDriverWindows": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionHostPoolRegistration": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Host Pool Registration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identy." + } + }, + "extensionGuestConfigurationExtension": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Guest Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identy." + } + }, + "guestConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled." + } + }, + "extensionCustomScriptProtectedSetting": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. An object that contains the extension specific protected settings." + } + }, + "extensionGuestConfigurationExtensionProtectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. An object that contains the extension specific protected settings." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to generate a registration token." + } + }, + "sasTokenValidityLength": { + "type": "string", + "defaultValue": "PT8H", + "metadata": { + "description": "Optional. SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. The chosen OS type." + } + }, + "disablePasswordAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether password authentication should be disabled." + } + }, + "provisionVMAgent": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." + } + }, + "enableAutomaticUpdates": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." + } + }, + "patchMode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "AutomaticByPlatform", + "AutomaticByOS", + "Manual", + "ImageDefault", + "" + ], + "metadata": { + "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." + } + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables customer to schedule patching without accidental upgrades." + } + }, + "rebootSetting": { + "type": "string", + "defaultValue": "IfRequired", + "allowedValues": [ + "Always", + "IfRequired", + "Never", + "Unknown" + ], + "metadata": { + "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." + } + }, + "patchAssessmentMode": { + "type": "string", + "defaultValue": "ImageDefault", + "allowedValues": [ + "AutomaticByPlatform", + "ImageDefault" + ], + "metadata": { + "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." + } + }, + "enableHotpatching": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." + } + }, + "additionalUnattendContent": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." + } + }, + "winRM": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object." + } + }, + "configurationProfile": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." + } + } + }, + "variables": { + "copy": [ + { + "name": "publicKeysFormatted", + "count": "[length(parameters('publicKeys'))]", + "input": { + "path": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].path]", + "keyData": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].keyData]" + } + }, + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "linuxConfiguration": { + "disablePasswordAuthentication": "[parameters('disablePasswordAuthentication')]", + "ssh": { + "publicKeys": "[variables('publicKeysFormatted')]" + }, + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" + }, + "windowsConfiguration": { + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'enableHotpatching', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), parameters('enableHotpatching'), false()), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", + "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", + "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), parameters('additionalUnattendContent'))]", + "winRM": "[if(not(empty(parameters('winRM'))), createObject('listeners', parameters('winRM')), null())]" + }, + "accountSasProperties": { + "signedServices": "b", + "signedPermission": "r", + "signedExpiry": "[dateTimeAdd(parameters('baseTime'), parameters('sasTokenValidityLength'))]", + "signedResourceTypes": "o", + "signedProtocol": "https" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", + "Desktop Virtualization Power On Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33')]", + "Desktop Virtualization Power On Off Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e')]", + "Desktop Virtualization Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')]", + "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", + "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", + "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", + "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", + "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", + "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", + "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]", + "VM Scanner Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "managedDataDisks": { + "copy": { + "name": "managedDataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]" + }, + "type": "Microsoft.Compute/disks", + "apiVersion": "2024-03-02", + "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex(), 1), 2, '0')))]", + "location": "[parameters('location')]", + "sku": { + "name": "[coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk.storageAccountType]" + }, + "properties": { + "diskSizeGB": "[coalesce(parameters('dataDisks'), createArray())[copyIndex()].diskSizeGB]", + "creationData": { + "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createoption'), 'Empty')]" + }, + "diskIOPSReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskIOPSReadWrite')]", + "diskMBpsReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskMBpsReadWrite')]" + }, + "zones": "[if(not(equals(parameters('zone'), 0)), array(string(parameters('zone'))), null())]" + }, + "vm": { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2024-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "zones": "[if(not(equals(parameters('zone'), 0)), array(string(parameters('zone'))), null())]", + "plan": "[if(not(empty(parameters('plan'))), parameters('plan'), null())]", + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "securityProfile": { + "encryptionAtHost": "[if(parameters('encryptionAtHost'), parameters('encryptionAtHost'), null())]", + "securityType": "[parameters('securityType')]", + "uefiSettings": "[if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null())]" + }, + "storageProfile": { + "copy": [ + { + "name": "dataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", + "input": { + "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", + "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))]", + "diskSizeGB": "[coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].diskSizeGB]", + "createOption": "[if(not(equals(resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null())), 'Attach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createoption'), 'Empty'))]", + "deleteOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete')]", + "caching": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly')]", + "managedDisk": { + "storageAccountType": "[coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.storageAccountType]", + "id": "[resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0'))))]", + "diskEncryptionSet": { + "id": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId')]" + } + } + } + } + ], + "imageReference": "[parameters('imageReference')]", + "osDisk": { + "name": "[coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name')))]", + "createOption": "[coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage')]", + "deleteOption": "[coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete')]", + "diskSizeGB": "[parameters('osDisk').diskSizeGB]", + "caching": "[coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly')]", + "managedDisk": { + "storageAccountType": "[parameters('osDisk').managedDisk.storageAccountType]", + "diskEncryptionSet": { + "id": "[tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')]" + } + } + } + }, + "additionalCapabilities": { + "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]" + }, + "osProfile": { + "computerName": "[parameters('computerName')]", + "adminUsername": "[parameters('adminUsername')]", + "adminPassword": "[parameters('adminPassword')]", + "customData": "[if(not(empty(parameters('customData'))), base64(parameters('customData')), null())]", + "windowsConfiguration": "[if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null())]", + "linuxConfiguration": "[if(equals(parameters('osType'), 'Linux'), variables('linuxConfiguration'), null())]", + "secrets": "[parameters('certificatesToBeInstalled')]", + "allowExtensionOperations": "[parameters('allowExtensionOperations')]" + }, + "networkProfile": { + "copy": [ + { + "name": "networkInterfaces", + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "properties": { + "deleteOption": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), 'Delete')]", + "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" + }, + "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", + "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" + } + }, + "applicationProfile": "[if(not(empty(parameters('galleryApplications'))), createObject('galleryApplications', parameters('galleryApplications')), null())]", + "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", + "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", + "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", + "priority": "[parameters('priority')]", + "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", + "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", + "host": "[if(not(empty(parameters('dedicatedHostId'))), createObject('id', parameters('dedicatedHostId')), null())]", + "licenseType": "[if(not(empty(parameters('licenseType'))), parameters('licenseType'), null())]", + "userData": "[if(not(empty(parameters('userData'))), base64(parameters('userData')), null())]" + }, + "dependsOn": [ + "managedDataDisks", + "vm_nic" + ] + }, + "vm_configurationAssignment": { + "condition": "[not(empty(parameters('maintenanceConfigurationResourceId')))]", + "type": "Microsoft.Maintenance/configurationAssignments", + "apiVersion": "2023-04-01", + "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", + "name": "[format('{0}assignment', parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "maintenanceConfigurationId": "[parameters('maintenanceConfigurationResourceId')]", + "resourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_configurationProfileAssignment": { + "condition": "[not(empty(parameters('configurationProfile')))]", + "type": "Microsoft.Automanage/configurationProfileAssignments", + "apiVersion": "2022-05-04", + "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", + "name": "default", + "properties": { + "configurationProfile": "[parameters('configurationProfile')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_autoShutdownConfiguration": { + "condition": "[not(empty(parameters('autoShutdownConfig')))]", + "type": "Microsoft.DevTestLab/schedules", + "apiVersion": "2018-09-15", + "name": "[format('shutdown-computevm-{0}', parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", + "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", + "taskType": "ComputeVmShutdownTask", + "dailyRecurrence": { + "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" + }, + "timeZoneId": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'timeZone'), 'UTC')]", + "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationStatus'), createObject('status', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationStatus'), 'Disabled'), 'emailRecipient', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationEmail'), ''), 'notificationLocale', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationLocale'), 'en'), 'webhookUrl', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationWebhookUrl'), ''), 'timeInMinutes', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationTimeInMinutes'), 30)), null())]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_dataCollectionRuleAssociations": { + "copy": { + "name": "vm_dataCollectionRuleAssociations", + "count": "[length(parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations)]" + }, + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Insights/dataCollectionRuleAssociations", + "apiVersion": "2023-03-11", + "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", + "name": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].name]", + "properties": { + "dataCollectionRuleId": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].dataCollectionRuleResourceId]" + }, + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] + }, + "AzureWindowsBaseline": { + "condition": "[not(empty(parameters('guestConfiguration')))]", + "type": "Microsoft.GuestConfiguration/guestConfigurationAssignments", + "apiVersion": "2020-06-25", + "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", + "name": "AzureWindowsBaseline", + "location": "[parameters('location')]", + "properties": { + "guestConfiguration": "[parameters('guestConfiguration')]" + }, + "dependsOn": [ + "vm", + "vm_azureGuestConfigurationExtension" + ] + }, + "vm_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_roleAssignments": { + "copy": { + "name": "vm_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/virtualMachines', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_nic": { + "copy": { + "name": "vm_nic", + "count": "[length(parameters('nicConfigurations'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkInterfaceName": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex()], 'nicSuffix')))]" + }, + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableIPForwarding": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), false())]" + }, + "enableAcceleratedNetworking": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), true())]" + }, + "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(parameters('nicConfigurations')[copyIndex()].dnsServers)), createObject('value', parameters('nicConfigurations')[copyIndex()].dnsServers), createObject('value', createArray())), createObject('value', createArray()))]", + "networkSecurityGroupResourceId": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" + }, + "ipConfigurations": { + "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" + }, + "lock": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'lock'), parameters('lock'))]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "9361328819285350634" + } + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "networkInterfaceName": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + }, + "ipConfigurations": { + "type": "array" + }, + "location": { + "type": "string", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false + }, + "dnsServers": { + "type": "array", + "defaultValue": [] + }, + "enableTelemetry": { + "type": "bool", + "metadata": { + "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the Network Interface." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "resources": { + "networkInterface_publicIPAddresses": { + "copy": { + "name": "networkInterface_publicIPAddresses", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[and(contains(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), not(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIpNameSuffix')))]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'idleTimeoutInMinutes')]" + }, + "ddosSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'dnsSettings')]" + }, + "publicIPAddressVersion": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressVersion'), 'IPv4')]" + }, + "publicIPAllocationMethod": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAllocationMethod'), 'Static')]" + }, + "publicIpPrefixResourceId": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPPrefixResourceId'), '')]" + }, + "roleAssignments": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'roleAssignments'), createArray())]" + }, + "skuName": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuName'), 'Standard')]" + }, + "skuTier": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuTier'), 'Regional')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "zones": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createArray(1, 2, 3))]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "16693645977675862540" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "", + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "metadata": { + "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + } + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.6.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": null + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkInterface', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('networkInterfaceName')]" + }, + "ipConfigurations": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('ipConfigurations'))]", + "input": "[createObject('name', if(not(empty(parameters('ipConfigurations')[copyIndex('value')].name)), parameters('ipConfigurations')[copyIndex('value')].name, null()), 'primary', equals(copyIndex('value'), 0), 'privateIPAllocationMethod', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod, null()), null()), 'privateIPAddress', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('value')].privateIPAddress, null()), null()), 'publicIPAddressResourceId', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), if(not(contains(parameters('ipConfigurations')[copyIndex('value')].pipConfiguration, 'publicIPAddressResourceId')), resourceId('Microsoft.Network/publicIPAddresses', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')].pipConfiguration, 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(parameters('ipConfigurations')[copyIndex('value')].pipConfiguration, 'publicIpNameSuffix')))), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.publicIPAddressResourceId), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), null()), 'applicationSecurityGroups', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), null()), 'applicationGatewayBackendAddressPools', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), null()), 'gatewayLoadBalancer', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), null()), 'loadBalancerInboundNatRules', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), null()), 'privateIPAddressVersion', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), null()), 'virtualNetworkTaps', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'), null()))]" + } + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "dnsServers": "[if(not(empty(parameters('dnsServers'))), createObject('value', parameters('dnsServers')), createObject('value', createArray()))]", + "enableAcceleratedNetworking": { + "value": "[parameters('enableAcceleratedNetworking')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enableIPForwarding": { + "value": "[parameters('enableIPForwarding')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", + "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "9226998037927576702" + }, + "name": "Network Interface", + "description": "This module deploys a Network Interface.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the network interface." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "dnsServers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "auxiliaryMode": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Floating", + "MaxConnections", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "auxiliarySku": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "A1", + "A2", + "A4", + "A8", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "disableTcpStateTracking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "description": "Required. A list of IPConfigurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "ipConfigurations", + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].name, format('ipconfig0{0}', add(copyIndex('ipConfigurations'), 1)))]", + "properties": { + "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", + "privateIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod, null()), null())]", + "privateIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress, null()), null())]", + "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId, null())), createObject('id', parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId), null()), null())]", + "subnet": { + "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" + }, + "loadBalancerBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerBackendAddressPools, null())]", + "applicationSecurityGroups": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationSecurityGroups, null())]", + "applicationGatewayBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationGatewayBackendAddressPools, null())]", + "gatewayLoadBalancer": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].gatewayLoadBalancer, null())]", + "loadBalancerInboundNatRules": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerInboundNatRules, null())]", + "privateIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddressVersion, null())]", + "virtualNetworkTaps": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].virtualNetworkTaps, null())]" + } + } + } + ], + "auxiliaryMode": "[parameters('auxiliaryMode')]", + "auxiliarySku": "[parameters('auxiliarySku')]", + "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", + "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "enableIPForwarding": "[parameters('enableIPForwarding')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" + } + }, + "networkInterface_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_diagnosticSettings": { + "copy": { + "name": "networkInterface_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_roleAssignments": { + "copy": { + "name": "networkInterface_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkInterface" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed resource." + }, + "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed resource." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkInterface', '2023-04-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "networkInterface_publicIPAddresses" + ] + } + } + } + } + }, + "vm_aadJoinExtension": { + "condition": "[parameters('extensionAadJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "AADLogin" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.ActiveDirectory" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "10459557628823249787" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] + }, + "vm_domainJoinExtension": { + "condition": "[and(contains(parameters('extensionDomainJoinConfig'), 'enabled'), parameters('extensionDomainJoinConfig').enabled)]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DomainJoin" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "JsonADDomainExtension" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[parameters('extensionDomainJoinConfig').settings]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": { + "Password": "[parameters('extensionDomainJoinPassword')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "10459557628823249787" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_aadJoinExtension" + ] + }, + "vm_microsoftAntiMalwareExtension": { + "condition": "[parameters('extensionAntiMalwareConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-MicrosoftAntiMalware', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "MicrosoftAntiMalware" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": { + "value": "IaaSAntimalware" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'settings'), createObject('AntimalwareEnabled', 'true', 'Exclusions', createObject(), 'RealtimeProtectionEnabled', 'true', 'ScheduledScanSettings', createObject('day', '7', 'isEnabled', 'true', 'scanType', 'Quick', 'time', '120')))]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "10459557628823249787" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_domainJoinExtension" + ] + }, + "vm_azureMonitorAgentExtension": { + "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-AzureMonitorAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "AzureMonitorAgent" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Monitor" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureMonitorWindowsAgent'), createObject('value', 'AzureMonitorLinuxAgent'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.22', '1.29'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "10459557628823249787" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_microsoftAntiMalwareExtension" + ] + }, + "vm_dependencyAgentExtension": { + "condition": "[parameters('extensionDependencyAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-DependencyAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DependencyAgent" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Monitoring.DependencyAgent" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.10')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" + }, + "settings": { + "value": { + "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "10459557628823249787" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureMonitorAgentExtension" + ] + }, + "vm_networkWatcherAgentExtension": { + "condition": "[parameters('extensionNetworkWatcherAgentConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-NetworkWatcherAgent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "NetworkWatcherAgent" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.NetworkWatcher" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "10459557628823249787" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_dependencyAgentExtension" + ] + }, + "vm_desiredStateConfigurationExtension": { + "condition": "[parameters('extensionDSCConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DesiredStateConfiguration" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Powershell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "10459557628823249787" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_networkWatcherAgentExtension" + ] + }, + "vm_customScriptExtension": { + "condition": "[parameters('extensionCustomScriptConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "CustomScriptExtension" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": { + "copy": [ + { + "name": "fileUris", + "count": "[length(parameters('extensionCustomScriptConfig').fileData)]", + "input": "[if(contains(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')], 'storageAccountId'), format('{0}?{1}', parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri, listAccountSas(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].storageAccountId, '2019-04-01', variables('accountSasProperties')).accountSasToken), parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri)]" + } + ] + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": "[parameters('extensionCustomScriptProtectedSetting')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "10459557628823249787" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_desiredStateConfigurationExtension" + ] + }, + "vm_azureDiskEncryptionExtension": { + "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "AzureDiskEncryption" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "10459557628823249787" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_customScriptExtension" + ] + }, + "vm_nvidiaGpuDriverWindowsExtension": { + "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "NvidiaGpuDriverWindows" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.HpcCompute" + }, + "type": { + "value": "NvidiaGpuDriverWindows" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), false())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "10459557628823249787" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureDiskEncryptionExtension" + ] + }, + "vm_hostPoolRegistrationExtension": { + "condition": "[parameters('extensionHostPoolRegistration').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-HostPoolRegistration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "HostPoolRegistration" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.PowerShell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": { + "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", + "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]", + "properties": { + "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", + "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]", + "aadJoin": true + }, + "supressFailures": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'supressFailures'), false())]" + } + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "10459557628823249787" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_nvidiaGpuDriverWindowsExtension" + ] + }, + "vm_azureGuestConfigurationExtension": { + "condition": "[parameters('extensionGuestConfigurationExtension').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-GuestConfiguration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzurePolicyforWindows'), createObject('value', 'AzurePolicyforLinux'))]", + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.GuestConfiguration" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), true())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" + }, + "protectedSettings": { + "value": "[parameters('extensionGuestConfigurationExtensionProtectedSettings')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "10459557628823249787" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension." + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_hostPoolRegistrationExtension" + ] + }, + "vm_backup": { + "condition": "[not(empty(parameters('backupVaultName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-Backup', uniqueString(deployment().name, parameters('location')))]", + "resourceGroup": "[parameters('backupVaultResourceGroup')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('vm;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "policyId": { + "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupPolicies', parameters('backupVaultName'), parameters('backupPolicyName'))]" + }, + "protectedItemType": { + "value": "Microsoft.Compute/virtualMachines" + }, + "protectionContainerName": { + "value": "[format('iaasvmcontainer;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" + }, + "recoveryVaultName": { + "value": "[parameters('backupVaultName')]" + }, + "sourceResourceId": { + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "16309659094506585930" + }, + "name": "Recovery Service Vaults Protection Container Protected Item", + "description": "This module deploys a Recovery Services Vault Protection Container Protected Item." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the resource." + } + }, + "protectionContainerName": { + "type": "string", + "metadata": { + "description": "Conditional. Name of the Azure Recovery Service Vault Protection Container. Required if the template is used in a standalone deployment." + } + }, + "recoveryVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Recovery Service Vault. Required if the template is used in a standalone deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "protectedItemType": { + "type": "string", + "allowedValues": [ + "AzureFileShareProtectedItem", + "AzureVmWorkloadSAPAseDatabase", + "AzureVmWorkloadSAPHanaDatabase", + "AzureVmWorkloadSQLDatabase", + "DPMProtectedItem", + "GenericProtectedItem", + "MabFileFolderProtectedItem", + "Microsoft.ClassicCompute/virtualMachines", + "Microsoft.Compute/virtualMachines", + "Microsoft.Sql/servers/databases" + ], + "metadata": { + "description": "Required. The backup item type." + } + }, + "policyId": { + "type": "string", + "metadata": { + "description": "Required. ID of the backup policy with which this item is backed up." + } + }, + "sourceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the resource to back up." + } + } + }, + "resources": [ + { + "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems", + "apiVersion": "2023-01-01", + "name": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "protectedItemType": "[parameters('protectedItemType')]", + "policyId": "[parameters('policyId')]", + "sourceResourceId": "[parameters('sourceResourceId')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the protected item was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the protected item." + }, + "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems', split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[0], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[1], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[2], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[3])]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The Name of the protected item." + }, + "value": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureGuestConfigurationExtension" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the VM." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the VM." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the VM was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('vm', '2024-07-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vm', '2024-07-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/compute/virtual-machine/modules/nic-configuration.bicep b/avm/1.1.0/res/compute/virtual-machine/modules/nic-configuration.bicep new file mode 100644 index 000000000..9c6bad736 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/modules/nic-configuration.bicep @@ -0,0 +1,186 @@ +param networkInterfaceName string +param virtualMachineName string +param ipConfigurations array + +@description('Optional. Location for all resources.') +param location string + +@description('Optional. Tags of the resource.') +param tags object? + +param enableIPForwarding bool = false +param enableAcceleratedNetworking bool = false +param dnsServers array = [] + +@description('Required. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableTelemetry bool + +@description('Optional. The network security group (NSG) to attach to the network interface.') +param networkSecurityGroupResourceId string = '' + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. The diagnostic settings of the Network Interface.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +module networkInterface_publicIPAddresses 'br/public:avm/res/network/public-ip-address:0.6.0' = [ + for (ipConfiguration, index) in ipConfigurations: if (contains(ipConfiguration, 'pipConfiguration') && !contains( + ipConfiguration.pipConfiguration, + 'publicIPAddressResourceId' + )) { + name: '${deployment().name}-publicIP-${index}' + params: { + name: ipConfiguration.pipConfiguration.?name ?? '${virtualMachineName}${ipConfiguration.pipConfiguration.?publicIpNameSuffix}' + diagnosticSettings: ipConfiguration.?diagnosticSettings + location: location + lock: lock + idleTimeoutInMinutes: ipConfiguration.pipConfiguration.?idleTimeoutInMinutes + ddosSettings: ipConfiguration.pipConfiguration.?ddosSettings + dnsSettings: ipConfiguration.pipConfiguration.?dnsSettings + publicIPAddressVersion: ipConfiguration.pipConfiguration.?publicIPAddressVersion ?? 'IPv4' + publicIPAllocationMethod: ipConfiguration.pipConfiguration.?publicIPAllocationMethod ?? 'Static' + publicIpPrefixResourceId: ipConfiguration.pipConfiguration.?publicIPPrefixResourceId ?? '' + roleAssignments: ipConfiguration.pipConfiguration.?roleAssignments ?? [] + skuName: ipConfiguration.pipConfiguration.?skuName ?? 'Standard' + skuTier: ipConfiguration.pipConfiguration.?skuTier ?? 'Regional' + tags: ipConfiguration.?tags ?? tags + zones: ipConfiguration.pipConfiguration.?zones ?? [ + 1 + 2 + 3 + ] + enableTelemetry: ipConfiguration.?enableTelemetry ?? enableTelemetry + } + } +] + +module networkInterface 'br/public:avm/res/network/network-interface:0.4.0' = { + name: '${deployment().name}-NetworkInterface' + params: { + name: networkInterfaceName + ipConfigurations: [ + for (ipConfiguration, index) in ipConfigurations: { + name: !empty(ipConfiguration.name) ? ipConfiguration.name : null + primary: index == 0 + privateIPAllocationMethod: contains(ipConfiguration, 'privateIPAllocationMethod') + ? (!empty(ipConfiguration.privateIPAllocationMethod) ? ipConfiguration.privateIPAllocationMethod : null) + : null + privateIPAddress: contains(ipConfiguration, 'privateIPAddress') + ? (!empty(ipConfiguration.privateIPAddress) ? ipConfiguration.privateIPAddress : null) + : null + publicIPAddressResourceId: contains(ipConfiguration, 'pipConfiguration') + ? !contains(ipConfiguration.pipConfiguration, 'publicIPAddressResourceId') + ? resourceId( + 'Microsoft.Network/publicIPAddresses', + ipConfiguration.pipConfiguration.?name ?? '${virtualMachineName}${ipConfiguration.pipConfiguration.?publicIpNameSuffix}' + ) + : ipConfiguration.pipConfiguration.publicIPAddressResourceId + : null + subnetResourceId: ipConfiguration.subnetResourceId + loadBalancerBackendAddressPools: ipConfiguration.?loadBalancerBackendAddressPools ?? null + applicationSecurityGroups: ipConfiguration.?applicationSecurityGroups ?? null + applicationGatewayBackendAddressPools: ipConfiguration.?applicationGatewayBackendAddressPools ?? null + gatewayLoadBalancer: ipConfiguration.?gatewayLoadBalancer ?? null + loadBalancerInboundNatRules: ipConfiguration.?loadBalancerInboundNatRules ?? null + privateIPAddressVersion: ipConfiguration.?privateIPAddressVersion ?? null + virtualNetworkTaps: ipConfiguration.?virtualNetworkTaps ?? null + } + ] + location: location + tags: tags + diagnosticSettings: diagnosticSettings + dnsServers: !empty(dnsServers) ? dnsServers : [] + enableAcceleratedNetworking: enableAcceleratedNetworking + enableTelemetry: enableTelemetry + enableIPForwarding: enableIPForwarding + lock: lock + networkSecurityGroupResourceId: !empty(networkSecurityGroupResourceId) ? networkSecurityGroupResourceId : '' + roleAssignments: !empty(roleAssignments) ? roleAssignments : [] + } + dependsOn: [ + networkInterface_publicIPAddresses + ] +} + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? + +type roleAssignmentType = { + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/compute/virtual-machine/modules/protected-item.bicep b/avm/1.1.0/res/compute/virtual-machine/modules/protected-item.bicep new file mode 100644 index 000000000..781a46df5 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/modules/protected-item.bicep @@ -0,0 +1,54 @@ +metadata name = 'Recovery Service Vaults Protection Container Protected Item' +metadata description = 'This module deploys a Recovery Services Vault Protection Container Protected Item.' + +@description('Required. Name of the resource.') +param name string + +@description('Conditional. Name of the Azure Recovery Service Vault Protection Container. Required if the template is used in a standalone deployment.') +param protectionContainerName string + +@description('Conditional. The name of the parent Azure Recovery Service Vault. Required if the template is used in a standalone deployment.') +param recoveryVaultName string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@allowed([ + 'AzureFileShareProtectedItem' + 'AzureVmWorkloadSAPAseDatabase' + 'AzureVmWorkloadSAPHanaDatabase' + 'AzureVmWorkloadSQLDatabase' + 'DPMProtectedItem' + 'GenericProtectedItem' + 'MabFileFolderProtectedItem' + 'Microsoft.ClassicCompute/virtualMachines' + 'Microsoft.Compute/virtualMachines' + 'Microsoft.Sql/servers/databases' +]) +@description('Required. The backup item type.') +param protectedItemType string + +@description('Required. ID of the backup policy with which this item is backed up.') +param policyId string + +@description('Required. Resource ID of the resource to back up.') +param sourceResourceId string + +resource protectedItem 'Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems@2023-01-01' = { + name: '${recoveryVaultName}/Azure/${protectionContainerName}/${name}' + location: location + properties: { + protectedItemType: any(protectedItemType) + policyId: policyId + sourceResourceId: sourceResourceId + } +} + +@description('The name of the Resource Group the protected item was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the protected item.') +output resourceId string = protectedItem.id + +@description('The Name of the protected item.') +output name string = protectedItem.name diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/atmg/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/atmg/dependencies.bicep new file mode 100644 index 000000000..b71a7c79a --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/atmg/dependencies.bicep @@ -0,0 +1,89 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Deployment Script to create for the SSH Key generation.') +param sshDeploymentScriptName string + +@description('Required. The name of the SSH Key to create.') +param sshKeyName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource msiRGContrRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalType: 'ServicePrincipal' + } +} + +resource sshDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: sshDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.0' + retentionInterval: 'P1D' + arguments: ' -SSHKeyName "${sshKeyName}" -ResourceGroupName "${resourceGroup().name}"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/New-SSHKey.ps1') + } + dependsOn: [ + msiRGContrRoleAssignment + ] +} + +resource sshKey 'Microsoft.Compute/sshPublicKeys@2022-03-01' = { + name: sshKeyName + location: location + properties: { + publicKey: sshDeploymentScript.properties.outputs.publicKey + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The Public Key of the created SSH Key.') +output SSHKeyPublicKey string = sshKey.properties.publicKey diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/atmg/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/atmg/main.test.bicep new file mode 100644 index 000000000..fcfd8d428 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/atmg/main.test.bicep @@ -0,0 +1,113 @@ +// WARNING: this test is disabled, as there is an known issue on Azure, preventing deployment, see https://techcommunity.microsoft.com/t5/azure-infrastructure/enabling-azure-automanage-or-creating-a-custom-configuration/m-p/4251861 +targetScope = 'subscription' + +metadata name = 'Using automanage for the VM.' +metadata description = 'This instance deploys the module with registering to an automation account.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmlinatmg' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + sshDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}' + sshKeyName: 'dep-${namePrefix}-ssh-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +// resource sshKey 'Microsoft.Compute/sshPublicKeys@2022-03-01' existing = { +// name: sshKeyName +// scope: resourceGroup +// } + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: if (false) { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + location: enforcedLocation + name: '${namePrefix}${serviceShort}' + adminUsername: 'localAdminUser' + imageReference: { + publisher: 'Canonical' + offer: '0001-com-ubuntu-server-jammy' + sku: '22_04-lts-gen2' + version: 'latest' + } + zone: 0 + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [ + 1 + 2 + 3 + ] + } + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Linux' + vmSize: 'Standard_D2s_v3' + configurationProfile: '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction' + disablePasswordAuthentication: true + publicKeys: [ + { + keyData: nestedDependencies.outputs.SSHKeyPublicKey + path: '/home/localAdminUser/.ssh/authorized_keys' + } + ] + } + dependsOn: [ + nestedDependencies // Required to leverage `existing` SSH key reference + ] + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.defaults/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.defaults/dependencies.bicep new file mode 100644 index 000000000..c9a69d0b5 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.defaults/dependencies.bicep @@ -0,0 +1,89 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Deployment Script to create for the SSH Key generation.') +param sshDeploymentScriptName string + +@description('Required. The name of the SSH Key to create.') +param sshKeyName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource msiRGContrRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalType: 'ServicePrincipal' + } +} + +resource sshDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: sshDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.0' + retentionInterval: 'P1D' + arguments: '-SSHKeyName "${sshKeyName}" -ResourceGroupName "${resourceGroup().name}"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/New-SSHKey.ps1') + } + dependsOn: [ + msiRGContrRoleAssignment + ] +} + +resource sshKey 'Microsoft.Compute/sshPublicKeys@2022-03-01' = { + name: sshKeyName + location: location + properties: { + publicKey: sshDeploymentScript.properties.outputs.publicKey + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The Public Key of the created SSH Key.') +output SSHKeyPublicKey string = sshKey.properties.publicKey diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.defaults/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.defaults/main.test.bicep new file mode 100644 index 000000000..16959ce77 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.defaults/main.test.bicep @@ -0,0 +1,107 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults for Linux' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmlinmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + sshDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}' + sshKeyName: 'dep-${namePrefix}-ssh-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +// resource sshKey 'Microsoft.Compute/sshPublicKeys@2022-03-01' existing = { +// name: sshKeyName +// scope: resourceGroup +// } + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + location: enforcedLocation + name: '${namePrefix}${serviceShort}' + adminUsername: 'localAdminUser' + imageReference: { + publisher: 'Canonical' + offer: '0001-com-ubuntu-server-jammy' + sku: '22_04-lts-gen2' + version: 'latest' + } + zone: 0 + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + pipConfiguration: { + name: 'pip-01' + } + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + diskSizeGB: 128 + caching: 'ReadWrite' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Linux' + vmSize: 'Standard_D2s_v3' + disablePasswordAuthentication: true + publicKeys: [ + { + keyData: nestedDependencies.outputs.SSHKeyPublicKey + path: '/home/localAdminUser/.ssh/authorized_keys' + } + ] + } + dependsOn: [ + nestedDependencies // Required to leverage `existing` SSH key reference + ] + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.max/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.max/dependencies.bicep new file mode 100644 index 000000000..18b139f47 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.max/dependencies.bicep @@ -0,0 +1,457 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Application Security Group to create.') +param applicationSecurityGroupName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Load Balancer to create.') +param loadBalancerName string + +@description('Required. The name of the Recovery Services Vault to create.') +param recoveryServicesVaultName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Deployment Script used to upload data to the Storage Account.') +param storageUploadDeploymentScriptName string + +@description('Required. The name of the Deployment Script to create for the SSH Key generation.') +param sshDeploymentScriptName string + +@description('Required. The name of the SSH Key to create.') +param sshKeyName string + +@description('Required. The name of the data collection rule.') +param dcrName string + +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The object ID of the Backup Management Service Enterprise Application.') +param backupManagementServiceApplicationObjectId string + +@description('Required. Resource ID of the log analytics worspace to stream logs from Azure monitoring agent.') +param logAnalyticsWorkspaceResourceId string + +var storageAccountCSEFileName = 'scriptExtensionMasterInstaller.ps1' +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource applicationSecurityGroup 'Microsoft.Network/applicationSecurityGroups@2023-04-01' = { + name: applicationSecurityGroupName + location: location +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource msiRGContrRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalType: 'ServicePrincipal' + } +} + +resource loadBalancer 'Microsoft.Network/loadBalancers@2023-04-01' = { + name: loadBalancerName + location: location + sku: { + name: 'Standard' + } + properties: { + frontendIPConfigurations: [ + { + name: 'privateIPConfig1' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + backendAddressPools: [ + { + name: 'servers' + } + ] + } +} + +resource recoveryServicesVault 'Microsoft.RecoveryServices/vaults@2022-04-01' = { + name: recoveryServicesVaultName + location: location + sku: { + name: 'RS0' + tier: 'Standard' + } + properties: {} + + resource backupPolicy 'backupPolicies@2022-03-01' = { + name: 'backupPolicy' + properties: { + backupManagementType: 'AzureIaasVM' + instantRPDetails: {} + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunFrequency: 'Daily' + scheduleRunTimes: [ + '2019-11-07T07:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + retentionPolicy: { + retentionPolicyType: 'LongTermRetentionPolicy' + dailySchedule: { + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + retentionDuration: { + count: 180 + durationType: 'Days' + } + } + weeklySchedule: { + daysOfTheWeek: [ + 'Sunday' + ] + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + retentionDuration: { + count: 12 + durationType: 'Weeks' + } + } + monthlySchedule: { + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + retentionDuration: { + count: 60 + durationType: 'Months' + } + } + yearlySchedule: { + retentionScheduleFormatType: 'Weekly' + monthsOfYear: [ + 'January' + ] + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + retentionDuration: { + count: 10 + durationType: 'Years' + } + } + } + instantRpRetentionRangeInDays: 2 + timeZone: 'UTC' + protectedItemsCount: 0 + } + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'encryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource backupServiceKeyVaultPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('${keyVault.name}-${location}-BackupManagementService-KeyVault-KeyVaultAdministrator-RoleAssignment') + scope: keyVault + properties: { + principalId: backupManagementServiceApplicationObjectId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '00482a5a-887f-4fb3-b363-3b7fe8e74483' + ) // Key Vault Administrator + principalType: 'ServicePrincipal' + } +} + +resource msiKVCryptoUserRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-KeyVault-Key-Read-RoleAssignment') + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + + resource blobService 'blobServices@2021-09-01' = { + name: 'default' + + resource container 'containers@2021-09-01' = { + name: 'scripts' + } + } +} + +resource storageUpload 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: storageUploadDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.0' + retentionInterval: 'P1D' + arguments: '-StorageAccountName "${storageAccount.name}" -ResourceGroupName "${resourceGroup().name}" -ContainerName "${storageAccount::blobService::container.name}" -FileName "${storageAccountCSEFileName}"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Set-BlobContent.ps1') + } + dependsOn: [ + msiRGContrRoleAssignment + ] +} + +resource sshDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: sshDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.0' + retentionInterval: 'P1D' + arguments: '-SSHKeyName "${sshKeyName}" -ResourceGroupName "${resourceGroup().name}"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/New-SSHKey.ps1') + } + dependsOn: [ + msiRGContrRoleAssignment + ] +} + +resource sshKey 'Microsoft.Compute/sshPublicKeys@2022-03-01' = { + name: sshKeyName + location: location + properties: { + publicKey: sshDeploymentScript.properties.outputs.publicKey + } +} + +resource dcr 'Microsoft.Insights/dataCollectionRules@2023-03-11' = { + name: dcrName + location: location + kind: 'Linux' + properties: { + dataSources: { + performanceCounters: [ + { + streams: [ + 'Microsoft-Perf' + ] + samplingFrequencyInSeconds: 60 + counterSpecifiers: [ + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Processes' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Handle Count' + '\\System\\System Up Time' + '\\System\\Context Switches/sec' + '\\System\\Processor Queue Length' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pages/sec' + '\\Memory\\Page Faults/sec' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + ] + name: 'perfCounterDataSource60' + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: logAnalyticsWorkspaceResourceId + name: 'la--1264800308' + } + ] + } + dataFlows: [ + { + streams: [ + 'Microsoft-Perf' + ] + destinations: [ + 'la--1264800308' + ] + transformKql: 'source' + outputStream: 'Microsoft-Perf' + } + ] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Application Security Group.') +output applicationSecurityGroupResourceId string = applicationSecurityGroup.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Load Balancer Backend Pool.') +output loadBalancerBackendPoolResourceId string = loadBalancer.properties.backendAddressPools[0].id + +@description('The name of the created Recovery Services Vault.') +output recoveryServicesVaultName string = recoveryServicesVault.name + +@description('The name of the Resource Group, the Recovery Services Vault was created in.') +output recoveryServicesVaultResourceGroupName string = resourceGroup().name + +@description('The name of the Backup Policy created in the Backup Recovery Vault.') +output recoveryServicesVaultBackupPolicyName string = recoveryServicesVault::backupPolicy.name + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The URL of the created Key Vault.') +output keyVaultUrl string = keyVault.properties.vaultUri + +@description('The URL of the created Key Vault Encryption Key.') +output keyVaultEncryptionKeyUrl string = keyVault::key.properties.keyUriWithVersion + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id + +@description('The URL of the Custom Script Extension in the created Storage Account.') +output storageAccountCSEFileUrl string = '${storageAccount.properties.primaryEndpoints.blob}${storageAccount::blobService::container.name}/${storageAccountCSEFileName}' + +@description('The name of the Custom Script Extension in the created Storage Account.') +output storageAccountCSEFileName string = storageAccountCSEFileName + +@description('The Public Key of the created SSH Key.') +output SSHKeyPublicKey string = sshKey.properties.publicKey + +@description('The resource ID of the created data collection rule.') +output dataCollectionRuleResourceId string = dcr.id diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.max/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.max/main.test.bicep new file mode 100644 index 000000000..1bc3a44a3 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/linux.max/main.test.bicep @@ -0,0 +1,364 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set for Linux' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmlinmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Required. The object id of the Backup Management Service Enterprise Application. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-BackupManagementServiceEnterpriseApplicationObjectId\'.') +@secure() +param backupManagementServiceEnterpriseApplicationObjectId string = '' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + applicationSecurityGroupName: 'dep-${namePrefix}-asg-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + loadBalancerName: 'dep-${namePrefix}-lb-${serviceShort}' + recoveryServicesVaultName: 'dep-${namePrefix}-rsv-${serviceShort}' + storageAccountName: 'dep${namePrefix}sa${serviceShort}01' + storageUploadDeploymentScriptName: 'dep-${namePrefix}-sads-${serviceShort}' + sshDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}' + sshKeyName: 'dep-${namePrefix}-ssh-${serviceShort}' + dcrName: 'dep-${namePrefix}-dcr-${serviceShort}' + backupManagementServiceApplicationObjectId: backupManagementServiceEnterpriseApplicationObjectId + logAnalyticsWorkspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: enforcedLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}' + computerName: '${namePrefix}linvm1' + location: enforcedLocation + adminUsername: 'localAdministrator' + imageReference: { + publisher: 'Canonical' + offer: '0001-com-ubuntu-server-focal' + sku: '20_04-lts-gen2' // Note: 22.04 does not support OMS extension + version: 'latest' + } + nicConfigurations: [ + { + deleteOption: 'Delete' + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: nestedDependencies.outputs.applicationSecurityGroupResourceId + } + ] + loadBalancerBackendAddressPools: [ + { + id: nestedDependencies.outputs.loadBalancerBackendPoolResourceId + } + ] + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [ + 1 + 2 + 3 + ] + roleAssignments: [ + { + name: '696e6067-3ddc-4b71-bf97-9caebeba441a' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + subnetResourceId: nestedDependencies.outputs.subnetResourceId + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + ] + name: 'nic-test-01' + roleAssignments: [ + { + name: 'ff72f58d-a3cf-42fd-9c27-c61906bdddfe' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + ] + osDisk: { + name: 'osdisk01' + caching: 'ReadOnly' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Linux' + vmSize: 'Standard_D2s_v3' + zone: 1 + backupPolicyName: nestedDependencies.outputs.recoveryServicesVaultBackupPolicyName + backupVaultName: nestedDependencies.outputs.recoveryServicesVaultName + backupVaultResourceGroup: nestedDependencies.outputs.recoveryServicesVaultResourceGroupName + dataDisks: [ + { + name: 'datadisk01' + caching: 'ReadWrite' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + { + name: 'datadisk02' + caching: 'ReadWrite' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + ] + enableAutomaticUpdates: true + patchMode: 'AutomaticByPlatform' + rebootSetting: 'IfRequired' + disablePasswordAuthentication: true + encryptionAtHost: false + extensionCustomScriptConfig: { + enabled: true + fileData: [ + { + storageAccountId: nestedDependencies.outputs.storageAccountResourceId + uri: nestedDependencies.outputs.storageAccountCSEFileUrl + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionCustomScriptProtectedSetting: { + commandToExecute: 'value=$(./${nestedDependencies.outputs.storageAccountCSEFileName}); echo "$value"' + } + extensionDependencyAgentConfig: { + enabled: true + enableAMA: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionAzureDiskEncryptionConfig: { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: nestedDependencies.outputs.keyVaultEncryptionKeyUrl + KeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + KeyVaultURL: nestedDependencies.outputs.keyVaultUrl + ResizeOSDisk: 'false' + VolumeType: 'All' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionAadJoinConfig: { + enabled: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionDSCConfig: { + enabled: false + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionMonitoringAgentConfig: { + enabled: true + dataCollectionRuleAssociations: [ + { + name: 'SendMetricsToLAW' + dataCollectionRuleResourceId: nestedDependencies.outputs.dataCollectionRuleResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionNetworkWatcherAgentConfig: { + enabled: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + publicKeys: [ + { + keyData: nestedDependencies.outputs.SSHKeyPublicKey + path: '/home/localAdministrator/.ssh/authorized_keys' + } + ] + roleAssignments: [ + { + name: 'eb01de52-d2be-4272-a7b9-13de6c399e27' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies // Required to leverage `existing` SSH key reference + ] +} diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..c7ddd01f8 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,469 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Maintenance Configuration to create.') +param maintenanceConfigurationName string + +@description('Required. The name of the Application Security Group to create.') +param applicationSecurityGroupName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Load Balancer to create.') +param loadBalancerName string + +@description('Required. The name of the Recovery Services Vault to create.') +param recoveryServicesVaultName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Deployment Script used to upload data to the Storage Account.') +param storageUploadDeploymentScriptName string + +@description('Required. The name of the Proximity Placement Group to create.') +param proximityPlacementGroupName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The object ID of the Backup Management Service Enterprise Application.') +param backupManagementServiceApplicationObjectId string + +@description('Required. The name of the data collection rule.') +param dcrName string + +@description('Required. Resource ID of the log analytics worspace to stream logs from Azure monitoring agent.') +param logAnalyticsWorkspaceResourceId string + +var storageAccountCSEFileName = 'scriptExtensionMasterInstaller.ps1' +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource maintenanceConfiguration 'Microsoft.Maintenance/maintenanceConfigurations@2023-10-01-preview' = { + name: maintenanceConfigurationName + location: location + properties: { + extensionProperties: { + InGuestPatchMode: 'User' + } + maintenanceScope: 'InGuestPatch' + maintenanceWindow: { + startDateTime: '2024-06-16 00:00' + duration: '03:55' + timeZone: 'W. Europe Standard Time' + recurEvery: '1Day' + } + visibility: 'Custom' + installPatches: { + rebootSetting: 'IfRequired' + windowsParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } + linuxParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } + } + } +} + +resource applicationSecurityGroup 'Microsoft.Network/applicationSecurityGroups@2023-04-01' = { + name: applicationSecurityGroupName + location: location +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource msiRGContrRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalType: 'ServicePrincipal' + } +} + +resource loadBalancer 'Microsoft.Network/loadBalancers@2023-04-01' = { + name: loadBalancerName + location: location + sku: { + name: 'Standard' + } + properties: { + frontendIPConfigurations: [ + { + name: 'privateIPConfig1' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + backendAddressPools: [ + { + name: 'servers' + } + ] + } +} + +resource recoveryServicesVault 'Microsoft.RecoveryServices/vaults@2022-04-01' = { + name: recoveryServicesVaultName + location: location + sku: { + name: 'RS0' + tier: 'Standard' + } + properties: {} + + resource backupPolicy 'backupPolicies@2022-03-01' = { + name: 'backupPolicy' + properties: { + backupManagementType: 'AzureIaasVM' + instantRPDetails: {} + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunFrequency: 'Daily' + scheduleRunTimes: [ + '2019-11-07T07:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + retentionPolicy: { + retentionPolicyType: 'LongTermRetentionPolicy' + dailySchedule: { + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + retentionDuration: { + count: 180 + durationType: 'Days' + } + } + weeklySchedule: { + daysOfTheWeek: [ + 'Sunday' + ] + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + retentionDuration: { + count: 12 + durationType: 'Weeks' + } + } + monthlySchedule: { + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + retentionDuration: { + count: 60 + durationType: 'Months' + } + } + yearlySchedule: { + retentionScheduleFormatType: 'Weekly' + monthsOfYear: [ + 'January' + ] + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + retentionDuration: { + count: 10 + durationType: 'Years' + } + } + } + instantRpRetentionRangeInDays: 2 + timeZone: 'UTC' + protectedItemsCount: 0 + } + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'encryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource backupServiceKeyVaultPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('${keyVault.name}-${location}-BackupManagementService-KeyVault-KeyVaultAdministrator-RoleAssignment') + scope: keyVault + properties: { + principalId: backupManagementServiceApplicationObjectId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '00482a5a-887f-4fb3-b363-3b7fe8e74483' + ) // Key Vault Administrator + principalType: 'ServicePrincipal' + } +} + +resource msiKVReadRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-KeyVault-Key-Read-RoleAssignment') + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + + resource blobService 'blobServices@2021-09-01' = { + name: 'default' + + resource container 'containers@2021-09-01' = { + name: 'scripts' + } + } +} + +resource storageUpload 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: storageUploadDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.0' + retentionInterval: 'P1D' + arguments: '-StorageAccountName ${storageAccount.name} -ResourceGroupName ${resourceGroup().name} -ContainerName ${storageAccount::blobService::container.name} -FileName ${storageAccountCSEFileName}' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Set-BlobContent.ps1') + } + dependsOn: [ + msiRGContrRoleAssignment + ] +} + +resource proximityPlacementGroup 'Microsoft.Compute/proximityPlacementGroups@2022-03-01' = { + name: proximityPlacementGroupName + location: location +} + +resource dcr 'Microsoft.Insights/dataCollectionRules@2023-03-11' = { + name: dcrName + location: location + kind: 'Windows' + properties: { + dataSources: { + performanceCounters: [ + { + streams: [ + 'Microsoft-Perf' + ] + samplingFrequencyInSeconds: 60 + counterSpecifiers: [ + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Processes' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Handle Count' + '\\System\\System Up Time' + '\\System\\Context Switches/sec' + '\\System\\Processor Queue Length' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pages/sec' + '\\Memory\\Page Faults/sec' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + ] + name: 'perfCounterDataSource60' + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: logAnalyticsWorkspaceResourceId + name: 'la--1264800308' + } + ] + } + dataFlows: [ + { + streams: [ + 'Microsoft-Perf' + ] + destinations: [ + 'la--1264800308' + ] + transformKql: 'source' + outputStream: 'Microsoft-Perf' + } + ] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the maintenance configuration.') +output maintenanceConfigurationResourceId string = maintenanceConfiguration.id + +@description('The resource ID of the created Application Security Group.') +output applicationSecurityGroupResourceId string = applicationSecurityGroup.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Load Balancer Backend Pool.') +output loadBalancerBackendPoolResourceId string = loadBalancer.properties.backendAddressPools[0].id + +@description('The name of the created Recovery Services Vault.') +output recoveryServicesVaultName string = recoveryServicesVault.name + +@description('The name of the Resource Group, the Recovery Services Vault was created in.') +output recoveryServicesVaultResourceGroupName string = resourceGroup().name + +@description('The name of the Backup Policy created in the Backup Recovery Vault.') +output recoveryServicesVaultBackupPolicyName string = recoveryServicesVault::backupPolicy.name + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The URL of the created Key Vault.') +output keyVaultUrl string = keyVault.properties.vaultUri + +@description('The URL of the created Key Vault Encryption Key.') +output keyVaultEncryptionKeyUrl string = keyVault::key.properties.keyUriWithVersion + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id + +@description('The name of the Custom Script Extension in the created Storage Account.') +output storageAccountCSEFileName string = storageAccountCSEFileName + +@description('The URL of the Custom Script Extension in the created Storage Account') +output storageAccountCSEFileUrl string = '${storageAccount.properties.primaryEndpoints.blob}${storageAccount::blobService::container.name}/${storageAccountCSEFileName}' + +@description('The resource ID of the created Proximity Placement Group.') +output proximityPlacementGroupResourceId string = proximityPlacementGroup.id + +@description('The resource ID of the created data collection rule.') +output dataCollectionRuleResourceId string = dcr.id diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..8d4a7ff38 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,354 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework for Windows.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmwinwaf' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Required. The object id of the Backup Management Service Enterprise Application. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-BackupManagementServiceEnterpriseApplicationObjectId\'.') +@secure() +param backupManagementServiceEnterpriseApplicationObjectId string = '' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + maintenanceConfigurationName: 'dep-${namePrefix}-mc-${serviceShort}' + applicationSecurityGroupName: 'dep-${namePrefix}-asg-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + loadBalancerName: 'dep-${namePrefix}-lb-${serviceShort}' + recoveryServicesVaultName: 'dep-${namePrefix}-rsv-${serviceShort}' + storageAccountName: 'dep${namePrefix}sa${serviceShort}01' + storageUploadDeploymentScriptName: 'dep-${namePrefix}-sads-${serviceShort}' + proximityPlacementGroupName: 'dep-${namePrefix}-ppg-${serviceShort}' + backupManagementServiceApplicationObjectId: backupManagementServiceEnterpriseApplicationObjectId + dcrName: 'dep-${namePrefix}-dcr-${serviceShort}' + logAnalyticsWorkspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: enforcedLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + location: enforcedLocation + name: '${namePrefix}${serviceShort}' + computerName: '${namePrefix}winvm1' + adminUsername: 'VMAdmin' + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2019-datacenter' + version: 'latest' + } + nicConfigurations: [ + { + deleteOption: 'Delete' + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: nestedDependencies.outputs.applicationSecurityGroupResourceId + } + ] + loadBalancerBackendAddressPools: [ + { + id: nestedDependencies.outputs.loadBalancerBackendPoolResourceId + } + ] + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [ + 1 + 2 + 3 + ] + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + subnetResourceId: nestedDependencies.outputs.subnetResourceId + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + ] + nicSuffix: '-nic-01' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + ] + osDisk: { + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + adminPassword: password + zone: 2 + backupPolicyName: nestedDependencies.outputs.recoveryServicesVaultBackupPolicyName + backupVaultName: nestedDependencies.outputs.recoveryServicesVaultName + backupVaultResourceGroup: nestedDependencies.outputs.recoveryServicesVaultResourceGroupName + dataDisks: [ + { + caching: 'ReadOnly' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + { + caching: 'ReadOnly' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + ] + enableAutomaticUpdates: true + patchMode: 'AutomaticByPlatform' + bypassPlatformSafetyChecksOnUserSchedule: true + maintenanceConfigurationResourceId: nestedDependencies.outputs.maintenanceConfigurationResourceId + encryptionAtHost: false + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: { + Extensions: '.ext1;.ext2' + Paths: 'c:\\excluded-path-1;c:\\excluded-path-2' + Processes: 'excludedproc1.exe;excludedproc2.exe' + } + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionCustomScriptConfig: { + enabled: true + fileData: [ + { + storageAccountId: nestedDependencies.outputs.storageAccountResourceId + uri: nestedDependencies.outputs.storageAccountCSEFileUrl + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionCustomScriptProtectedSetting: { + commandToExecute: 'powershell -ExecutionPolicy Unrestricted -Command "& ./${nestedDependencies.outputs.storageAccountCSEFileName}"' + } + extensionDependencyAgentConfig: { + enabled: true + enableAMA: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionAzureDiskEncryptionConfig: { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: nestedDependencies.outputs.keyVaultEncryptionKeyUrl + KeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + KeyVaultURL: nestedDependencies.outputs.keyVaultUrl + ResizeOSDisk: 'false' + VolumeType: 'All' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } + extensionAadJoinConfig: { + enabled: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionDSCConfig: { + enabled: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionMonitoringAgentConfig: { + enabled: true + dataCollectionRuleAssociations: [ + { + name: 'SendMetricsToLAW' + dataCollectionRuleResourceId: nestedDependencies.outputs.dataCollectionRuleResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionNetworkWatcherAgentConfig: { + enabled: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + proximityPlacementGroupResourceId: nestedDependencies.outputs.proximityPlacementGroupResourceId + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.SSDv2/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.SSDv2/dependencies.bicep new file mode 100644 index 000000000..68972ec7e --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.SSDv2/dependencies.bicep @@ -0,0 +1,30 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.SSDv2/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.SSDv2/main.test.bicep new file mode 100644 index 000000000..d2e547f0c --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.SSDv2/main.test.bicep @@ -0,0 +1,101 @@ +targetScope = 'subscription' + +metadata name = 'Deploying Windows VM with premium SSDv2 data disk' +metadata description = 'This instance deploys the module with premium SSDv2 data disk.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmwinssdv2' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + location: enforcedLocation + name: '${namePrefix}${serviceShort}' + adminUsername: 'localAdminUser' + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + zone: 1 + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + diskSizeGB: 128 + caching: 'ReadWrite' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + dataDisks: [ + { + diskSizeGB: 1024 + caching: 'None' + managedDisk: { + storageAccountType: 'PremiumV2_LRS' + } + diskIOPSReadWrite: 3000 + diskMBpsReadWrite: 125 + } + ] + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + adminPassword: password + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.defaults/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.defaults/dependencies.bicep new file mode 100644 index 000000000..68972ec7e --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.defaults/dependencies.bicep @@ -0,0 +1,30 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.defaults/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.defaults/main.test.bicep new file mode 100644 index 000000000..db778bf32 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.defaults/main.test.bicep @@ -0,0 +1,90 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults for Windows' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmwinmin' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + location: enforcedLocation + name: '${namePrefix}${serviceShort}' + adminUsername: 'localAdminUser' + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + zone: 0 + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + diskSizeGB: 128 + caching: 'ReadWrite' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + adminPassword: password + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/dependencies.bicep new file mode 100644 index 000000000..68972ec7e --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/dependencies.bicep @@ -0,0 +1,30 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/main.test.bicep new file mode 100644 index 000000000..e719018cf --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/main.test.bicep @@ -0,0 +1,123 @@ +targetScope = 'subscription' + +metadata name = 'Using guest configuration for Windows' +metadata description = 'This instance deploys the module with the a guest configuration.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmwinguest' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + managedIdentities: { + systemAssigned: true + } + location: enforcedLocation + name: '${namePrefix}${serviceShort}' + adminUsername: 'localAdminUser' + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + zone: 0 + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [] + } + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + diskSizeGB: 128 + caching: 'ReadWrite' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + adminPassword: password + extensionGuestConfigurationExtension: { + enabled: true + } + guestConfiguration: { + name: 'AzureWindowsBaseline' + version: '1.*' + assignmentType: 'ApplyAndMonitor' + configurationParameter: [ + { + name: 'Minimum Password Length;ExpectedValue' + value: '16' + } + { + name: 'Minimum Password Length;RemediateValue' + value: '16' + } + { + name: 'Maximum Password Age;ExpectedValue' + value: '75' + } + { + name: 'Maximum Password Age;RemediateValue' + value: '75' + } + ] + } + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.hostpool/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.hostpool/dependencies.bicep new file mode 100644 index 000000000..30416db68 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.hostpool/dependencies.bicep @@ -0,0 +1,94 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Deployment Script used to upload data to the Storage Account.') +param getRegistrationTokenDeploymentScriptName string + +@description('Required. The name of the Host pool to create.') +param hostPoolName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource hostPool 'Microsoft.DesktopVirtualization/hostPools@2023-09-05' = { + name: hostPoolName + location: location + properties: { + hostPoolType: 'Personal' + loadBalancerType: 'BreadthFirst' + preferredAppGroupType: 'Desktop' + } +} + +resource msiHPDesktopVirtualizationVirtualMachineContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${hostPool.name}-${location}-${managedIdentity.id}-HostPool-DesktopVirtualizationVirtualMachineContributor-RoleAssignment') + scope: hostPool + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a959dbd1-f747-45e3-8ba6-dd80f235f97c' + ) // Desktop Virtualization Virtual Machine Contributor + principalType: 'ServicePrincipal' + } +} + +resource getRegistrationTokenDeploymentScript 'Microsoft.Resources/deploymentScripts@2023-08-01' = { + name: getRegistrationTokenDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + dependsOn: [ + msiHPDesktopVirtualizationVirtualMachineContributorRoleAssignment + ] + properties: { + azPowerShellVersion: '10.0' + arguments: '-HostPoolName "${hostPool.name}" -HostPoolResourceGroupName "${resourceGroup().name}" -SubscriptionId "${subscription().subscriptionId}"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Get-HostPoolRegistrationKey.ps1') + retentionInterval: 'PT1H' + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The name of the created Host pool.') +output hostPoolName string = hostPool.name + +@description('The registration token of the created Host pool.') +output registrationInfoToken string = getRegistrationTokenDeploymentScript.properties.outputs.registrationInfoToken diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.hostpool/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.hostpool/main.test.bicep new file mode 100644 index 000000000..06cb5b663 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.hostpool/main.test.bicep @@ -0,0 +1,116 @@ +targetScope = 'subscription' + +metadata name = 'Using a host pool to register the VM' +metadata description = 'This instance deploys the module and registers it in a host pool.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmwinhp' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + hostPoolName: 'dep${namePrefix}-hp-${serviceShort}01' + getRegistrationTokenDeploymentScriptName: 'dep-${namePrefix}-rtds-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + location: enforcedLocation + name: '${namePrefix}${serviceShort}' + adminUsername: 'localAdminUser' + managedIdentities: { + systemAssigned: true + } + zone: 0 + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + diskSizeGB: 128 + caching: 'ReadWrite' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + adminPassword: password + extensionAadJoinConfig: { + enabled: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionHostPoolRegistration: { + enabled: true + hostPoolName: nestedDependencies.outputs.hostPoolName + registrationInfoToken: nestedDependencies.outputs.registrationInfoToken + modulesUrl: 'https://wvdportalstorageblob.blob.${environment().suffixes.storage}/galleryartifacts/Configuration_09-08-2022.zip' + configurationFunction: 'Configuration.ps1\\AddSessionHost' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.max/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.max/dependencies.bicep new file mode 100644 index 000000000..bd3f2d08a --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.max/dependencies.bicep @@ -0,0 +1,446 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Application Security Group to create.') +param applicationSecurityGroupName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Load Balancer to create.') +param loadBalancerName string + +@description('Required. The name of the Public IP address to create.') +param publicIPAddressName string + +@description('Required. The name of the Recovery Services Vault to create.') +param recoveryServicesVaultName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Deployment Script used to upload data to the Storage Account.') +param storageUploadDeploymentScriptName string + +@description('Required. The name of the Proximity Placement Group to create.') +param proximityPlacementGroupName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The object ID of the Backup Management Service Enterprise Application.') +param backupManagementServiceApplicationObjectId string + +@description('Required. The name of the data collection rule.') +param dcrName string + +@description('Required. Resource ID of the log analytics worspace to stream logs from Azure monitoring agent.') +param logAnalyticsWorkspaceResourceId string + +var storageAccountCSEFileName = 'scriptExtensionMasterInstaller.ps1' +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource applicationSecurityGroup 'Microsoft.Network/applicationSecurityGroups@2023-04-01' = { + name: applicationSecurityGroupName + location: location +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource msiRGContrRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'Contributor', managedIdentity.id) + scope: resourceGroup() + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalType: 'ServicePrincipal' + } +} + +resource loadBalancer 'Microsoft.Network/loadBalancers@2023-04-01' = { + name: loadBalancerName + location: location + sku: { + name: 'Standard' + } + properties: { + frontendIPConfigurations: [ + { + name: 'privateIPConfig1' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + backendAddressPools: [ + { + name: 'servers' + } + ] + } +} + +resource pip 'Microsoft.Network/publicIPAddresses@2024-01-01' = { + name: publicIPAddressName + location: location + sku: { + name: 'Standard' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource recoveryServicesVault 'Microsoft.RecoveryServices/vaults@2022-04-01' = { + name: recoveryServicesVaultName + location: location + sku: { + name: 'RS0' + tier: 'Standard' + } + properties: {} + + resource backupPolicy 'backupPolicies@2022-03-01' = { + name: 'backupPolicy' + properties: { + backupManagementType: 'AzureIaasVM' + instantRPDetails: {} + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunFrequency: 'Daily' + scheduleRunTimes: [ + '2019-11-07T07:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + retentionPolicy: { + retentionPolicyType: 'LongTermRetentionPolicy' + dailySchedule: { + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + retentionDuration: { + count: 180 + durationType: 'Days' + } + } + weeklySchedule: { + daysOfTheWeek: [ + 'Sunday' + ] + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + retentionDuration: { + count: 12 + durationType: 'Weeks' + } + } + monthlySchedule: { + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + retentionDuration: { + count: 60 + durationType: 'Months' + } + } + yearlySchedule: { + retentionScheduleFormatType: 'Weekly' + monthsOfYear: [ + 'January' + ] + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + retentionDuration: { + count: 10 + durationType: 'Years' + } + } + } + instantRpRetentionRangeInDays: 2 + timeZone: 'UTC' + protectedItemsCount: 0 + } + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'encryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource backupServiceKeyVaultPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('${keyVault.name}-${location}-BackupManagementService-KeyVault-KeyVaultAdministrator-RoleAssignment') + scope: keyVault + properties: { + principalId: backupManagementServiceApplicationObjectId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '00482a5a-887f-4fb3-b363-3b7fe8e74483' + ) // Key Vault Administrator + principalType: 'ServicePrincipal' + } +} + +resource msiKVReadRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-KeyVault-Key-Read-RoleAssignment') + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + + resource blobService 'blobServices@2021-09-01' = { + name: 'default' + + resource container 'containers@2021-09-01' = { + name: 'scripts' + } + } +} + +resource storageUpload 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: storageUploadDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.0' + retentionInterval: 'P1D' + arguments: '-StorageAccountName "${storageAccount.name}" -ResourceGroupName "${resourceGroup().name}" -ContainerName "${storageAccount::blobService::container.name}" -FileName "${storageAccountCSEFileName}"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Set-BlobContent.ps1') + } + dependsOn: [ + msiRGContrRoleAssignment + ] +} + +resource proximityPlacementGroup 'Microsoft.Compute/proximityPlacementGroups@2022-03-01' = { + name: proximityPlacementGroupName + location: location +} + +resource dcr 'Microsoft.Insights/dataCollectionRules@2023-03-11' = { + name: dcrName + location: location + kind: 'Windows' + properties: { + dataSources: { + performanceCounters: [ + { + streams: [ + 'Microsoft-Perf' + ] + samplingFrequencyInSeconds: 60 + counterSpecifiers: [ + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Processes' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Handle Count' + '\\System\\System Up Time' + '\\System\\Context Switches/sec' + '\\System\\Processor Queue Length' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pages/sec' + '\\Memory\\Page Faults/sec' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + ] + name: 'perfCounterDataSource60' + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: logAnalyticsWorkspaceResourceId + name: 'la--1264800308' + } + ] + } + dataFlows: [ + { + streams: [ + 'Microsoft-Perf' + ] + destinations: [ + 'la--1264800308' + ] + transformKql: 'source' + outputStream: 'Microsoft-Perf' + } + ] + } +} +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Application Security Group.') +output applicationSecurityGroupResourceId string = applicationSecurityGroup.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Load Balancer Backend Pool.') +output loadBalancerBackendPoolResourceId string = loadBalancer.properties.backendAddressPools[0].id + +@description('The name of the created Recovery Services Vault.') +output recoveryServicesVaultName string = recoveryServicesVault.name + +@description('The name of the Resource Group, the Recovery Services Vault was created in.') +output recoveryServicesVaultResourceGroupName string = resourceGroup().name + +@description('The name of the Backup Policy created in the Backup Recovery Vault.') +output recoveryServicesVaultBackupPolicyName string = recoveryServicesVault::backupPolicy.name + +@description('The resource ID of the created PIP.') +output publicIPAddressResourceId string = pip.id + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The URL of the created Key Vault.') +output keyVaultUrl string = keyVault.properties.vaultUri + +@description('The URL of the created Key Vault Encryption Key.') +output keyVaultEncryptionKeyUrl string = keyVault::key.properties.keyUriWithVersion + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id + +@description('The name of the Custom Script Extension in the created Storage Account.') +output storageAccountCSEFileName string = storageAccountCSEFileName + +@description('The URL of the Custom Script Extension in the created Storage Account') +output storageAccountCSEFileUrl string = '${storageAccount.properties.primaryEndpoints.blob}${storageAccount::blobService::container.name}/${storageAccountCSEFileName}' + +@description('The resource ID of the created Proximity Placement Group.') +output proximityPlacementGroupResourceId string = proximityPlacementGroup.id + +@description('The resource ID of the created data collection rule.') +output dataCollectionRuleResourceId string = dcr.id diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.max/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.max/main.test.bicep new file mode 100644 index 000000000..c44c8eb73 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.max/main.test.bicep @@ -0,0 +1,393 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set for Windows' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmwinmax' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Required. The object id of the Backup Management Service Enterprise Application. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-BackupManagementServiceEnterpriseApplicationObjectId\'.') +@secure() +param backupManagementServiceEnterpriseApplicationObjectId string = '' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + applicationSecurityGroupName: 'dep-${namePrefix}-asg-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + publicIPAddressName: 'dep-${namePrefix}-pip-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + loadBalancerName: 'dep-${namePrefix}-lb-${serviceShort}' + recoveryServicesVaultName: 'dep-${namePrefix}-rsv-${serviceShort}' + storageAccountName: 'dep${namePrefix}sa${serviceShort}01' + storageUploadDeploymentScriptName: 'dep-${namePrefix}-sads-${serviceShort}' + proximityPlacementGroupName: 'dep-${namePrefix}-ppg-${serviceShort}' + backupManagementServiceApplicationObjectId: backupManagementServiceEnterpriseApplicationObjectId + dcrName: 'dep-${namePrefix}-dcr-${serviceShort}' + logAnalyticsWorkspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: enforcedLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + location: enforcedLocation + name: '${namePrefix}${serviceShort}' + computerName: '${namePrefix}winvm1' + adminUsername: 'VMAdmin' + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2019-datacenter' + version: 'latest' + } + nicConfigurations: [ + { + deleteOption: 'Delete' + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: nestedDependencies.outputs.applicationSecurityGroupResourceId + } + ] + loadBalancerBackendAddressPools: [ + { + id: nestedDependencies.outputs.loadBalancerBackendPoolResourceId + } + ] + name: 'ipconfig01' + pipConfiguration: { + publicIPAddressResourceId: nestedDependencies.outputs.publicIPAddressResourceId + roleAssignments: [ + { + name: 'e962e7c1-261a-4afd-b5ad-17a640a0b7bc' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + subnetResourceId: nestedDependencies.outputs.subnetResourceId + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + ] + name: 'nic-test-01' + enableIPForwarding: true + roleAssignments: [ + { + name: '95fc1cc2-05ed-4f5a-a22c-a6ca852df7e7' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + ] + osDisk: { + name: 'osdisk01' + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + adminPassword: password + zone: 2 + backupPolicyName: nestedDependencies.outputs.recoveryServicesVaultBackupPolicyName + backupVaultName: nestedDependencies.outputs.recoveryServicesVaultName + backupVaultResourceGroup: nestedDependencies.outputs.recoveryServicesVaultResourceGroupName + dataDisks: [ + { + name: 'datadisk01' + lun: 0 + caching: 'None' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + { + name: 'datadisk02' + lun: 1 + caching: 'None' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + ] + enableAutomaticUpdates: true + patchMode: 'AutomaticByPlatform' + rebootSetting: 'IfRequired' + encryptionAtHost: false + autoShutdownConfig: { + status: 'Enabled' + dailyRecurrenceTime: '19:00' + timeZone: 'UTC' + notificationStatus: 'Enabled' + notificationEmail: 'test@contoso.com' + notificationLocale: 'en' + notificationTimeInMinutes: 30 + } + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: { + Extensions: '.ext1;.ext2' + Paths: 'c:\\excluded-path-1;c:\\excluded-path-2' + Processes: 'excludedproc1.exe;excludedproc2.exe' + } + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionCustomScriptConfig: { + enabled: true + fileData: [ + { + storageAccountId: nestedDependencies.outputs.storageAccountResourceId + uri: nestedDependencies.outputs.storageAccountCSEFileUrl + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionCustomScriptProtectedSetting: { + commandToExecute: 'powershell -ExecutionPolicy Unrestricted -Command "& ./${nestedDependencies.outputs.storageAccountCSEFileName}"' + } + extensionDependencyAgentConfig: { + enabled: true + enableAMA: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionAzureDiskEncryptionConfig: { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: nestedDependencies.outputs.keyVaultEncryptionKeyUrl + KeyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + KeyVaultURL: nestedDependencies.outputs.keyVaultUrl + ResizeOSDisk: 'false' + VolumeType: 'All' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } + extensionAadJoinConfig: { + enabled: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionDSCConfig: { + enabled: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionMonitoringAgentConfig: { + enabled: true + dataCollectionRuleAssociations: [ + { + name: 'SendMetricsToLAW' + dataCollectionRuleResourceId: nestedDependencies.outputs.dataCollectionRuleResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + extensionNetworkWatcherAgentConfig: { + enabled: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + proximityPlacementGroupResourceId: nestedDependencies.outputs.proximityPlacementGroupResourceId + roleAssignments: [ + { + name: 'c70e8c48-6945-4607-9695-1098ba5a86ed' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.nvidia/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.nvidia/dependencies.bicep new file mode 100644 index 000000000..68972ec7e --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.nvidia/dependencies.bicep @@ -0,0 +1,30 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep new file mode 100644 index 000000000..0b8df1ac0 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep @@ -0,0 +1,93 @@ +targetScope = 'subscription' + +metadata name = 'Deploy a VM with nVidia graphic card' +metadata description = 'This instance deploys the module for a VM with dedicated nVidia graphic card.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmwinnv' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + location: enforcedLocation + name: '${namePrefix}${serviceShort}' + adminUsername: 'localAdminUser' + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + zone: 0 + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + diskSizeGB: 128 + caching: 'ReadWrite' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_NV6ads_A10_v5' + adminPassword: password + extensionNvidiaGpuDriverWindows: { + enabled: true + } + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.ssecmk/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.ssecmk/dependencies.bicep new file mode 100644 index 000000000..bb849994d --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.ssecmk/dependencies.bicep @@ -0,0 +1,95 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Disk Encryption Set to create.') +param diskEncryptionSetName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource diskEncryptionSet 'Microsoft.Compute/diskEncryptionSets@2021-04-01' = { + name: diskEncryptionSetName + location: location + identity: { + type: 'SystemAssigned' + } + properties: { + activeKey: { + sourceVault: { + id: keyVault.id + } + keyUrl: keyVault::key.properties.keyUriWithVersion + } + encryptionType: 'EncryptionAtRestWithPlatformAndCustomerKeys' + } +} + +resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(keyVault::key.id, 'Key Vault Crypto User', diskEncryptionSet.id) + scope: keyVault + properties: { + principalId: diskEncryptionSet.identity.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'e147488a-f6f5-4113-8e2d-b22465e65bf6' + ) // Key Vault Crypto Service Encryption User + principalType: 'ServicePrincipal' + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Disk Encryption Set.') +output diskEncryptionSetResourceId string = diskEncryptionSet.id diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.ssecmk/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.ssecmk/main.test.bicep new file mode 100644 index 000000000..8c9e1a248 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.ssecmk/main.test.bicep @@ -0,0 +1,109 @@ +targetScope = 'subscription' + +metadata name = 'Using disk encryption set for the VM.' +metadata description = 'This instance deploys the module with disk enryption set.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmwincmk' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep${namePrefix}kv${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + diskEncryptionSetName: 'dep-${namePrefix}-des-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + location: enforcedLocation + name: '${namePrefix}${serviceShort}' + adminUsername: 'VMAdministrator' + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2019-datacenter' + version: 'latest' + } + zone: 0 + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + diskEncryptionSet: { + id: nestedDependencies.outputs.diskEncryptionSetResourceId + } + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + adminPassword: password + dataDisks: [ + { + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + diskEncryptionSet: { + id: nestedDependencies.outputs.diskEncryptionSetResourceId + } + } + } + ] + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.vmss/dependencies.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.vmss/dependencies.bicep new file mode 100644 index 000000000..6c8fcca3f --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.vmss/dependencies.bicep @@ -0,0 +1,101 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Virtual Machine Scale Set to create.') +param vmssName string + +@description('Required. The name of the public IP address for the Virtual Machine Scale Set to create.') +param pipName string + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2023-09-01' = { + name: vmssName + location: location + sku: { + name: 'Standard_B12ms' + } + properties: { + orchestrationMode: 'Flexible' + platformFaultDomainCount: 1 + virtualMachineProfile: { + osProfile: { + adminUsername: 'localAdminUser' + adminPassword: password + computerNamePrefix: 'vmssvm' + } + storageProfile: { + osDisk: { + createOption: 'fromImage' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + osType: 'Windows' + } + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + } + networkProfile: { + networkApiVersion: '2020-11-01' + networkInterfaceConfigurations: [ + { + name: 'nicconfig1' + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + publicIPAddressConfiguration: { + name: pipName + } + } + } + ] + } + } + ] + } + } + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Virtual Machine Scale Set.') +output vmssResourceId string = vmss.id diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep new file mode 100644 index 000000000..aa14a3502 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep @@ -0,0 +1,94 @@ +targetScope = 'subscription' + +metadata name = 'Adding the VM to a VMSS.' +metadata description = 'This instance deploys the module with the minimum set of required parameters and adds it to a VMSS.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' + +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cvmwinvmss' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + vmssName: 'dep-${namePrefix}-vmss-${serviceShort}' + pipName: 'dep-${namePrefix}-pip-${serviceShort}' + password: password + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + location: enforcedLocation + name: '${namePrefix}${serviceShort}' + adminUsername: 'localAdminUser' + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + zone: 0 + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + diskSizeGB: 128 + caching: 'ReadWrite' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_D2s_v3' + adminPassword: password + virtualMachineScaleSetResourceId: nestedDependencies.outputs.vmssResourceId + } + } +] diff --git a/avm/1.1.0/res/compute/virtual-machine/tests/unit/avm.core.team.tests.ps1 b/avm/1.1.0/res/compute/virtual-machine/tests/unit/avm.core.team.tests.ps1 new file mode 100644 index 000000000..ab40d5e16 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/tests/unit/avm.core.team.tests.ps1 @@ -0,0 +1,35 @@ +<# +.SYNOPSIS +This file contains Pester tests that the AVM Core Team has written for the module. Any additions or changes to these tests will need to be reviewed by the AVM Core Team, this is handled by CODEOWNERS. + +If you wish to add your own Pester tests for you module create a new .tests.ps1 file in the /tests/unit folder of your module. +#> + +param ( + [Parameter(Mandatory = $false)] + [array] $moduleFolderPaths, + + [Parameter(Mandatory = $false)] + [string] $repoRootPath +) + +BeforeAll { + . (Join-Path $RepoRootPath 'utilities' 'pipelines' 'sharedScripts' 'helper' 'Get-IsParameterRequired.ps1') + + if ($moduleFolderPaths.Count -gt 1) { + $topLevelModuleTemplatePath = $moduleFolderPaths | Sort-Object -Culture 'en-US' | Select-Object -First 1 + } else { + $topLevelModuleTemplatePath = $moduleFolderPaths + } + + $moduleJsonContentHashtable = Get-Content -Path (Join-Path $topLevelModuleTemplatePath 'main.json') | ConvertFrom-Json -AsHashtable +} + +Describe 'AVM Core Team Module Specific Tests' { + Context 'WAF - Reliability Pillar - Parameter Tests' { + It 'VM Module Availability Zone Parameter Should Not Have A Default Value Set' { + $isRequired = Get-IsParameterRequired -TemplateFileContent $moduleJsonContentHashtable -Parameter $moduleJsonContentHashtable.parameters.zone + $isRequired | Should -Be $true + } + } +} diff --git a/avm/1.1.0/res/compute/virtual-machine/version.json b/avm/1.1.0/res/compute/virtual-machine/version.json new file mode 100644 index 000000000..23f381588 --- /dev/null +++ b/avm/1.1.0/res/compute/virtual-machine/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.12", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/desktop-virtualization/application-group/README.md b/avm/1.1.0/res/desktop-virtualization/application-group/README.md new file mode 100644 index 000000000..2ece1d6fa --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/application-group/README.md @@ -0,0 +1,870 @@ +# Azure Virtual Desktop Application Group `[Microsoft.DesktopVirtualization/applicationGroups]` + +This module deploys an Azure Virtual Desktop Application Group. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.DesktopVirtualization/applicationGroups` | [2023-09-05](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DesktopVirtualization/2023-09-05/applicationGroups) | +| `Microsoft.DesktopVirtualization/applicationGroups/applications` | [2023-09-05](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DesktopVirtualization/2023-09-05/applicationGroups/applications) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/desktop-virtualization/application-group:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module applicationGroup 'br/public:avm/res/desktop-virtualization/application-group:' = { + name: 'applicationGroupDeployment' + params: { + // Required parameters + applicationGroupType: 'Desktop' + hostpoolName: '' + name: 'dvagmin002' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "applicationGroupType": { + "value": "Desktop" + }, + "hostpoolName": { + "value": "" + }, + "name": { + "value": "dvagmin002" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/application-group:' + +// Required parameters +param applicationGroupType = 'Desktop' +param hostpoolName = '' +param name = 'dvagmin002' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module applicationGroup 'br/public:avm/res/desktop-virtualization/application-group:' = { + name: 'applicationGroupDeployment' + params: { + // Required parameters + applicationGroupType: 'RemoteApp' + hostpoolName: '' + name: 'dvagmax002' + // Non-required parameters + applications: [ + { + commandLineArguments: '' + commandLineSetting: 'DoNotAllow' + description: 'Notepad by ARM template' + filePath: 'C:\\Windows\\System32\\notepad.exe' + friendlyName: 'Notepad' + iconIndex: 0 + iconPath: 'C:\\Windows\\System32\\notepad.exe' + name: 'notepad' + showInPortal: true + } + { + filePath: 'C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe' + friendlyName: 'Wordpad' + name: 'wordpad' + } + ] + description: 'myDescription' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '30eaf006-ee2d-4a95-921c-87dfdb4c2061' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "applicationGroupType": { + "value": "RemoteApp" + }, + "hostpoolName": { + "value": "" + }, + "name": { + "value": "dvagmax002" + }, + // Non-required parameters + "applications": { + "value": [ + { + "commandLineArguments": "", + "commandLineSetting": "DoNotAllow", + "description": "Notepad by ARM template", + "filePath": "C:\\Windows\\System32\\notepad.exe", + "friendlyName": "Notepad", + "iconIndex": 0, + "iconPath": "C:\\Windows\\System32\\notepad.exe", + "name": "notepad", + "showInPortal": true + }, + { + "filePath": "C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe", + "friendlyName": "Wordpad", + "name": "wordpad" + } + ] + }, + "description": { + "value": "myDescription" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "logCategoriesAndGroups": [ + { + "categoryGroup": "allLogs" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "30eaf006-ee2d-4a95-921c-87dfdb4c2061", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/application-group:' + +// Required parameters +param applicationGroupType = 'RemoteApp' +param hostpoolName = '' +param name = 'dvagmax002' +// Non-required parameters +param applications = [ + { + commandLineArguments: '' + commandLineSetting: 'DoNotAllow' + description: 'Notepad by ARM template' + filePath: 'C:\\Windows\\System32\\notepad.exe' + friendlyName: 'Notepad' + iconIndex: 0 + iconPath: 'C:\\Windows\\System32\\notepad.exe' + name: 'notepad' + showInPortal: true + } + { + filePath: 'C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe' + friendlyName: 'Wordpad' + name: 'wordpad' + } +] +param description = 'myDescription' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '30eaf006-ee2d-4a95-921c-87dfdb4c2061' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module applicationGroup 'br/public:avm/res/desktop-virtualization/application-group:' = { + name: 'applicationGroupDeployment' + params: { + // Required parameters + applicationGroupType: 'Desktop' + hostpoolName: '' + name: 'dvagwaf002' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "applicationGroupType": { + "value": "Desktop" + }, + "hostpoolName": { + "value": "" + }, + "name": { + "value": "dvagwaf002" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/application-group:' + +// Required parameters +param applicationGroupType = 'Desktop' +param hostpoolName = '' +param name = 'dvagwaf002' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationGroupType`](#parameter-applicationgrouptype) | string | The type of the Application Group to be created. Allowed values: RemoteApp or Desktop. | +| [`hostpoolName`](#parameter-hostpoolname) | string | Name of the Host Pool to be linked to this Application Group. | +| [`name`](#parameter-name) | string | Name of the Application Group. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applications`](#parameter-applications) | array | List of applications to be created in the Application Group. | +| [`description`](#parameter-description) | string | Description of the application group. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`friendlyName`](#parameter-friendlyname) | string | The friendly name of the Application Group to be created. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `applicationGroupType` + +The type of the Application Group to be created. Allowed values: RemoteApp or Desktop. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Desktop' + 'RemoteApp' + ] + ``` + +### Parameter: `hostpoolName` + +Name of the Host Pool to be linked to this Application Group. + +- Required: Yes +- Type: string + +### Parameter: `name` + +Name of the Application Group. + +- Required: Yes +- Type: string + +### Parameter: `applications` + +List of applications to be created in the Application Group. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `description` + +Description of the application group. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `friendlyName` + +The friendly name of the Application Group to be created. + +- Required: No +- Type: string +- Default: `[parameters('name')]` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Owner'` + - `'Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Application Group Contributor'` + - `'Desktop Virtualization Application Group Contributor'` + - `'Desktop Virtualization Application Group Reader'` + - `'Desktop Virtualization Contributor'` + - `'Desktop Virtualization Host Pool Contributor'` + - `'Desktop Virtualization Host Pool Reader'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Reader'` + - `'Desktop Virtualization Session Host Operator'` + - `'Desktop Virtualization User'` + - `'Desktop Virtualization User Session Operator'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'Desktop Virtualization Workspace Contributor'` + - `'Desktop Virtualization Workspace Reader'` + - `'Managed Application Contributor Role'` + - `'Managed Application Operator Role'` + - `'Managed Applications Reader'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location of the scaling plan. | +| `name` | string | The name of the scaling plan. | +| `resourceGroupName` | string | The name of the resource group the scaling plan was created in. | +| `resourceId` | string | The resource ID of the scaling plan. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/desktop-virtualization/application-group/application/README.md b/avm/1.1.0/res/desktop-virtualization/application-group/application/README.md new file mode 100644 index 000000000..da38612c2 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/application-group/application/README.md @@ -0,0 +1,134 @@ +# Azure Virtual Desktop Application Group Application `[Microsoft.DesktopVirtualization/applicationGroups/applications]` + +This module deploys an Azure Virtual Desktop Application Group Application. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.DesktopVirtualization/applicationGroups/applications` | [2023-09-05](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DesktopVirtualization/2023-09-05/applicationGroups/applications) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`filePath`](#parameter-filepath) | string | Specifies a path for the executable file for the Application. | +| [`friendlyName`](#parameter-friendlyname) | string | Friendly name of the Application. | +| [`name`](#parameter-name) | string | Name of the Application to be created in the Application Group. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationGroupName`](#parameter-applicationgroupname) | string | The name of the parent Application Group to create the application(s) in. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`commandLineArguments`](#parameter-commandlinearguments) | string | Command-Line Arguments for the Application. | +| [`commandLineSetting`](#parameter-commandlinesetting) | string | Specifies whether this published Application can be launched with command-line arguments provided by the client, command-line arguments specified at publish time, or no command-line arguments at all. | +| [`description`](#parameter-description) | string | Description of the Application. | +| [`iconIndex`](#parameter-iconindex) | int | Index of the icon. | +| [`iconPath`](#parameter-iconpath) | string | Path to icon. | +| [`showInPortal`](#parameter-showinportal) | bool | Specifies whether to show the RemoteApp program in the RD Web Access server. | + +### Parameter: `filePath` + +Specifies a path for the executable file for the Application. + +- Required: Yes +- Type: string + +### Parameter: `friendlyName` + +Friendly name of the Application. + +- Required: Yes +- Type: string + +### Parameter: `name` + +Name of the Application to be created in the Application Group. + +- Required: Yes +- Type: string + +### Parameter: `applicationGroupName` + +The name of the parent Application Group to create the application(s) in. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `commandLineArguments` + +Command-Line Arguments for the Application. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `commandLineSetting` + +Specifies whether this published Application can be launched with command-line arguments provided by the client, command-line arguments specified at publish time, or no command-line arguments at all. + +- Required: No +- Type: string +- Default: `'DoNotAllow'` +- Allowed: + ```Bicep + [ + 'Allow' + 'DoNotAllow' + 'Require' + ] + ``` + +### Parameter: `description` + +Description of the Application. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `iconIndex` + +Index of the icon. + +- Required: No +- Type: int +- Default: `0` + +### Parameter: `iconPath` + +Path to icon. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `showInPortal` + +Specifies whether to show the RemoteApp program in the RD Web Access server. + +- Required: No +- Type: bool +- Default: `False` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the Application. | +| `resourceGroupName` | string | The name of the resource group the Application was created in. | +| `resourceId` | string | The resource ID of the Application. | diff --git a/avm/1.1.0/res/desktop-virtualization/application-group/application/main.bicep b/avm/1.1.0/res/desktop-virtualization/application-group/application/main.bicep new file mode 100644 index 000000000..e3d42e086 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/application-group/application/main.bicep @@ -0,0 +1,65 @@ +metadata name = 'Azure Virtual Desktop Application Group Application' +metadata description = 'This module deploys an Azure Virtual Desktop Application Group Application.' + +@sys.description('Conditional. The name of the parent Application Group to create the application(s) in. Required if the template is used in a standalone deployment.') +param applicationGroupName string + +@sys.description('Required. Name of the Application to be created in the Application Group.') +param name string + +@sys.description('Optional. Description of the Application.') +param description string = '' + +@sys.description('Required. Friendly name of the Application.') +param friendlyName string + +@sys.description('Required. Specifies a path for the executable file for the Application.') +param filePath string + +@allowed([ + 'Allow' + 'DoNotAllow' + 'Require' +]) +@sys.description('Optional. Specifies whether this published Application can be launched with command-line arguments provided by the client, command-line arguments specified at publish time, or no command-line arguments at all.') +param commandLineSetting string = 'DoNotAllow' + +@sys.description('Optional. Command-Line Arguments for the Application.') +param commandLineArguments string = '' + +@sys.description('Optional. Specifies whether to show the RemoteApp program in the RD Web Access server.') +param showInPortal bool = false + +@sys.description('Optional. Path to icon.') +param iconPath string = '' + +@sys.description('Optional. Index of the icon.') +param iconIndex int = 0 + +resource appGroup 'Microsoft.DesktopVirtualization/applicationGroups@2023-09-05' existing = { + name: applicationGroupName +} + +resource application 'Microsoft.DesktopVirtualization/applicationGroups/applications@2023-09-05' = { + name: name + parent: appGroup + properties: { + description: description + friendlyName: friendlyName + filePath: filePath + commandLineSetting: commandLineSetting + commandLineArguments: commandLineArguments + showInPortal: showInPortal + iconPath: iconPath + iconIndex: iconIndex + } +} + +@sys.description('The resource ID of the Application.') +output resourceId string = application.id + +@sys.description('The name of the resource group the Application was created in.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The name of the Application.') +output name string = application.name diff --git a/avm/1.1.0/res/desktop-virtualization/application-group/application/main.json b/avm/1.1.0/res/desktop-virtualization/application-group/application/main.json new file mode 100644 index 000000000..5cc586099 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/application-group/application/main.json @@ -0,0 +1,126 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "13090481719462571506" + }, + "name": "Azure Virtual Desktop Application Group Application", + "description": "This module deploys an Azure Virtual Desktop Application Group Application." + }, + "parameters": { + "applicationGroupName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Group to create the application(s) in. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application to be created in the Application Group." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Description of the Application." + } + }, + "friendlyName": { + "type": "string", + "metadata": { + "description": "Required. Friendly name of the Application." + } + }, + "filePath": { + "type": "string", + "metadata": { + "description": "Required. Specifies a path for the executable file for the Application." + } + }, + "commandLineSetting": { + "type": "string", + "defaultValue": "DoNotAllow", + "allowedValues": [ + "Allow", + "DoNotAllow", + "Require" + ], + "metadata": { + "description": "Optional. Specifies whether this published Application can be launched with command-line arguments provided by the client, command-line arguments specified at publish time, or no command-line arguments at all." + } + }, + "commandLineArguments": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Command-Line Arguments for the Application." + } + }, + "showInPortal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether to show the RemoteApp program in the RD Web Access server." + } + }, + "iconPath": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Path to icon." + } + }, + "iconIndex": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Index of the icon." + } + } + }, + "resources": [ + { + "type": "Microsoft.DesktopVirtualization/applicationGroups/applications", + "apiVersion": "2023-09-05", + "name": "[format('{0}/{1}', parameters('applicationGroupName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "friendlyName": "[parameters('friendlyName')]", + "filePath": "[parameters('filePath')]", + "commandLineSetting": "[parameters('commandLineSetting')]", + "commandLineArguments": "[parameters('commandLineArguments')]", + "showInPortal": "[parameters('showInPortal')]", + "iconPath": "[parameters('iconPath')]", + "iconIndex": "[parameters('iconIndex')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Application." + }, + "value": "[resourceId('Microsoft.DesktopVirtualization/applicationGroups/applications', parameters('applicationGroupName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Application was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Application." + }, + "value": "[parameters('name')]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/desktop-virtualization/application-group/main.bicep b/avm/1.1.0/res/desktop-virtualization/application-group/main.bicep new file mode 100644 index 000000000..79d062392 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/application-group/main.bicep @@ -0,0 +1,266 @@ +metadata name = 'Azure Virtual Desktop Application Group' +metadata description = 'This module deploys an Azure Virtual Desktop Application Group.' + +@sys.description('Required. Name of the Application Group.') +@minLength(3) +param name string + +@sys.description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@sys.description('Required. The type of the Application Group to be created. Allowed values: RemoteApp or Desktop.') +@allowed([ + 'RemoteApp' + 'Desktop' +]) +param applicationGroupType string + +@sys.description('Required. Name of the Host Pool to be linked to this Application Group.') +param hostpoolName string + +@sys.description('Optional. The friendly name of the Application Group to be created.') +param friendlyName string = name + +@sys.description('Optional. Description of the application group.') +param description string = '' + +@sys.description('Optional. List of applications to be created in the Application Group.') +param applications array = [] + +@sys.description('Optional. Tags of the resource.') +param tags object? + +@sys.description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@sys.description('Optional. The lock settings of the service.') +param lock lockType + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@sys.description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +var builtInRoleNames = { + Owner: '/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635' + Contributor: '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + Reader: '/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7' + 'Role Based Access Control Administrator': '/providers/Microsoft.Authorization/roleDefinitions/f58310d9-a9f6-439a-9e8d-f62e7b41a168' + 'User Access Administrator': '/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + 'Application Group Contributor': '/providers/Microsoft.Authorization/roleDefinitions/ca6382a4-1721-4bcf-a114-ff0c70227b6b' + 'Desktop Virtualization Application Group Contributor': '/providers/Microsoft.Authorization/roleDefinitions/86240b0e-9422-4c43-887b-b61143f32ba8' + 'Desktop Virtualization Application Group Reader': '/providers/Microsoft.Authorization/roleDefinitions/aebf23d0-b568-4e86-b8f9-fe83a2c6ab55' + 'Desktop Virtualization Contributor': '/providers/Microsoft.Authorization/roleDefinitions/082f0a83-3be5-4ba1-904c-961cca79b387' + 'Desktop Virtualization Host Pool Contributor': '/providers/Microsoft.Authorization/roleDefinitions/e307426c-f9b6-4e81-87de-d99efb3c32bc' + 'Desktop Virtualization Host Pool Reader': '/providers/Microsoft.Authorization/roleDefinitions/ceadfde2-b300-400a-ab7b-6143895aa822' + 'Desktop Virtualization Power On Off Contributor': '/providers/Microsoft.Authorization/roleDefinitions/40c5ff49-9181-41f8-ae61-143b0e78555e' + 'Desktop Virtualization Reader': '/providers/Microsoft.Authorization/roleDefinitions/49a72310-ab8d-41df-bbb0-79b649203868' + 'Desktop Virtualization Session Host Operator': '/providers/Microsoft.Authorization/roleDefinitions/2ad6aaab-ead9-4eaa-8ac5-da422f562408' + 'Desktop Virtualization User': '/providers/Microsoft.Authorization/roleDefinitions/1d18fff3-a72a-46b5-b4a9-0b38a3cd7e63' + 'Desktop Virtualization User Session Operator': '/providers/Microsoft.Authorization/roleDefinitions/ea4bfff8-7fb4-485a-aadd-d4129a0ffaa6' + 'Desktop Virtualization Virtual Machine Contributor': '/providers/Microsoft.Authorization/roleDefinitions/a959dbd1-f747-45e3-8ba6-dd80f235f97c' + 'Desktop Virtualization Workspace Contributor': '/providers/Microsoft.Authorization/roleDefinitions/21efdde3-836f-432b-bf3d-3e8e734d4b2b' + 'Desktop Virtualization Workspace Reader': '/providers/Microsoft.Authorization/roleDefinitions/0fa44ee9-7a7d-466b-9bb2-2bf446b1204d' + 'Managed Application Contributor Role': '/providers/Microsoft.Authorization/roleDefinitions/641177b8-a67a-45b9-a033-47bc880bb21e' + 'Managed Application Operator Role': '/providers/Microsoft.Authorization/roleDefinitions/c7393b34-138c-406f-901b-d8cf2b17e6ae' + 'Managed Applications Reader': '/providers/Microsoft.Authorization/roleDefinitions/b9331d33-8a36-4f8c-b097-4f54124fdb44' +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.desktopvirtualization-appgroup.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource appGroup_hostpool 'Microsoft.DesktopVirtualization/hostPools@2022-09-09' existing = { + name: hostpoolName +} + +resource appGroup 'Microsoft.DesktopVirtualization/applicationGroups@2023-09-05' = { + name: name + location: location + tags: tags + properties: { + hostPoolArmPath: appGroup_hostpool.id + friendlyName: friendlyName + description: description + applicationGroupType: applicationGroupType + } +} + +module appGroup_applications 'application/main.bicep' = [ + for (application, index) in applications: { + name: '${uniqueString(deployment().name, location)}-AppGroup-App-${index}' + params: { + name: application.name + applicationGroupName: appGroup.name + description: contains(application, 'description') ? application.description : '' + friendlyName: contains(application, 'friendlyName') ? application.friendlyName : appGroup.name + filePath: application.filePath + commandLineSetting: contains(application, 'commandLineSetting') ? application.commandLineSetting : 'DoNotAllow' + commandLineArguments: contains(application, 'commandLineArguments') ? application.commandLineArguments : '' + showInPortal: contains(application, 'showInPortal') ? application.showInPortal : false + iconPath: contains(application, 'iconPath') ? application.iconPath : application.filePath + iconIndex: contains(application, 'iconIndex') ? application.iconIndex : 0 + } + } +] + +resource appGroup_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: appGroup +} + +resource appGroup_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(appGroup.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: appGroup + } +] + +resource appGroup_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: appGroup + } +] + +@sys.description('The resource ID of the scaling plan.') +output resourceId string = appGroup.id + +@sys.description('The name of the resource group the scaling plan was created in.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The name of the scaling plan.') +output name string = appGroup.name + +@sys.description('The location of the scaling plan.') +output location string = appGroup.location + +// ================ // +// Definitions // +// ================ // + +type lockType = { + @sys.description('Optional. Specify the name of lock.') + name: string? + + @sys.description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @sys.description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @sys.description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @sys.description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @sys.description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @sys.description('Optional. The description of the role assignment.') + 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".') + condition: string? + + @sys.description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @sys.description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type diagnosticSettingType = { + @sys.description('Optional. The name of diagnostic setting.') + name: string? + + @sys.description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @sys.description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @sys.description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs.') + categoryGroup: string? + + @sys.description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @sys.description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @sys.description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @sys.description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @sys.description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @sys.description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @sys.description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? diff --git a/avm/1.1.0/res/desktop-virtualization/application-group/main.json b/avm/1.1.0/res/desktop-virtualization/application-group/main.json new file mode 100644 index 000000000..fde8d2b9b --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/application-group/main.json @@ -0,0 +1,628 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "16749070301001806245" + }, + "name": "Azure Virtual Desktop Application Group", + "description": "This module deploys an Azure Virtual Desktop Application Group." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 3, + "metadata": { + "description": "Required. Name of the Application Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "applicationGroupType": { + "type": "string", + "allowedValues": [ + "RemoteApp", + "Desktop" + ], + "metadata": { + "description": "Required. The type of the Application Group to be created. Allowed values: RemoteApp or Desktop." + } + }, + "hostpoolName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Host Pool to be linked to this Application Group." + } + }, + "friendlyName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. The friendly name of the Application Group to be created." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Description of the application group." + } + }, + "applications": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of applications to be created in the Application Group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Owner": "/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635", + "Contributor": "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c", + "Reader": "/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7", + "Role Based Access Control Administrator": "/providers/Microsoft.Authorization/roleDefinitions/f58310d9-a9f6-439a-9e8d-f62e7b41a168", + "User Access Administrator": "/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9", + "Application Group Contributor": "/providers/Microsoft.Authorization/roleDefinitions/ca6382a4-1721-4bcf-a114-ff0c70227b6b", + "Desktop Virtualization Application Group Contributor": "/providers/Microsoft.Authorization/roleDefinitions/86240b0e-9422-4c43-887b-b61143f32ba8", + "Desktop Virtualization Application Group Reader": "/providers/Microsoft.Authorization/roleDefinitions/aebf23d0-b568-4e86-b8f9-fe83a2c6ab55", + "Desktop Virtualization Contributor": "/providers/Microsoft.Authorization/roleDefinitions/082f0a83-3be5-4ba1-904c-961cca79b387", + "Desktop Virtualization Host Pool Contributor": "/providers/Microsoft.Authorization/roleDefinitions/e307426c-f9b6-4e81-87de-d99efb3c32bc", + "Desktop Virtualization Host Pool Reader": "/providers/Microsoft.Authorization/roleDefinitions/ceadfde2-b300-400a-ab7b-6143895aa822", + "Desktop Virtualization Power On Off Contributor": "/providers/Microsoft.Authorization/roleDefinitions/40c5ff49-9181-41f8-ae61-143b0e78555e", + "Desktop Virtualization Reader": "/providers/Microsoft.Authorization/roleDefinitions/49a72310-ab8d-41df-bbb0-79b649203868", + "Desktop Virtualization Session Host Operator": "/providers/Microsoft.Authorization/roleDefinitions/2ad6aaab-ead9-4eaa-8ac5-da422f562408", + "Desktop Virtualization User": "/providers/Microsoft.Authorization/roleDefinitions/1d18fff3-a72a-46b5-b4a9-0b38a3cd7e63", + "Desktop Virtualization User Session Operator": "/providers/Microsoft.Authorization/roleDefinitions/ea4bfff8-7fb4-485a-aadd-d4129a0ffaa6", + "Desktop Virtualization Virtual Machine Contributor": "/providers/Microsoft.Authorization/roleDefinitions/a959dbd1-f747-45e3-8ba6-dd80f235f97c", + "Desktop Virtualization Workspace Contributor": "/providers/Microsoft.Authorization/roleDefinitions/21efdde3-836f-432b-bf3d-3e8e734d4b2b", + "Desktop Virtualization Workspace Reader": "/providers/Microsoft.Authorization/roleDefinitions/0fa44ee9-7a7d-466b-9bb2-2bf446b1204d", + "Managed Application Contributor Role": "/providers/Microsoft.Authorization/roleDefinitions/641177b8-a67a-45b9-a033-47bc880bb21e", + "Managed Application Operator Role": "/providers/Microsoft.Authorization/roleDefinitions/c7393b34-138c-406f-901b-d8cf2b17e6ae", + "Managed Applications Reader": "/providers/Microsoft.Authorization/roleDefinitions/b9331d33-8a36-4f8c-b097-4f54124fdb44" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.desktopvirtualization-appgroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "appGroup_hostpool": { + "existing": true, + "type": "Microsoft.DesktopVirtualization/hostPools", + "apiVersion": "2022-09-09", + "name": "[parameters('hostpoolName')]" + }, + "appGroup": { + "type": "Microsoft.DesktopVirtualization/applicationGroups", + "apiVersion": "2023-09-05", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "hostPoolArmPath": "[resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('hostpoolName'))]", + "friendlyName": "[parameters('friendlyName')]", + "description": "[parameters('description')]", + "applicationGroupType": "[parameters('applicationGroupType')]" + } + }, + "appGroup_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.DesktopVirtualization/applicationGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "appGroup" + ] + }, + "appGroup_roleAssignments": { + "copy": { + "name": "appGroup_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.DesktopVirtualization/applicationGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DesktopVirtualization/applicationGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "appGroup" + ] + }, + "appGroup_diagnosticSettings": { + "copy": { + "name": "appGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DesktopVirtualization/applicationGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "appGroup" + ] + }, + "appGroup_applications": { + "copy": { + "name": "appGroup_applications", + "count": "[length(parameters('applications'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppGroup-App-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('applications')[copyIndex()].name]" + }, + "applicationGroupName": { + "value": "[parameters('name')]" + }, + "description": "[if(contains(parameters('applications')[copyIndex()], 'description'), createObject('value', parameters('applications')[copyIndex()].description), createObject('value', ''))]", + "friendlyName": "[if(contains(parameters('applications')[copyIndex()], 'friendlyName'), createObject('value', parameters('applications')[copyIndex()].friendlyName), createObject('value', parameters('name')))]", + "filePath": { + "value": "[parameters('applications')[copyIndex()].filePath]" + }, + "commandLineSetting": "[if(contains(parameters('applications')[copyIndex()], 'commandLineSetting'), createObject('value', parameters('applications')[copyIndex()].commandLineSetting), createObject('value', 'DoNotAllow'))]", + "commandLineArguments": "[if(contains(parameters('applications')[copyIndex()], 'commandLineArguments'), createObject('value', parameters('applications')[copyIndex()].commandLineArguments), createObject('value', ''))]", + "showInPortal": "[if(contains(parameters('applications')[copyIndex()], 'showInPortal'), createObject('value', parameters('applications')[copyIndex()].showInPortal), createObject('value', false()))]", + "iconPath": "[if(contains(parameters('applications')[copyIndex()], 'iconPath'), createObject('value', parameters('applications')[copyIndex()].iconPath), createObject('value', parameters('applications')[copyIndex()].filePath))]", + "iconIndex": "[if(contains(parameters('applications')[copyIndex()], 'iconIndex'), createObject('value', parameters('applications')[copyIndex()].iconIndex), createObject('value', 0))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "13090481719462571506" + }, + "name": "Azure Virtual Desktop Application Group Application", + "description": "This module deploys an Azure Virtual Desktop Application Group Application." + }, + "parameters": { + "applicationGroupName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Group to create the application(s) in. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application to be created in the Application Group." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Description of the Application." + } + }, + "friendlyName": { + "type": "string", + "metadata": { + "description": "Required. Friendly name of the Application." + } + }, + "filePath": { + "type": "string", + "metadata": { + "description": "Required. Specifies a path for the executable file for the Application." + } + }, + "commandLineSetting": { + "type": "string", + "defaultValue": "DoNotAllow", + "allowedValues": [ + "Allow", + "DoNotAllow", + "Require" + ], + "metadata": { + "description": "Optional. Specifies whether this published Application can be launched with command-line arguments provided by the client, command-line arguments specified at publish time, or no command-line arguments at all." + } + }, + "commandLineArguments": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Command-Line Arguments for the Application." + } + }, + "showInPortal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether to show the RemoteApp program in the RD Web Access server." + } + }, + "iconPath": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Path to icon." + } + }, + "iconIndex": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Index of the icon." + } + } + }, + "resources": [ + { + "type": "Microsoft.DesktopVirtualization/applicationGroups/applications", + "apiVersion": "2023-09-05", + "name": "[format('{0}/{1}', parameters('applicationGroupName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "friendlyName": "[parameters('friendlyName')]", + "filePath": "[parameters('filePath')]", + "commandLineSetting": "[parameters('commandLineSetting')]", + "commandLineArguments": "[parameters('commandLineArguments')]", + "showInPortal": "[parameters('showInPortal')]", + "iconPath": "[parameters('iconPath')]", + "iconIndex": "[parameters('iconIndex')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Application." + }, + "value": "[resourceId('Microsoft.DesktopVirtualization/applicationGroups/applications', parameters('applicationGroupName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Application was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Application." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "appGroup" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the scaling plan." + }, + "value": "[resourceId('Microsoft.DesktopVirtualization/applicationGroups', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the scaling plan was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the scaling plan." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location of the scaling plan." + }, + "value": "[reference('appGroup', '2023-09-05', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..a78bd0236 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,18 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Host Pool to create.') +param hostPoolName string + +resource hostPool 'Microsoft.DesktopVirtualization/hostPools@2022-09-09' = { + name: hostPoolName + location: location + properties: { + hostPoolType: 'Pooled' + loadBalancerType: 'BreadthFirst' + preferredAppGroupType: 'Desktop' + } +} + +@description('The name of the created Host Pool.') +output hostPoolName string = hostPool.name diff --git a/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..bb93aa44a --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,59 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.applicationgroup-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dvagmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + hostPoolName: 'dep-${namePrefix}-hp-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + location: resourceLocation + applicationGroupType: 'Desktop' + hostpoolName: nestedDependencies.outputs.hostPoolName + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..0f75ef232 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/max/dependencies.bicep @@ -0,0 +1,29 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Host Pool to create.') +param hostPoolName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource hostPool 'Microsoft.DesktopVirtualization/hostPools@2022-09-09' = { + name: hostPoolName + location: location + properties: { + hostPoolType: 'Pooled' + loadBalancerType: 'BreadthFirst' + preferredAppGroupType: 'RailApplications' + } +} + +@description('The name of the created Host Pool.') +output hostPoolName string = hostPool.name + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..f2ca109b2 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/max/main.test.bicep @@ -0,0 +1,140 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.applicationgroup-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dvagmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + hostPoolName: 'dep-${namePrefix}-hp-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// Diagnostics +// =========== + +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: substring('dep${uniqueString(deployment().name, resourceLocation)}${serviceShort}03', 0, 24) + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + location: resourceLocation + applicationGroupType: 'RemoteApp' + applications: [ + { + commandLineArguments: '' + commandLineSetting: 'DoNotAllow' + description: 'Notepad by ARM template' + filePath: 'C:\\Windows\\System32\\notepad.exe' + friendlyName: 'Notepad' + iconIndex: 0 + iconPath: 'C:\\Windows\\System32\\notepad.exe' + name: 'notepad' + showInPortal: true + } + { + filePath: 'C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe' + friendlyName: 'Wordpad' + name: 'wordpad' + } + ] + description: 'myDescription' + hostpoolName: nestedDependencies.outputs.hostPoolName + diagnosticSettings: [ + { + name: 'customSetting' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '30eaf006-ee2d-4a95-921c-87dfdb4c2061' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..a78bd0236 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,18 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Host Pool to create.') +param hostPoolName string + +resource hostPool 'Microsoft.DesktopVirtualization/hostPools@2022-09-09' = { + name: hostPoolName + location: location + properties: { + hostPoolType: 'Pooled' + loadBalancerType: 'BreadthFirst' + preferredAppGroupType: 'Desktop' + } +} + +@description('The name of the created Host Pool.') +output hostPoolName string = hostPool.name diff --git a/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..6886168d1 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/application-group/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,87 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework.' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.applicationgroup-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dvagwaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + hostPoolName: 'dep-${namePrefix}-hp-${serviceShort}' + } +} + +// Diagnostics +// =========== + +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: substring('dep${uniqueString(deployment().name, resourceLocation)}${serviceShort}03', 0, 24) + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + location: resourceLocation + applicationGroupType: 'Desktop' + hostpoolName: nestedDependencies.outputs.hostPoolName + diagnosticSettings: [ + { + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/1.1.0/res/desktop-virtualization/application-group/version.json b/avm/1.1.0/res/desktop-virtualization/application-group/version.json new file mode 100644 index 000000000..76049e1c4 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/application-group/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/desktop-virtualization/host-pool/README.md b/avm/1.1.0/res/desktop-virtualization/host-pool/README.md new file mode 100644 index 000000000..2bc40f79d --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/host-pool/README.md @@ -0,0 +1,1615 @@ +# Azure Virtual Desktop Host Pool `[Microsoft.DesktopVirtualization/hostPools]` + +This module deploys an Azure Virtual Desktop Host Pool + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.DesktopVirtualization/hostPools` | [2024-04-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DesktopVirtualization/2024-04-03/hostPools) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/desktop-virtualization/host-pool:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' = { + name: 'hostPoolDeployment' + params: { + // Required parameters + name: 'dvhpmin002' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "dvhpmin002" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/host-pool:' + +// Required parameters +param name = 'dvhpmin002' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' = { + name: 'hostPoolDeployment' + params: { + // Required parameters + name: 'dvhpmax001' + // Non-required parameters + agentUpdate: { + maintenanceWindows: [ + { + dayOfWeek: 'Friday' + hour: 7 + } + { + dayOfWeek: 'Saturday' + hour: 8 + } + ] + maintenanceWindowTimeZone: 'Alaskan Standard Time' + type: 'Scheduled' + useSessionHostLocalTime: false + } + customRdpProperty: 'audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2;' + description: 'My first AVD Host Pool' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + enableTelemetry: true + friendlyName: 'AVDv2' + hostPoolType: 'Pooled' + loadBalancerType: 'BreadthFirst' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + maxSessionLimit: 99999 + personalDesktopAssignmentType: 'Automatic' + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } + ] + publicNetworkAccess: 'Disabled' + roleAssignments: [ + { + name: '52c43567-917f-4c56-8c9b-6cadeef37b51' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vmTemplate: { + customImageId: '' + domain: 'domainname.onmicrosoft.com' + galleryImageOffer: 'office-365' + galleryImagePublisher: 'microsoftwindowsdesktop' + galleryImageSKU: '20h1-evd-o365pp' + imageType: 'Gallery' + imageUri: '' + namePrefix: 'avdv2' + osDiskType: 'StandardSSD_LRS' + useManagedDisks: true + vmSize: { + cores: 2 + id: 'Standard_D2s_v3' + ram: 8 + } + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "dvhpmax001" + }, + // Non-required parameters + "agentUpdate": { + "value": { + "maintenanceWindows": [ + { + "dayOfWeek": "Friday", + "hour": 7 + }, + { + "dayOfWeek": "Saturday", + "hour": 8 + } + ], + "maintenanceWindowTimeZone": "Alaskan Standard Time", + "type": "Scheduled", + "useSessionHostLocalTime": false + } + }, + "customRdpProperty": { + "value": "audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2;" + }, + "description": { + "value": "My first AVD Host Pool" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "logCategoriesAndGroups": [ + { + "categoryGroup": "allLogs" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "enableTelemetry": { + "value": true + }, + "friendlyName": { + "value": "AVDv2" + }, + "hostPoolType": { + "value": "Pooled" + }, + "loadBalancerType": { + "value": "BreadthFirst" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "maxSessionLimit": { + "value": 99999 + }, + "personalDesktopAssignmentType": { + "value": "Automatic" + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "subnetResourceId": "" + }, + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "subnetResourceId": "" + } + ] + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "roleAssignments": { + "value": [ + { + "name": "52c43567-917f-4c56-8c9b-6cadeef37b51", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "vmTemplate": { + "value": { + "customImageId": "", + "domain": "domainname.onmicrosoft.com", + "galleryImageOffer": "office-365", + "galleryImagePublisher": "microsoftwindowsdesktop", + "galleryImageSKU": "20h1-evd-o365pp", + "imageType": "Gallery", + "imageUri": "", + "namePrefix": "avdv2", + "osDiskType": "StandardSSD_LRS", + "useManagedDisks": true, + "vmSize": { + "cores": 2, + "id": "Standard_D2s_v3", + "ram": 8 + } + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/host-pool:' + +// Required parameters +param name = 'dvhpmax001' +// Non-required parameters +param agentUpdate = { + maintenanceWindows: [ + { + dayOfWeek: 'Friday' + hour: 7 + } + { + dayOfWeek: 'Saturday' + hour: 8 + } + ] + maintenanceWindowTimeZone: 'Alaskan Standard Time' + type: 'Scheduled' + useSessionHostLocalTime: false +} +param customRdpProperty = 'audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2;' +param description = 'My first AVD Host Pool' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enableTelemetry = true +param friendlyName = 'AVDv2' +param hostPoolType = 'Pooled' +param loadBalancerType = 'BreadthFirst' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param maxSessionLimit = 99999 +param personalDesktopAssignmentType = 'Automatic' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: '52c43567-917f-4c56-8c9b-6cadeef37b51' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vmTemplate = { + customImageId: '' + domain: 'domainname.onmicrosoft.com' + galleryImageOffer: 'office-365' + galleryImagePublisher: 'microsoftwindowsdesktop' + galleryImageSKU: '20h1-evd-o365pp' + imageType: 'Gallery' + imageUri: '' + namePrefix: 'avdv2' + osDiskType: 'StandardSSD_LRS' + useManagedDisks: true + vmSize: { + cores: 2 + id: 'Standard_D2s_v3' + ram: 8 + } +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' = { + name: 'hostPoolDeployment' + params: { + // Required parameters + name: 'dvhpwaf002' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "dvhpwaf002" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/host-pool:' + +// Required parameters +param name = 'dvhpwaf002' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the scaling plan. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`agentUpdate`](#parameter-agentupdate) | object | The session host configuration for updating agent, monitoring agent, and stack component. | +| [`customRdpProperty`](#parameter-customrdpproperty) | string | Host Pool RDP properties. | +| [`description`](#parameter-description) | string | Description of the scaling plan. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`friendlyName`](#parameter-friendlyname) | string | Friendly name of the scaling plan. | +| [`hostPoolType`](#parameter-hostpooltype) | string | Set this parameter to Personal if you would like to enable Persistent Desktop experience. Defaults to Pooled. | +| [`loadBalancerType`](#parameter-loadbalancertype) | string | Type of load balancer algorithm. | +| [`location`](#parameter-location) | string | Location of the scaling plan. Defaults to resource group location. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`maxSessionLimit`](#parameter-maxsessionlimit) | int | Maximum number of sessions. | +| [`personalDesktopAssignmentType`](#parameter-personaldesktopassignmenttype) | string | Set the type of assignment for a Personal Host Pool type. | +| [`preferredAppGroupType`](#parameter-preferredappgrouptype) | string | The type of preferred application group type, default to Desktop Application Group. | +| [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Set public network access. | +| [`ring`](#parameter-ring) | int | The ring number of HostPool. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ssoadfsAuthority`](#parameter-ssoadfsauthority) | string | URL to customer ADFS server for signing WVD SSO certificates. | +| [`ssoClientId`](#parameter-ssoclientid) | string | ClientId for the registered Relying Party used to issue WVD SSO certificates. | +| [`ssoClientSecretKeyVaultPath`](#parameter-ssoclientsecretkeyvaultpath) | string | Path to Azure KeyVault storing the secret used for communication to ADFS. | +| [`ssoSecretType`](#parameter-ssosecrettype) | string | The type of single sign on Secret Type. | +| [`startVMOnConnect`](#parameter-startvmonconnect) | bool | Enable Start VM on connect to allow users to start the virtual machine from a deallocated state. Important: Custom RBAC role required to power manage VMs. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`tokenValidityLength`](#parameter-tokenvaliditylength) | string | Host Pool token validity length. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the token will be valid for 8 hours. | +| [`validationEnvironment`](#parameter-validationenvironment) | bool | Validation host pools allows you to test service changes before they are deployed to production. When set to true, the Host Pool will be deployed in a validation 'ring' (environment) that receives all the new features (might be less stable). Defaults to false that stands for the stable, production-ready environment. | +| [`vmTemplate`](#parameter-vmtemplate) | object | The necessary information for adding more VMs to this Host Pool. | + +**Generated parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`baseTime`](#parameter-basetime) | string | Do not provide a value! This date value is used to generate a registration token. | + +### Parameter: `name` + +Name of the scaling plan. + +- Required: Yes +- Type: string + +### Parameter: `agentUpdate` + +The session host configuration for updating agent, monitoring agent, and stack component. + +- Required: No +- Type: object +- Default: + ```Bicep + { + maintenanceWindows: [ + { + dayOfWeek: 'Sunday' + hour: 12 + } + ] + type: 'Scheduled' + useSessionHostLocalTime: true + } + ``` + +### Parameter: `customRdpProperty` + +Host Pool RDP properties. + +- Required: No +- Type: string +- Default: `'audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2;'` + +### Parameter: `description` + +Description of the scaling plan. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `friendlyName` + +Friendly name of the scaling plan. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `hostPoolType` + +Set this parameter to Personal if you would like to enable Persistent Desktop experience. Defaults to Pooled. + +- Required: No +- Type: string +- Default: `'Pooled'` +- Allowed: + ```Bicep + [ + 'Personal' + 'Pooled' + ] + ``` + +### Parameter: `loadBalancerType` + +Type of load balancer algorithm. + +- Required: No +- Type: string +- Default: `'BreadthFirst'` +- Allowed: + ```Bicep + [ + 'BreadthFirst' + 'DepthFirst' + 'Persistent' + ] + ``` + +### Parameter: `location` + +Location of the scaling plan. Defaults to resource group location. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `maxSessionLimit` + +Maximum number of sessions. + +- Required: No +- Type: int +- Default: `99999` + +### Parameter: `personalDesktopAssignmentType` + +Set the type of assignment for a Personal Host Pool type. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Automatic' + 'Direct' + ] + ``` + +### Parameter: `preferredAppGroupType` + +The type of preferred application group type, default to Desktop Application Group. + +- Required: No +- Type: string +- Default: `'Desktop'` +- Allowed: + ```Bicep + [ + 'Desktop' + 'None' + 'RailApplications' + ] + ``` + +### Parameter: `privateEndpoints` + +Configuration details for private endpoints. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationSecurityGroupResourceIds`](#parameter-privateendpointsapplicationsecuritygroupresourceids) | array | Application security groups in which the private endpoint IP configuration is included. | +| [`customDnsConfigs`](#parameter-privateendpointscustomdnsconfigs) | array | Custom DNS configurations. | +| [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | +| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | +| [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | +| [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | +| [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | +| [`privateDnsZoneGroup`](#parameter-privateendpointsprivatednszonegroup) | object | The private DNS zone group to configure for the private endpoint. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | +| [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | +| [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | + +### Parameter: `privateEndpoints.subnetResourceId` + +Resource ID of the subnet where the endpoint needs to be created. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.applicationSecurityGroupResourceIds` + +Application security groups in which the private endpoint IP configuration is included. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs` + +Custom DNS configurations. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | FQDN that resolves to private endpoint IP address. | + +### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +A list of private IP addresses of the private endpoint. + +- Required: Yes +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +FQDN that resolves to private endpoint IP address. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.customNetworkInterfaceName` + +The custom name of the network interface attached to the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.ipConfigurations` + +A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsipconfigurationsname) | string | The name of the resource that is unique within a resource group. | +| [`properties`](#parameter-privateendpointsipconfigurationsproperties) | object | Properties of private endpoint IP configurations. | + +### Parameter: `privateEndpoints.ipConfigurations.name` + +The name of the resource that is unique within a resource group. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties` + +Properties of private endpoint IP configurations. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private IP address obtained from the private endpoint's subnet. | + +### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` + +The ID of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.memberName` + +The member name of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` + +A private IP address obtained from the private endpoint's subnet. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.location` + +The location to deploy the private endpoint to. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.lock` + +Specify the type of lock. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-privateendpointslockkind) | string | Specify the type of lock. | +| [`name`](#parameter-privateendpointslockname) | string | Specify the name of lock. | + +### Parameter: `privateEndpoints.lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `privateEndpoints.lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.manualConnectionRequestMessage` + +A message passed to the owner of the remote resource with the manual connection request. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.name` + +The name of the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup` + +The private DNS zone group to configure for the private endpoint. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneGroupConfigs`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigs) | array | The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the Private DNS Zone Group. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs` + +The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneResourceId`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsprivatednszoneresourceid) | string | The resource id of the private DNS zone. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsname) | string | The name of the private DNS zone group config. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.privateDnsZoneResourceId` + +The resource id of the private DNS zone. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.name` + +The name of the private DNS zone group config. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.name` + +The name of the Private DNS Zone Group. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.resourceGroupName` + +Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-privateendpointsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-privateendpointsroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-privateendpointsroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-privateendpointsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-privateendpointsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-privateendpointsroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-privateendpointsroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-privateendpointsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `privateEndpoints.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `privateEndpoints.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `privateEndpoints.service` + +The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.tags` + +Tags to be applied on all resources/resource groups in this deployment. + +- Required: No +- Type: object + +### Parameter: `publicNetworkAccess` + +Set public network access. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + 'EnabledForClientsOnly' + 'EnabledForSessionHostsOnly' + ] + ``` + +### Parameter: `ring` + +The ring number of HostPool. + +- Required: No +- Type: int +- Default: `-1` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Owner'` + - `'Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Application Group Contributor'` + - `'Desktop Virtualization Application Group Contributor'` + - `'Desktop Virtualization Application Group Reader'` + - `'Desktop Virtualization Contributor'` + - `'Desktop Virtualization Host Pool Contributor'` + - `'Desktop Virtualization Host Pool Reader'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Reader'` + - `'Desktop Virtualization Session Host Operator'` + - `'Desktop Virtualization User'` + - `'Desktop Virtualization User Session Operator'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'Desktop Virtualization Workspace Contributor'` + - `'Desktop Virtualization Workspace Reader'` + - `'Managed Application Contributor Role'` + - `'Managed Application Operator Role'` + - `'Managed Applications Reader'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ssoadfsAuthority` + +URL to customer ADFS server for signing WVD SSO certificates. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `ssoClientId` + +ClientId for the registered Relying Party used to issue WVD SSO certificates. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `ssoClientSecretKeyVaultPath` + +Path to Azure KeyVault storing the secret used for communication to ADFS. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `ssoSecretType` + +The type of single sign on Secret Type. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Certificate' + 'CertificateInKeyVault' + 'SharedKey' + 'SharedKeyInKeyVault' + ] + ``` + +### Parameter: `startVMOnConnect` + +Enable Start VM on connect to allow users to start the virtual machine from a deallocated state. Important: Custom RBAC role required to power manage VMs. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `tokenValidityLength` + +Host Pool token validity length. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the token will be valid for 8 hours. + +- Required: No +- Type: string +- Default: `'PT8H'` + +### Parameter: `validationEnvironment` + +Validation host pools allows you to test service changes before they are deployed to production. When set to true, the Host Pool will be deployed in a validation 'ring' (environment) that receives all the new features (might be less stable). Defaults to false that stands for the stable, production-ready environment. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `vmTemplate` + +The necessary information for adding more VMs to this Host Pool. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `baseTime` + +Do not provide a value! This date value is used to generate a registration token. + +- Required: No +- Type: string +- Default: `[utcNow('u')]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location of the host pool. | +| `name` | string | The name of the host pool. | +| `privateEndpoints` | array | The private endpoints of the host pool. | +| `resourceGroupName` | string | The name of the resource group the host pool was created in. | +| `resourceId` | string | The resource ID of the host pool. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/private-endpoint:0.7.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/desktop-virtualization/host-pool/main.bicep b/avm/1.1.0/res/desktop-virtualization/host-pool/main.bicep new file mode 100644 index 000000000..557c4f5f4 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/host-pool/main.bicep @@ -0,0 +1,502 @@ +metadata name = 'Azure Virtual Desktop Host Pool' +metadata description = 'This module deploys an Azure Virtual Desktop Host Pool' + +@sys.description('Required. Name of the scaling plan.') +param name string + +@sys.description('Optional. Location of the scaling plan. Defaults to resource group location.') +param location string = resourceGroup().location + +@sys.description('Optional. Friendly name of the scaling plan.') +param friendlyName string = '' + +@sys.description('Optional. Description of the scaling plan.') +param description string = '' + +@sys.description('Optional. Set this parameter to Personal if you would like to enable Persistent Desktop experience. Defaults to Pooled.') +@allowed([ + 'Personal' + 'Pooled' +]) +param hostPoolType string = 'Pooled' + +@sys.description('Optional. Set public network access.') +@allowed([ + 'Disabled' + 'Enabled' + 'EnabledForClientsOnly' + 'EnabledForSessionHostsOnly' +]) +param publicNetworkAccess string = 'Enabled' + +@sys.description('Optional. Configuration details for private endpoints.') +param privateEndpoints privateEndpointType + +@sys.description('Optional. Set the type of assignment for a Personal Host Pool type.') +@allowed([ + 'Automatic' + 'Direct' + '' +]) +param personalDesktopAssignmentType string = '' + +@sys.description('Optional. Type of load balancer algorithm.') +@allowed([ + 'BreadthFirst' + 'DepthFirst' + 'Persistent' +]) +param loadBalancerType string = 'BreadthFirst' + +@sys.description('Optional. Maximum number of sessions.') +param maxSessionLimit int = 99999 + +@sys.description('Optional. Host Pool RDP properties.') +param customRdpProperty string = 'audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2;' + +@sys.description('Optional. Validation host pools allows you to test service changes before they are deployed to production. When set to true, the Host Pool will be deployed in a validation \'ring\' (environment) that receives all the new features (might be less stable). Defaults to false that stands for the stable, production-ready environment.') +param validationEnvironment bool = false + +@sys.description('Optional. The necessary information for adding more VMs to this Host Pool.') +param vmTemplate object = {} + +@sys.description('Optional. Host Pool token validity length. Usage: \'PT8H\' - valid for 8 hours; \'P5D\' - valid for 5 days; \'P1Y\' - valid for 1 year. When not provided, the token will be valid for 8 hours.') +param tokenValidityLength string = 'PT8H' + +@sys.description('Generated. Do not provide a value! This date value is used to generate a registration token.') +param baseTime string = utcNow('u') + +@sys.description('Optional. The type of preferred application group type, default to Desktop Application Group.') +@allowed([ + 'Desktop' + 'None' + 'RailApplications' +]) +param preferredAppGroupType string = 'Desktop' + +@sys.description('Optional. Enable Start VM on connect to allow users to start the virtual machine from a deallocated state. Important: Custom RBAC role required to power manage VMs.') +param startVMOnConnect bool = false + +@sys.description('Optional. The session host configuration for updating agent, monitoring agent, and stack component.') +param agentUpdate object = { + type: 'Scheduled' + useSessionHostLocalTime: true + maintenanceWindows: [ + { + dayOfWeek: 'Sunday' + hour: 12 + } + ] +} + +@sys.description('Optional. The ring number of HostPool.') +param ring int = -1 + +@sys.description('Optional. URL to customer ADFS server for signing WVD SSO certificates.') +param ssoadfsAuthority string = '' + +@sys.description('Optional. ClientId for the registered Relying Party used to issue WVD SSO certificates.') +param ssoClientId string = '' + +@sys.description('Optional. Path to Azure KeyVault storing the secret used for communication to ADFS.') +#disable-next-line secure-secrets-in-params +param ssoClientSecretKeyVaultPath string = '' + +@sys.description('Optional. The type of single sign on Secret Type.') +@allowed([ + '' + 'Certificate' + 'CertificateInKeyVault' + 'SharedKey' + 'SharedKeyInKeyVault' +]) +#disable-next-line secure-secrets-in-params +param ssoSecretType string = '' + +@sys.description('Optional. Tags of the resource.') +param tags object? + +@sys.description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@sys.description('Optional. The lock settings of the service.') +param lock lockType + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@sys.description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +var builtInRoleNames = { + Owner: '/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635' + Contributor: '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + Reader: '/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7' + 'Role Based Access Control Administrator': '/providers/Microsoft.Authorization/roleDefinitions/f58310d9-a9f6-439a-9e8d-f62e7b41a168' + 'User Access Administrator': '/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + 'Application Group Contributor': '/providers/Microsoft.Authorization/roleDefinitions/ca6382a4-1721-4bcf-a114-ff0c70227b6b' + 'Desktop Virtualization Application Group Contributor': '/providers/Microsoft.Authorization/roleDefinitions/86240b0e-9422-4c43-887b-b61143f32ba8' + 'Desktop Virtualization Application Group Reader': '/providers/Microsoft.Authorization/roleDefinitions/aebf23d0-b568-4e86-b8f9-fe83a2c6ab55' + 'Desktop Virtualization Contributor': '/providers/Microsoft.Authorization/roleDefinitions/082f0a83-3be5-4ba1-904c-961cca79b387' + 'Desktop Virtualization Host Pool Contributor': '/providers/Microsoft.Authorization/roleDefinitions/e307426c-f9b6-4e81-87de-d99efb3c32bc' + 'Desktop Virtualization Host Pool Reader': '/providers/Microsoft.Authorization/roleDefinitions/ceadfde2-b300-400a-ab7b-6143895aa822' + 'Desktop Virtualization Power On Off Contributor': '/providers/Microsoft.Authorization/roleDefinitions/40c5ff49-9181-41f8-ae61-143b0e78555e' + 'Desktop Virtualization Reader': '/providers/Microsoft.Authorization/roleDefinitions/49a72310-ab8d-41df-bbb0-79b649203868' + 'Desktop Virtualization Session Host Operator': '/providers/Microsoft.Authorization/roleDefinitions/2ad6aaab-ead9-4eaa-8ac5-da422f562408' + 'Desktop Virtualization User': '/providers/Microsoft.Authorization/roleDefinitions/1d18fff3-a72a-46b5-b4a9-0b38a3cd7e63' + 'Desktop Virtualization User Session Operator': '/providers/Microsoft.Authorization/roleDefinitions/ea4bfff8-7fb4-485a-aadd-d4129a0ffaa6' + 'Desktop Virtualization Virtual Machine Contributor': '/providers/Microsoft.Authorization/roleDefinitions/a959dbd1-f747-45e3-8ba6-dd80f235f97c' + 'Desktop Virtualization Workspace Contributor': '/providers/Microsoft.Authorization/roleDefinitions/21efdde3-836f-432b-bf3d-3e8e734d4b2b' + 'Desktop Virtualization Workspace Reader': '/providers/Microsoft.Authorization/roleDefinitions/0fa44ee9-7a7d-466b-9bb2-2bf446b1204d' + 'Managed Application Contributor Role': '/providers/Microsoft.Authorization/roleDefinitions/641177b8-a67a-45b9-a033-47bc880bb21e' + 'Managed Application Operator Role': '/providers/Microsoft.Authorization/roleDefinitions/c7393b34-138c-406f-901b-d8cf2b17e6ae' + 'Managed Applications Reader': '/providers/Microsoft.Authorization/roleDefinitions/b9331d33-8a36-4f8c-b097-4f54124fdb44' +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.res.desktopvirtualization-hostpool.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource hostPool 'Microsoft.DesktopVirtualization/hostPools@2024-04-03' = { + name: name + location: location + tags: tags + properties: { + friendlyName: friendlyName + description: description + hostPoolType: hostPoolType + publicNetworkAccess: publicNetworkAccess + customRdpProperty: customRdpProperty + personalDesktopAssignmentType: any(personalDesktopAssignmentType) + preferredAppGroupType: preferredAppGroupType + maxSessionLimit: maxSessionLimit + loadBalancerType: loadBalancerType + startVMOnConnect: startVMOnConnect + validationEnvironment: validationEnvironment + registrationInfo: { + expirationTime: dateTimeAdd(baseTime, tokenValidityLength) + token: null + registrationTokenOperation: 'Update' + } + vmTemplate: ((!empty(vmTemplate)) ? null : string(vmTemplate)) + agentUpdate: agentUpdate + ring: ring != -1 ? ring : null + ssoadfsAuthority: ssoadfsAuthority + ssoClientId: ssoClientId + ssoClientSecretKeyVaultPath: ssoClientSecretKeyVaultPath + ssoSecretType: ssoSecretType + } +} + +module hostPool_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.7.1' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-hostPool-PrivateEndpoint-${index}' + scope: resourceGroup(privateEndpoint.?resourceGroupName ?? '') + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(hostPool.id, '/'))}-${privateEndpoint.?service ?? 'connection'}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(hostPool.id, '/'))}-${privateEndpoint.?service ?? 'connection'}-${index}' + properties: { + privateLinkServiceId: hostPool.id + groupIds: [ + privateEndpoint.?service ?? 'connection' + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(hostPool.id, '/'))}-${privateEndpoint.?service ?? 'connection'}-${index}' + properties: { + privateLinkServiceId: hostPool.id + groupIds: [ + privateEndpoint.?service ?? 'connection' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] + : null + subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry + location: privateEndpoint.?location ?? reference( + split(privateEndpoint.subnetResourceId, '/subnets/')[0], + '2020-06-01', + 'Full' + ).location + lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } + } +] + +resource hostPool_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: hostPool +} + +resource hostPool_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(hostPool.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: hostPool + } +] + +resource hostPool_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: hostPool + } +] + +@sys.description('The resource ID of the host pool.') +output resourceId string = hostPool.id + +@sys.description('The name of the resource group the host pool was created in.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The name of the host pool.') +output name string = hostPool.name + +@sys.description('The location of the host pool.') +output location string = hostPool.location + +@sys.description('The private endpoints of the host pool.') +output privateEndpoints array = [ + for (pe, i) in (!empty(privateEndpoints) ? array(privateEndpoints) : []): { + name: hostPool_privateEndpoints[i].outputs.name + resourceId: hostPool_privateEndpoints[i].outputs.resourceId + groupId: hostPool_privateEndpoints[i].outputs.groupId + customDnsConfig: hostPool_privateEndpoints[i].outputs.customDnsConfig + networkInterfaceIds: hostPool_privateEndpoints[i].outputs.networkInterfaceIds + } +] + +// ================ // +// Definitions // +// ================ // + +type diagnosticSettingType = { + @sys.description('Optional. The name of diagnostic setting.') + name: string? + + @sys.description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @sys.description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @sys.description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @sys.description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @sys.description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @sys.description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @sys.description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @sys.description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @sys.description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @sys.description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? + +type roleAssignmentType = { + @sys.description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @sys.description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @sys.description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @sys.description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @sys.description('Optional. The description of the role assignment.') + 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".') + condition: string? + + @sys.description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @sys.description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type privateEndpointType = { + @sys.description('Optional. The name of the private endpoint.') + name: string? + + @sys.description('Optional. The location to deploy the private endpoint to.') + location: string? + + @sys.description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + + @sys.description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') + service: string? + + @sys.description('Required. Resource ID of the subnet where the endpoint needs to be created.') + subnetResourceId: string + + @sys.description('Optional. The private DNS zone group to configure for the private endpoint.') + privateDnsZoneGroup: { + @sys.description('Optional. The name of the Private DNS Zone Group.') + name: string? + + @sys.description('Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones.') + privateDnsZoneGroupConfigs: { + @sys.description('Optional. The name of the private DNS zone group config.') + name: string? + + @sys.description('Required. The resource id of the private DNS zone.') + privateDnsZoneResourceId: string + }[] + }? + + @sys.description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @sys.description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + + @sys.description('Optional. Custom DNS configurations.') + customDnsConfigs: { + @sys.description('Optional. FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @sys.description('Required. A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[]? + + @sys.description('Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints.') + ipConfigurations: { + @sys.description('Required. The name of the resource that is unique within a resource group.') + name: string + + @sys.description('Required. Properties of private endpoint IP configurations.') + properties: { + @sys.description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') + groupId: string + + @sys.description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') + memberName: string + + @sys.description('Required. A private IP address obtained from the private endpoint\'s subnet.') + privateIPAddress: string + } + }[]? + + @sys.description('Optional. Application security groups in which the private endpoint IP configuration is included.') + applicationSecurityGroupResourceIds: string[]? + + @sys.description('Optional. The custom name of the network interface attached to the private endpoint.') + customNetworkInterfaceName: string? + + @sys.description('Optional. Specify the type of lock.') + lock: lockType + + @sys.description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @sys.description('Optional. Tags to be applied on all resources/resource groups in this deployment.') + tags: object? + + @sys.description('Optional. Enable/Disable usage telemetry for module.') + enableTelemetry: bool? + + @sys.description('Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.') + resourceGroupName: string? +}[]? + +type lockType = { + @sys.description('Optional. Specify the name of lock.') + name: string? + + @sys.description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? diff --git a/avm/1.1.0/res/desktop-virtualization/host-pool/main.json b/avm/1.1.0/res/desktop-virtualization/host-pool/main.json new file mode 100644 index 000000000..263f0fd06 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/host-pool/main.json @@ -0,0 +1,1630 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "13222003463237903084" + }, + "name": "Azure Virtual Desktop Host Pool", + "description": "This module deploys an Azure Virtual Desktop Host Pool" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroup": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the scaling plan." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the scaling plan. Defaults to resource group location." + } + }, + "friendlyName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Friendly name of the scaling plan." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Description of the scaling plan." + } + }, + "hostPoolType": { + "type": "string", + "defaultValue": "Pooled", + "allowedValues": [ + "Personal", + "Pooled" + ], + "metadata": { + "description": "Optional. Set this parameter to Personal if you would like to enable Persistent Desktop experience. Defaults to Pooled." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled", + "EnabledForClientsOnly", + "EnabledForSessionHostsOnly" + ], + "metadata": { + "description": "Optional. Set public network access." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints." + } + }, + "personalDesktopAssignmentType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Automatic", + "Direct", + "" + ], + "metadata": { + "description": "Optional. Set the type of assignment for a Personal Host Pool type." + } + }, + "loadBalancerType": { + "type": "string", + "defaultValue": "BreadthFirst", + "allowedValues": [ + "BreadthFirst", + "DepthFirst", + "Persistent" + ], + "metadata": { + "description": "Optional. Type of load balancer algorithm." + } + }, + "maxSessionLimit": { + "type": "int", + "defaultValue": 99999, + "metadata": { + "description": "Optional. Maximum number of sessions." + } + }, + "customRdpProperty": { + "type": "string", + "defaultValue": "audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2;", + "metadata": { + "description": "Optional. Host Pool RDP properties." + } + }, + "validationEnvironment": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Validation host pools allows you to test service changes before they are deployed to production. When set to true, the Host Pool will be deployed in a validation 'ring' (environment) that receives all the new features (might be less stable). Defaults to false that stands for the stable, production-ready environment." + } + }, + "vmTemplate": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The necessary information for adding more VMs to this Host Pool." + } + }, + "tokenValidityLength": { + "type": "string", + "defaultValue": "PT8H", + "metadata": { + "description": "Optional. Host Pool token validity length. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the token will be valid for 8 hours." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to generate a registration token." + } + }, + "preferredAppGroupType": { + "type": "string", + "defaultValue": "Desktop", + "allowedValues": [ + "Desktop", + "None", + "RailApplications" + ], + "metadata": { + "description": "Optional. The type of preferred application group type, default to Desktop Application Group." + } + }, + "startVMOnConnect": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable Start VM on connect to allow users to start the virtual machine from a deallocated state. Important: Custom RBAC role required to power manage VMs." + } + }, + "agentUpdate": { + "type": "object", + "defaultValue": { + "type": "Scheduled", + "useSessionHostLocalTime": true, + "maintenanceWindows": [ + { + "dayOfWeek": "Sunday", + "hour": 12 + } + ] + }, + "metadata": { + "description": "Optional. The session host configuration for updating agent, monitoring agent, and stack component." + } + }, + "ring": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. The ring number of HostPool." + } + }, + "ssoadfsAuthority": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. URL to customer ADFS server for signing WVD SSO certificates." + } + }, + "ssoClientId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ClientId for the registered Relying Party used to issue WVD SSO certificates." + } + }, + "ssoClientSecretKeyVaultPath": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Path to Azure KeyVault storing the secret used for communication to ADFS." + } + }, + "ssoSecretType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Certificate", + "CertificateInKeyVault", + "SharedKey", + "SharedKeyInKeyVault" + ], + "metadata": { + "description": "Optional. The type of single sign on Secret Type." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Owner": "/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635", + "Contributor": "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c", + "Reader": "/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7", + "Role Based Access Control Administrator": "/providers/Microsoft.Authorization/roleDefinitions/f58310d9-a9f6-439a-9e8d-f62e7b41a168", + "User Access Administrator": "/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9", + "Application Group Contributor": "/providers/Microsoft.Authorization/roleDefinitions/ca6382a4-1721-4bcf-a114-ff0c70227b6b", + "Desktop Virtualization Application Group Contributor": "/providers/Microsoft.Authorization/roleDefinitions/86240b0e-9422-4c43-887b-b61143f32ba8", + "Desktop Virtualization Application Group Reader": "/providers/Microsoft.Authorization/roleDefinitions/aebf23d0-b568-4e86-b8f9-fe83a2c6ab55", + "Desktop Virtualization Contributor": "/providers/Microsoft.Authorization/roleDefinitions/082f0a83-3be5-4ba1-904c-961cca79b387", + "Desktop Virtualization Host Pool Contributor": "/providers/Microsoft.Authorization/roleDefinitions/e307426c-f9b6-4e81-87de-d99efb3c32bc", + "Desktop Virtualization Host Pool Reader": "/providers/Microsoft.Authorization/roleDefinitions/ceadfde2-b300-400a-ab7b-6143895aa822", + "Desktop Virtualization Power On Off Contributor": "/providers/Microsoft.Authorization/roleDefinitions/40c5ff49-9181-41f8-ae61-143b0e78555e", + "Desktop Virtualization Reader": "/providers/Microsoft.Authorization/roleDefinitions/49a72310-ab8d-41df-bbb0-79b649203868", + "Desktop Virtualization Session Host Operator": "/providers/Microsoft.Authorization/roleDefinitions/2ad6aaab-ead9-4eaa-8ac5-da422f562408", + "Desktop Virtualization User": "/providers/Microsoft.Authorization/roleDefinitions/1d18fff3-a72a-46b5-b4a9-0b38a3cd7e63", + "Desktop Virtualization User Session Operator": "/providers/Microsoft.Authorization/roleDefinitions/ea4bfff8-7fb4-485a-aadd-d4129a0ffaa6", + "Desktop Virtualization Virtual Machine Contributor": "/providers/Microsoft.Authorization/roleDefinitions/a959dbd1-f747-45e3-8ba6-dd80f235f97c", + "Desktop Virtualization Workspace Contributor": "/providers/Microsoft.Authorization/roleDefinitions/21efdde3-836f-432b-bf3d-3e8e734d4b2b", + "Desktop Virtualization Workspace Reader": "/providers/Microsoft.Authorization/roleDefinitions/0fa44ee9-7a7d-466b-9bb2-2bf446b1204d", + "Managed Application Contributor Role": "/providers/Microsoft.Authorization/roleDefinitions/641177b8-a67a-45b9-a033-47bc880bb21e", + "Managed Application Operator Role": "/providers/Microsoft.Authorization/roleDefinitions/c7393b34-138c-406f-901b-d8cf2b17e6ae", + "Managed Applications Reader": "/providers/Microsoft.Authorization/roleDefinitions/b9331d33-8a36-4f8c-b097-4f54124fdb44" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.res.desktopvirtualization-hostpool.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "hostPool": { + "type": "Microsoft.DesktopVirtualization/hostPools", + "apiVersion": "2024-04-03", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "friendlyName": "[parameters('friendlyName')]", + "description": "[parameters('description')]", + "hostPoolType": "[parameters('hostPoolType')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "customRdpProperty": "[parameters('customRdpProperty')]", + "personalDesktopAssignmentType": "[parameters('personalDesktopAssignmentType')]", + "preferredAppGroupType": "[parameters('preferredAppGroupType')]", + "maxSessionLimit": "[parameters('maxSessionLimit')]", + "loadBalancerType": "[parameters('loadBalancerType')]", + "startVMOnConnect": "[parameters('startVMOnConnect')]", + "validationEnvironment": "[parameters('validationEnvironment')]", + "registrationInfo": { + "expirationTime": "[dateTimeAdd(parameters('baseTime'), parameters('tokenValidityLength'))]", + "token": null, + "registrationTokenOperation": "Update" + }, + "vmTemplate": "[if(not(empty(parameters('vmTemplate'))), null(), string(parameters('vmTemplate')))]", + "agentUpdate": "[parameters('agentUpdate')]", + "ring": "[if(not(equals(parameters('ring'), -1)), parameters('ring'), null())]", + "ssoadfsAuthority": "[parameters('ssoadfsAuthority')]", + "ssoClientId": "[parameters('ssoClientId')]", + "ssoClientSecretKeyVaultPath": "[parameters('ssoClientSecretKeyVaultPath')]", + "ssoSecretType": "[parameters('ssoSecretType')]" + } + }, + "hostPool_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.DesktopVirtualization/hostPools/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "hostPool" + ] + }, + "hostPool_roleAssignments": { + "copy": { + "name": "hostPool_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.DesktopVirtualization/hostPools/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "hostPool" + ] + }, + "hostPool_diagnosticSettings": { + "copy": { + "name": "hostPool_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DesktopVirtualization/hostPools/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "hostPool" + ] + }, + "hostPool_privateEndpoints": { + "copy": { + "name": "hostPool_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-hostPool-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "1277254088602407590" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + } + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5805178546717255803" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" + }, + "customDnsConfig": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceIds": { + "type": "array", + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + }, + "value": "[reference('privateEndpoint').networkInterfaces]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(and(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds', 0), ''), if(and(not(empty(reference('privateEndpoint').privateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds', 0), ''), ''))]" + } + } + } + }, + "dependsOn": [ + "hostPool" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the host pool." + }, + "value": "[resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the host pool was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the host pool." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location of the host pool." + }, + "value": "[reference('hostPool', '2024-04-03', 'full').location]" + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the host pool." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", + "input": { + "name": "[reference(format('hostPool_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('hostPool_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('hostPool_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('hostPool_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('hostPool_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..6c16ed846 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,42 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.hostpools-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dvhpmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}002' + location: resourceLocation + } +} diff --git a/avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..0bc4ab686 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/max/dependencies.bicep @@ -0,0 +1,60 @@ +@sys.description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-01-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.wvd.microsoft.com' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..e0d1e88fe --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/max/main.test.bicep @@ -0,0 +1,179 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.hostpools-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dvhpmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// Diagnostics +// =========== + +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}03' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + customRdpProperty: 'audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2;' + enableTelemetry: true + diagnosticSettings: [ + { + name: 'customSetting' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + description: 'My first AVD Host Pool' + friendlyName: 'AVDv2' + hostPoolType: 'Pooled' + publicNetworkAccess: 'Disabled' + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + loadBalancerType: 'BreadthFirst' + location: resourceLocation + maxSessionLimit: 99999 + personalDesktopAssignmentType: 'Automatic' + vmTemplate: { + customImageId: null + domain: 'domainname.onmicrosoft.com' + galleryImageOffer: 'office-365' + galleryImagePublisher: 'microsoftwindowsdesktop' + galleryImageSKU: '20h1-evd-o365pp' + imageType: 'Gallery' + imageUri: null + namePrefix: 'avdv2' + osDiskType: 'StandardSSD_LRS' + useManagedDisks: true + vmSize: { + cores: 2 + id: 'Standard_D2s_v3' + ram: 8 + } + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '52c43567-917f-4c56-8c9b-6cadeef37b51' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + agentUpdate: { + type: 'Scheduled' + useSessionHostLocalTime: false + maintenanceWindowTimeZone: 'Alaskan Standard Time' + maintenanceWindows: [ + { + hour: 7 + dayOfWeek: 'Friday' + } + { + hour: 8 + dayOfWeek: 'Saturday' + } + ] + } + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] +} diff --git a/avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..2b745bec0 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/host-pool/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,73 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.hostpools-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dvhpwaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +// Diagnostics +// =========== + +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}03' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}002' + location: resourceLocation + diagnosticSettings: [ + { + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + diagnosticDependencies + ] +} diff --git a/avm/1.1.0/res/desktop-virtualization/host-pool/version.json b/avm/1.1.0/res/desktop-virtualization/host-pool/version.json new file mode 100644 index 000000000..ea4f3b6e6 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/host-pool/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/desktop-virtualization/scaling-plan/README.md b/avm/1.1.0/res/desktop-virtualization/scaling-plan/README.md new file mode 100644 index 000000000..4482d692f --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/scaling-plan/README.md @@ -0,0 +1,1164 @@ +# Azure Virtual Desktop Scaling Plan `[Microsoft.DesktopVirtualization/scalingPlans]` + +This module deploys an Azure Virtual Desktop Scaling Plan. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.DesktopVirtualization/scalingPlans` | [2023-09-05](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DesktopVirtualization/2023-09-05/scalingPlans) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/desktop-virtualization/scaling-plan:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan:' = { + name: 'scalingPlanDeployment' + params: { + // Required parameters + name: 'dvspmin002' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "dvspmin002" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/scaling-plan:' + +// Required parameters +param name = 'dvspmin002' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan:' = { + name: 'scalingPlanDeployment' + params: { + // Required parameters + name: 'dvspmax002' + // Non-required parameters + description: 'myDescription' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + friendlyName: 'friendlyName' + hostPoolReferences: [ + { + hostPoolArmPath: '' + scalingPlanEnabled: true + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'c2c1c560-2169-405a-a8dc-7427e403e5ac' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + schedules: [ + { + daysOfWeek: [ + 'Friday' + 'Monday' + 'Thursday' + 'Wednesday' + ] + name: 'WeekdaySchedule' + offPeakLoadBalancingAlgorithm: 'DepthFirst' + offPeakStartTime: { + hour: 20 + minute: 0 + } + peakLoadBalancingAlgorithm: 'DepthFirst' + peakStartTime: { + hour: 9 + minute: 0 + } + rampDownCapacityThresholdPct: 90 + rampDownForceLogoffUsers: true + rampDownLoadBalancingAlgorithm: 'DepthFirst' + rampDownMinimumHostsPct: 0 + rampDownNotificationMessage: 'You will be logged off in 30 min. Make sure to save your work.' + rampDownStartTime: { + hour: 18 + minute: 0 + } + rampDownStopHostsWhen: 'ZeroActiveSessions' + rampDownWaitTimeMinutes: 30 + rampUpCapacityThresholdPct: 80 + rampUpLoadBalancingAlgorithm: 'BreadthFirst' + rampUpMinimumHostsPct: 20 + rampUpStartTime: { + hour: 7 + minute: 0 + } + } + { + daysOfWeek: [ + 'Tuesday' + ] + name: 'weekdaysSchedule-agent-updates' + offPeakLoadBalancingAlgorithm: 'DepthFirst' + offPeakStartTime: { + hour: 20 + minute: 0 + } + peakLoadBalancingAlgorithm: 'DepthFirst' + peakStartTime: { + hour: 9 + minute: 0 + } + rampDownCapacityThresholdPct: 90 + rampDownForceLogoffUsers: true + rampDownLoadBalancingAlgorithm: 'DepthFirst' + rampDownMinimumHostsPct: 0 + rampDownNotificationMessage: 'You will be logged off in 30 min. Make sure to save your work.' + rampDownStartTime: { + hour: 19 + minute: 0 + } + rampDownStopHostsWhen: 'ZeroActiveSessions' + rampDownWaitTimeMinutes: 30 + rampUpCapacityThresholdPct: 80 + rampUpLoadBalancingAlgorithm: 'BreadthFirst' + rampUpMinimumHostsPct: 20 + rampUpStartTime: { + hour: 7 + minute: 0 + } + } + { + daysOfWeek: [ + 'Saturday' + 'Sunday' + ] + name: 'WeekendSchedule' + offPeakLoadBalancingAlgorithm: 'DepthFirst' + offPeakStartTime: { + hour: 18 + minute: 0 + } + peakLoadBalancingAlgorithm: 'DepthFirst' + peakStartTime: { + hour: 10 + minute: 0 + } + rampDownCapacityThresholdPct: 90 + rampDownForceLogoffUsers: true + rampDownLoadBalancingAlgorithm: 'DepthFirst' + rampDownMinimumHostsPct: 0 + rampDownNotificationMessage: 'You will be logged off in 30 min. Make sure to save your work.' + rampDownStartTime: { + hour: 16 + minute: 0 + } + rampDownStopHostsWhen: 'ZeroActiveSessions' + rampDownWaitTimeMinutes: 30 + rampUpCapacityThresholdPct: 90 + rampUpLoadBalancingAlgorithm: 'DepthFirst' + rampUpMinimumHostsPct: 0 + rampUpStartTime: { + hour: 9 + minute: 0 + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "dvspmax002" + }, + // Non-required parameters + "description": { + "value": "myDescription" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "logCategoriesAndGroups": [ + { + "categoryGroup": "allLogs" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "friendlyName": { + "value": "friendlyName" + }, + "hostPoolReferences": { + "value": [ + { + "hostPoolArmPath": "", + "scalingPlanEnabled": true + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "c2c1c560-2169-405a-a8dc-7427e403e5ac", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "schedules": { + "value": [ + { + "daysOfWeek": [ + "Friday", + "Monday", + "Thursday", + "Wednesday" + ], + "name": "WeekdaySchedule", + "offPeakLoadBalancingAlgorithm": "DepthFirst", + "offPeakStartTime": { + "hour": 20, + "minute": 0 + }, + "peakLoadBalancingAlgorithm": "DepthFirst", + "peakStartTime": { + "hour": 9, + "minute": 0 + }, + "rampDownCapacityThresholdPct": 90, + "rampDownForceLogoffUsers": true, + "rampDownLoadBalancingAlgorithm": "DepthFirst", + "rampDownMinimumHostsPct": 0, + "rampDownNotificationMessage": "You will be logged off in 30 min. Make sure to save your work.", + "rampDownStartTime": { + "hour": 18, + "minute": 0 + }, + "rampDownStopHostsWhen": "ZeroActiveSessions", + "rampDownWaitTimeMinutes": 30, + "rampUpCapacityThresholdPct": 80, + "rampUpLoadBalancingAlgorithm": "BreadthFirst", + "rampUpMinimumHostsPct": 20, + "rampUpStartTime": { + "hour": 7, + "minute": 0 + } + }, + { + "daysOfWeek": [ + "Tuesday" + ], + "name": "weekdaysSchedule-agent-updates", + "offPeakLoadBalancingAlgorithm": "DepthFirst", + "offPeakStartTime": { + "hour": 20, + "minute": 0 + }, + "peakLoadBalancingAlgorithm": "DepthFirst", + "peakStartTime": { + "hour": 9, + "minute": 0 + }, + "rampDownCapacityThresholdPct": 90, + "rampDownForceLogoffUsers": true, + "rampDownLoadBalancingAlgorithm": "DepthFirst", + "rampDownMinimumHostsPct": 0, + "rampDownNotificationMessage": "You will be logged off in 30 min. Make sure to save your work.", + "rampDownStartTime": { + "hour": 19, + "minute": 0 + }, + "rampDownStopHostsWhen": "ZeroActiveSessions", + "rampDownWaitTimeMinutes": 30, + "rampUpCapacityThresholdPct": 80, + "rampUpLoadBalancingAlgorithm": "BreadthFirst", + "rampUpMinimumHostsPct": 20, + "rampUpStartTime": { + "hour": 7, + "minute": 0 + } + }, + { + "daysOfWeek": [ + "Saturday", + "Sunday" + ], + "name": "WeekendSchedule", + "offPeakLoadBalancingAlgorithm": "DepthFirst", + "offPeakStartTime": { + "hour": 18, + "minute": 0 + }, + "peakLoadBalancingAlgorithm": "DepthFirst", + "peakStartTime": { + "hour": 10, + "minute": 0 + }, + "rampDownCapacityThresholdPct": 90, + "rampDownForceLogoffUsers": true, + "rampDownLoadBalancingAlgorithm": "DepthFirst", + "rampDownMinimumHostsPct": 0, + "rampDownNotificationMessage": "You will be logged off in 30 min. Make sure to save your work.", + "rampDownStartTime": { + "hour": 16, + "minute": 0 + }, + "rampDownStopHostsWhen": "ZeroActiveSessions", + "rampDownWaitTimeMinutes": 30, + "rampUpCapacityThresholdPct": 90, + "rampUpLoadBalancingAlgorithm": "DepthFirst", + "rampUpMinimumHostsPct": 0, + "rampUpStartTime": { + "hour": 9, + "minute": 0 + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/scaling-plan:' + +// Required parameters +param name = 'dvspmax002' +// Non-required parameters +param description = 'myDescription' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param friendlyName = 'friendlyName' +param hostPoolReferences = [ + { + hostPoolArmPath: '' + scalingPlanEnabled: true + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'c2c1c560-2169-405a-a8dc-7427e403e5ac' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param schedules = [ + { + daysOfWeek: [ + 'Friday' + 'Monday' + 'Thursday' + 'Wednesday' + ] + name: 'WeekdaySchedule' + offPeakLoadBalancingAlgorithm: 'DepthFirst' + offPeakStartTime: { + hour: 20 + minute: 0 + } + peakLoadBalancingAlgorithm: 'DepthFirst' + peakStartTime: { + hour: 9 + minute: 0 + } + rampDownCapacityThresholdPct: 90 + rampDownForceLogoffUsers: true + rampDownLoadBalancingAlgorithm: 'DepthFirst' + rampDownMinimumHostsPct: 0 + rampDownNotificationMessage: 'You will be logged off in 30 min. Make sure to save your work.' + rampDownStartTime: { + hour: 18 + minute: 0 + } + rampDownStopHostsWhen: 'ZeroActiveSessions' + rampDownWaitTimeMinutes: 30 + rampUpCapacityThresholdPct: 80 + rampUpLoadBalancingAlgorithm: 'BreadthFirst' + rampUpMinimumHostsPct: 20 + rampUpStartTime: { + hour: 7 + minute: 0 + } + } + { + daysOfWeek: [ + 'Tuesday' + ] + name: 'weekdaysSchedule-agent-updates' + offPeakLoadBalancingAlgorithm: 'DepthFirst' + offPeakStartTime: { + hour: 20 + minute: 0 + } + peakLoadBalancingAlgorithm: 'DepthFirst' + peakStartTime: { + hour: 9 + minute: 0 + } + rampDownCapacityThresholdPct: 90 + rampDownForceLogoffUsers: true + rampDownLoadBalancingAlgorithm: 'DepthFirst' + rampDownMinimumHostsPct: 0 + rampDownNotificationMessage: 'You will be logged off in 30 min. Make sure to save your work.' + rampDownStartTime: { + hour: 19 + minute: 0 + } + rampDownStopHostsWhen: 'ZeroActiveSessions' + rampDownWaitTimeMinutes: 30 + rampUpCapacityThresholdPct: 80 + rampUpLoadBalancingAlgorithm: 'BreadthFirst' + rampUpMinimumHostsPct: 20 + rampUpStartTime: { + hour: 7 + minute: 0 + } + } + { + daysOfWeek: [ + 'Saturday' + 'Sunday' + ] + name: 'WeekendSchedule' + offPeakLoadBalancingAlgorithm: 'DepthFirst' + offPeakStartTime: { + hour: 18 + minute: 0 + } + peakLoadBalancingAlgorithm: 'DepthFirst' + peakStartTime: { + hour: 10 + minute: 0 + } + rampDownCapacityThresholdPct: 90 + rampDownForceLogoffUsers: true + rampDownLoadBalancingAlgorithm: 'DepthFirst' + rampDownMinimumHostsPct: 0 + rampDownNotificationMessage: 'You will be logged off in 30 min. Make sure to save your work.' + rampDownStartTime: { + hour: 16 + minute: 0 + } + rampDownStopHostsWhen: 'ZeroActiveSessions' + rampDownWaitTimeMinutes: 30 + rampUpCapacityThresholdPct: 90 + rampUpLoadBalancingAlgorithm: 'DepthFirst' + rampUpMinimumHostsPct: 0 + rampUpStartTime: { + hour: 9 + minute: 0 + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan:' = { + name: 'scalingPlanDeployment' + params: { + // Required parameters + name: 'dvspwaf002' + // Non-required parameters + description: 'myDescription' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + friendlyName: 'myFriendlyName' + location: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "dvspwaf002" + }, + // Non-required parameters + "description": { + "value": "myDescription" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "friendlyName": { + "value": "myFriendlyName" + }, + "location": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/scaling-plan:' + +// Required parameters +param name = 'dvspwaf002' +// Non-required parameters +param description = 'myDescription' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param friendlyName = 'myFriendlyName' +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Scaling Plan. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | Description of the Scaling Plan. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`exclusionTag`](#parameter-exclusiontag) | string | Exclusion tag to be used for exclusion of VMs from Scaling Plan. | +| [`friendlyName`](#parameter-friendlyname) | string | Friendly name of the Scaling Plan. | +| [`hostPoolReferences`](#parameter-hostpoolreferences) | array | Host pool references of the Scaling Plan. | +| [`hostPoolType`](#parameter-hostpooltype) | string | Host pool type of the Scaling Plan. | +| [`location`](#parameter-location) | string | Location of the Scaling Plan. Defaults to resource group location. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`schedules`](#parameter-schedules) | array | Schedules of the Scaling Plan. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`timeZone`](#parameter-timezone) | string | Time zone of the Scaling Plan. Defaults to UTC. | + +### Parameter: `name` + +Name of the Scaling Plan. + +- Required: Yes +- Type: string + +### Parameter: `description` + +Description of the Scaling Plan. + +- Required: No +- Type: string +- Default: `[parameters('name')]` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `exclusionTag` + +Exclusion tag to be used for exclusion of VMs from Scaling Plan. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `friendlyName` + +Friendly name of the Scaling Plan. + +- Required: No +- Type: string +- Default: `[parameters('name')]` + +### Parameter: `hostPoolReferences` + +Host pool references of the Scaling Plan. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `hostPoolType` + +Host pool type of the Scaling Plan. + +- Required: No +- Type: string +- Default: `'Pooled'` +- Allowed: + ```Bicep + [ + 'Personal' + 'Pooled' + ] + ``` + +### Parameter: `location` + +Location of the Scaling Plan. Defaults to resource group location. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Owner'` + - `'Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Application Group Contributor'` + - `'Desktop Virtualization Application Group Contributor'` + - `'Desktop Virtualization Application Group Reader'` + - `'Desktop Virtualization Contributor'` + - `'Desktop Virtualization Host Pool Contributor'` + - `'Desktop Virtualization Host Pool Reader'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Reader'` + - `'Desktop Virtualization Session Host Operator'` + - `'Desktop Virtualization User'` + - `'Desktop Virtualization User Session Operator'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'Desktop Virtualization Workspace Contributor'` + - `'Desktop Virtualization Workspace Reader'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `schedules` + +Schedules of the Scaling Plan. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `timeZone` + +Time zone of the Scaling Plan. Defaults to UTC. + +- Required: No +- Type: string +- Default: `'UTC'` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location of the Scaling Plan. | +| `name` | string | The name of the Scaling Plan. | +| `resourceGroupName` | string | The name of the resource group the Scaling Plan was created in. | +| `resourceId` | string | The resource ID of the Scaling Plan. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/desktop-virtualization/scaling-plan/main.bicep b/avm/1.1.0/res/desktop-virtualization/scaling-plan/main.bicep new file mode 100644 index 000000000..10f0fe7f0 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/scaling-plan/main.bicep @@ -0,0 +1,249 @@ +metadata name = 'Azure Virtual Desktop Scaling Plan' +metadata description = 'This module deploys an Azure Virtual Desktop Scaling Plan.' + +@sys.description('Required. Name of the Scaling Plan.') +param name string + +@sys.description('Optional. Location of the Scaling Plan. Defaults to resource group location.') +param location string = resourceGroup().location + +@sys.description('Optional. Friendly name of the Scaling Plan.') +param friendlyName string = name + +@sys.description('Optional. Time zone of the Scaling Plan. Defaults to UTC.') +param timeZone string = 'UTC' + +@sys.description('Optional. Host pool type of the Scaling Plan.') +@allowed([ + 'Personal' + 'Pooled' +]) +param hostPoolType string = 'Pooled' + +@sys.description('Optional. Exclusion tag to be used for exclusion of VMs from Scaling Plan.') +param exclusionTag string = '' + +@sys.description('Optional. Schedules of the Scaling Plan.') +param schedules array = [] + +@sys.description('Optional. Host pool references of the Scaling Plan.') +param hostPoolReferences array = [] + +@sys.description('Optional. Description of the Scaling Plan.') +param description string = name + +@sys.description('Optional. Tags of the resource.') +param tags object? + +@sys.description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@sys.description('Optional. The lock settings of the service.') +param lock lockType + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@sys.description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +var builtInRoleNames = { + Owner: '/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635' + Contributor: '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + Reader: '/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7' + 'Role Based Access Control Administrator': '/providers/Microsoft.Authorization/roleDefinitions/f58310d9-a9f6-439a-9e8d-f62e7b41a168' + 'User Access Administrator': '/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + 'Application Group Contributor': '/providers/Microsoft.Authorization/roleDefinitions/ca6382a4-1721-4bcf-a114-ff0c70227b6b' + 'Desktop Virtualization Application Group Contributor': '/providers/Microsoft.Authorization/roleDefinitions/86240b0e-9422-4c43-887b-b61143f32ba8' + 'Desktop Virtualization Application Group Reader': '/providers/Microsoft.Authorization/roleDefinitions/aebf23d0-b568-4e86-b8f9-fe83a2c6ab55' + 'Desktop Virtualization Contributor': '/providers/Microsoft.Authorization/roleDefinitions/082f0a83-3be5-4ba1-904c-961cca79b387' + 'Desktop Virtualization Host Pool Contributor': '/providers/Microsoft.Authorization/roleDefinitions/e307426c-f9b6-4e81-87de-d99efb3c32bc' + 'Desktop Virtualization Host Pool Reader': '/providers/Microsoft.Authorization/roleDefinitions/ceadfde2-b300-400a-ab7b-6143895aa822' + 'Desktop Virtualization Power On Off Contributor': '/providers/Microsoft.Authorization/roleDefinitions/40c5ff49-9181-41f8-ae61-143b0e78555e' + 'Desktop Virtualization Reader': '/providers/Microsoft.Authorization/roleDefinitions/49a72310-ab8d-41df-bbb0-79b649203868' + 'Desktop Virtualization Session Host Operator': '/providers/Microsoft.Authorization/roleDefinitions/2ad6aaab-ead9-4eaa-8ac5-da422f562408' + 'Desktop Virtualization User': '/providers/Microsoft.Authorization/roleDefinitions/1d18fff3-a72a-46b5-b4a9-0b38a3cd7e63' + 'Desktop Virtualization User Session Operator': '/providers/Microsoft.Authorization/roleDefinitions/ea4bfff8-7fb4-485a-aadd-d4129a0ffaa6' + 'Desktop Virtualization Virtual Machine Contributor': '/providers/Microsoft.Authorization/roleDefinitions/a959dbd1-f747-45e3-8ba6-dd80f235f97c' + 'Desktop Virtualization Workspace Contributor': '/providers/Microsoft.Authorization/roleDefinitions/21efdde3-836f-432b-bf3d-3e8e734d4b2b' + 'Desktop Virtualization Workspace Reader': '/providers/Microsoft.Authorization/roleDefinitions/0fa44ee9-7a7d-466b-9bb2-2bf446b1204d' +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.desktopvirtualization-scalingplan.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource scalingPlan 'Microsoft.DesktopVirtualization/scalingPlans@2023-09-05' = { + name: name + location: location + tags: tags + properties: { + friendlyName: friendlyName + timeZone: timeZone + hostPoolType: hostPoolType + exclusionTag: exclusionTag + schedules: schedules + hostPoolReferences: hostPoolReferences + description: description + } +} + +resource scalingPlan_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: scalingPlan +} + +resource scalingPlan_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(scalingPlan.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: scalingPlan + } +] + +resource scalingPlan_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: scalingPlan + } +] + +@sys.description('The resource ID of the Scaling Plan.') +output resourceId string = scalingPlan.id + +@sys.description('The name of the resource group the Scaling Plan was created in.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The name of the Scaling Plan.') +output name string = scalingPlan.name + +@sys.description('The location of the Scaling Plan.') +output location string = scalingPlan.location + +// ================ // +// Definitions // +// ================ // + +type lockType = { + @sys.description('Optional. Specify the name of lock.') + name: string? + + @sys.description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @sys.description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @sys.description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @sys.description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @sys.description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @sys.description('Optional. The description of the role assignment.') + 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".') + condition: string? + + @sys.description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @sys.description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type diagnosticSettingType = { + @sys.description('Optional. The name of diagnostic setting.') + name: string? + + @sys.description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @sys.description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @sys.description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs.') + categoryGroup: string? + + @sys.description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @sys.description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @sys.description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @sys.description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @sys.description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @sys.description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @sys.description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? diff --git a/avm/1.1.0/res/desktop-virtualization/scaling-plan/main.json b/avm/1.1.0/res/desktop-virtualization/scaling-plan/main.json new file mode 100644 index 000000000..9aec36b92 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/scaling-plan/main.json @@ -0,0 +1,475 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "7853771488680556141" + }, + "name": "Azure Virtual Desktop Scaling Plan", + "description": "This module deploys an Azure Virtual Desktop Scaling Plan." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Scaling Plan." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the Scaling Plan. Defaults to resource group location." + } + }, + "friendlyName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Friendly name of the Scaling Plan." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "UTC", + "metadata": { + "description": "Optional. Time zone of the Scaling Plan. Defaults to UTC." + } + }, + "hostPoolType": { + "type": "string", + "defaultValue": "Pooled", + "allowedValues": [ + "Personal", + "Pooled" + ], + "metadata": { + "description": "Optional. Host pool type of the Scaling Plan." + } + }, + "exclusionTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Exclusion tag to be used for exclusion of VMs from Scaling Plan." + } + }, + "schedules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Schedules of the Scaling Plan." + } + }, + "hostPoolReferences": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Host pool references of the Scaling Plan." + } + }, + "description": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Description of the Scaling Plan." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Owner": "/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635", + "Contributor": "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c", + "Reader": "/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7", + "Role Based Access Control Administrator": "/providers/Microsoft.Authorization/roleDefinitions/f58310d9-a9f6-439a-9e8d-f62e7b41a168", + "User Access Administrator": "/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9", + "Application Group Contributor": "/providers/Microsoft.Authorization/roleDefinitions/ca6382a4-1721-4bcf-a114-ff0c70227b6b", + "Desktop Virtualization Application Group Contributor": "/providers/Microsoft.Authorization/roleDefinitions/86240b0e-9422-4c43-887b-b61143f32ba8", + "Desktop Virtualization Application Group Reader": "/providers/Microsoft.Authorization/roleDefinitions/aebf23d0-b568-4e86-b8f9-fe83a2c6ab55", + "Desktop Virtualization Contributor": "/providers/Microsoft.Authorization/roleDefinitions/082f0a83-3be5-4ba1-904c-961cca79b387", + "Desktop Virtualization Host Pool Contributor": "/providers/Microsoft.Authorization/roleDefinitions/e307426c-f9b6-4e81-87de-d99efb3c32bc", + "Desktop Virtualization Host Pool Reader": "/providers/Microsoft.Authorization/roleDefinitions/ceadfde2-b300-400a-ab7b-6143895aa822", + "Desktop Virtualization Power On Off Contributor": "/providers/Microsoft.Authorization/roleDefinitions/40c5ff49-9181-41f8-ae61-143b0e78555e", + "Desktop Virtualization Reader": "/providers/Microsoft.Authorization/roleDefinitions/49a72310-ab8d-41df-bbb0-79b649203868", + "Desktop Virtualization Session Host Operator": "/providers/Microsoft.Authorization/roleDefinitions/2ad6aaab-ead9-4eaa-8ac5-da422f562408", + "Desktop Virtualization User": "/providers/Microsoft.Authorization/roleDefinitions/1d18fff3-a72a-46b5-b4a9-0b38a3cd7e63", + "Desktop Virtualization User Session Operator": "/providers/Microsoft.Authorization/roleDefinitions/ea4bfff8-7fb4-485a-aadd-d4129a0ffaa6", + "Desktop Virtualization Virtual Machine Contributor": "/providers/Microsoft.Authorization/roleDefinitions/a959dbd1-f747-45e3-8ba6-dd80f235f97c", + "Desktop Virtualization Workspace Contributor": "/providers/Microsoft.Authorization/roleDefinitions/21efdde3-836f-432b-bf3d-3e8e734d4b2b", + "Desktop Virtualization Workspace Reader": "/providers/Microsoft.Authorization/roleDefinitions/0fa44ee9-7a7d-466b-9bb2-2bf446b1204d" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.desktopvirtualization-scalingplan.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "scalingPlan": { + "type": "Microsoft.DesktopVirtualization/scalingPlans", + "apiVersion": "2023-09-05", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "friendlyName": "[parameters('friendlyName')]", + "timeZone": "[parameters('timeZone')]", + "hostPoolType": "[parameters('hostPoolType')]", + "exclusionTag": "[parameters('exclusionTag')]", + "schedules": "[parameters('schedules')]", + "hostPoolReferences": "[parameters('hostPoolReferences')]", + "description": "[parameters('description')]" + } + }, + "scalingPlan_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.DesktopVirtualization/scalingPlans/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "scalingPlan" + ] + }, + "scalingPlan_roleAssignments": { + "copy": { + "name": "scalingPlan_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.DesktopVirtualization/scalingPlans/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DesktopVirtualization/scalingPlans', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "scalingPlan" + ] + }, + "scalingPlan_diagnosticSettings": { + "copy": { + "name": "scalingPlan_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DesktopVirtualization/scalingPlans/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "scalingPlan" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Scaling Plan." + }, + "value": "[resourceId('Microsoft.DesktopVirtualization/scalingPlans', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Scaling Plan was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Scaling Plan." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location of the Scaling Plan." + }, + "value": "[reference('scalingPlan', '2023-09-05', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..532bc90df --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,45 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.scalingplans-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dvspmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7b804fb6e --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/max/dependencies.bicep @@ -0,0 +1,52 @@ +@sys.description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +param tags object = {} + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Optional. Expiration time of Host Pool registration token. Should be between one hour and 30 days from now and the format is like \'2023-12-24T12:00:00.0000000Z\'. If not provided, the expiration time will be set to two days from now.') +param expirationTime string = dateTimeAdd(utcNow(), 'P2D') + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource hostPool 'Microsoft.DesktopVirtualization/hostPools@2022-09-09' = { + name: 'myHostPool' + location: location + tags: tags + properties: { + friendlyName: 'hostPoolFriendlyName' + description: 'myDescription' + hostPoolType: 'Pooled' + customRdpProperty: '' + personalDesktopAssignmentType: 'Automatic' + preferredAppGroupType: 'Desktop' + maxSessionLimit: 5 + loadBalancerType: 'BreadthFirst' + startVMOnConnect: false + validationEnvironment: false + registrationInfo: { + expirationTime: expirationTime + token: null + registrationTokenOperation: 'Update' + } + agentUpdate: { + useSessionHostLocalTime: true + } + ring: -1 + ssoadfsAuthority: '' + ssoClientId: '' + ssoClientSecretKeyVaultPath: '' + ssoSecretType: '' + } +} + +@description('The resource ID of the created host pool.') +output hostPoolId string = hostPool.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..d6ce6b8b6 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/max/main.test.bicep @@ -0,0 +1,230 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.scalingplans-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dvspmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// Diagnostics +// =========== + +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}03' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + location: resourceLocation + friendlyName: 'friendlyName' + description: 'myDescription' + schedules: [ + { + daysOfWeek: [ + 'Monday' + 'Wednesday' + 'Thursday' + 'Friday' + ] + name: 'WeekdaySchedule' + offPeakLoadBalancingAlgorithm: 'DepthFirst' + offPeakStartTime: { + hour: 20 + minute: 0 + } + peakLoadBalancingAlgorithm: 'DepthFirst' + peakStartTime: { + hour: 9 + minute: 0 + } + rampDownCapacityThresholdPct: 90 + rampDownForceLogoffUsers: true + rampDownLoadBalancingAlgorithm: 'DepthFirst' + rampDownMinimumHostsPct: 0 + rampDownNotificationMessage: 'You will be logged off in 30 min. Make sure to save your work.' + rampDownStartTime: { + hour: 18 + minute: 0 + } + rampDownStopHostsWhen: 'ZeroActiveSessions' + rampDownWaitTimeMinutes: 30 + rampUpCapacityThresholdPct: 80 + rampUpLoadBalancingAlgorithm: 'BreadthFirst' + rampUpMinimumHostsPct: 20 + rampUpStartTime: { + hour: 7 + minute: 0 + } + } + { + daysOfWeek: [ + 'Tuesday' + ] + name: 'weekdaysSchedule-agent-updates' + offPeakLoadBalancingAlgorithm: 'DepthFirst' + offPeakStartTime: { + hour: 20 + minute: 0 + } + peakLoadBalancingAlgorithm: 'DepthFirst' + peakStartTime: { + hour: 9 + minute: 0 + } + rampDownCapacityThresholdPct: 90 + rampDownForceLogoffUsers: true + rampDownLoadBalancingAlgorithm: 'DepthFirst' + rampDownMinimumHostsPct: 0 + rampDownNotificationMessage: 'You will be logged off in 30 min. Make sure to save your work.' + rampDownStartTime: { + hour: 19 + minute: 0 + } + rampDownStopHostsWhen: 'ZeroActiveSessions' + rampDownWaitTimeMinutes: 30 + rampUpCapacityThresholdPct: 80 + rampUpLoadBalancingAlgorithm: 'BreadthFirst' + rampUpMinimumHostsPct: 20 + rampUpStartTime: { + hour: 7 + minute: 0 + } + } + { + daysOfWeek: [ + 'Saturday' + 'Sunday' + ] + name: 'WeekendSchedule' + offPeakLoadBalancingAlgorithm: 'DepthFirst' + offPeakStartTime: { + hour: 18 + minute: 0 + } + peakLoadBalancingAlgorithm: 'DepthFirst' + peakStartTime: { + hour: 10 + minute: 0 + } + rampDownCapacityThresholdPct: 90 + rampDownForceLogoffUsers: true + rampDownLoadBalancingAlgorithm: 'DepthFirst' + rampDownMinimumHostsPct: 0 + rampDownNotificationMessage: 'You will be logged off in 30 min. Make sure to save your work.' + rampDownStartTime: { + hour: 16 + minute: 0 + } + rampDownStopHostsWhen: 'ZeroActiveSessions' + rampDownWaitTimeMinutes: 30 + rampUpCapacityThresholdPct: 90 + rampUpLoadBalancingAlgorithm: 'DepthFirst' + rampUpMinimumHostsPct: 0 + rampUpStartTime: { + hour: 9 + minute: 0 + } + } + ] + hostPoolReferences: [ + { + hostPoolArmPath: nestedDependencies.outputs.hostPoolId + scalingPlanEnabled: true + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'c2c1c560-2169-405a-a8dc-7427e403e5ac' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..ebb127fff --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/scaling-plan/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,75 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.scalingplans-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dvspwaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// Diagnostics +// =========== + +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}03' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + friendlyName: 'myFriendlyName' + location: resourceLocation + description: 'myDescription' + diagnosticSettings: [ + { + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/desktop-virtualization/scaling-plan/version.json b/avm/1.1.0/res/desktop-virtualization/scaling-plan/version.json new file mode 100644 index 000000000..76049e1c4 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/scaling-plan/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/desktop-virtualization/workspace/README.md b/avm/1.1.0/res/desktop-virtualization/workspace/README.md new file mode 100644 index 000000000..48551acfb --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/workspace/README.md @@ -0,0 +1,1431 @@ +# Workspace `[Microsoft.DesktopVirtualization/workspaces]` + +This module deploys an Azure Virtual Desktop Workspace. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.DesktopVirtualization/workspaces` | [2022-10-14-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DesktopVirtualization/2022-10-14-preview/workspaces) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/desktop-virtualization/workspace:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module workspace 'br/public:avm/res/desktop-virtualization/workspace:' = { + name: 'workspaceDeployment' + params: { + // Required parameters + name: 'dvwsmin002' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "dvwsmin002" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/workspace:' + +// Required parameters +param name = 'dvwsmin002' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module workspace 'br/public:avm/res/desktop-virtualization/workspace:' = { + name: 'workspaceDeployment' + params: { + // Required parameters + name: 'dvwsmax001' + // Non-required parameters + applicationGroupReferences: [] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + friendlyName: 'AVD Workspace' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + privateEndpoints: [ + { + customDnsConfigs: [] + ipConfigurations: [ + { + name: 'myIPconfig-feed1' + properties: { + groupId: 'feed' + memberName: 'web-r0' + privateIPAddress: '10.0.0.10' + } + } + { + name: 'myIPconfig-feed2' + properties: { + groupId: 'feed' + memberName: 'web-r1' + privateIPAddress: '10.0.0.13' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + service: 'feed' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + customDnsConfigs: [] + ipConfigurations: [ + { + name: 'myIPconfig-global' + properties: { + groupId: 'global' + memberName: 'web' + privateIPAddress: '10.0.0.11' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + service: 'global' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + publicNetworkAccess: 'Disabled' + roleAssignments: [ + { + name: 'e31e3fcd-816f-49b9-a741-feff792a56d7' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "dvwsmax001" + }, + // Non-required parameters + "applicationGroupReferences": { + "value": [] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "logCategoriesAndGroups": [ + { + "categoryGroup": "allLogs" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "friendlyName": { + "value": "AVD Workspace" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "privateEndpoints": { + "value": [ + { + "customDnsConfigs": [], + "ipConfigurations": [ + { + "name": "myIPconfig-feed1", + "properties": { + "groupId": "feed", + "memberName": "web-r0", + "privateIPAddress": "10.0.0.10" + } + }, + { + "name": "myIPconfig-feed2", + "properties": { + "groupId": "feed", + "memberName": "web-r1", + "privateIPAddress": "10.0.0.13" + } + } + ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "service": "feed", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + { + "customDnsConfigs": [], + "ipConfigurations": [ + { + "name": "myIPconfig-global", + "properties": { + "groupId": "global", + "memberName": "web", + "privateIPAddress": "10.0.0.11" + } + } + ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "service": "global", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + ] + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "roleAssignments": { + "value": [ + { + "name": "e31e3fcd-816f-49b9-a741-feff792a56d7", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/workspace:' + +// Required parameters +param name = 'dvwsmax001' +// Non-required parameters +param applicationGroupReferences = [] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param friendlyName = 'AVD Workspace' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + customDnsConfigs: [] + ipConfigurations: [ + { + name: 'myIPconfig-feed1' + properties: { + groupId: 'feed' + memberName: 'web-r0' + privateIPAddress: '10.0.0.10' + } + } + { + name: 'myIPconfig-feed2' + properties: { + groupId: 'feed' + memberName: 'web-r1' + privateIPAddress: '10.0.0.13' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + service: 'feed' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + customDnsConfigs: [] + ipConfigurations: [ + { + name: 'myIPconfig-global' + properties: { + groupId: 'global' + memberName: 'web' + privateIPAddress: '10.0.0.11' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + service: 'global' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: 'e31e3fcd-816f-49b9-a741-feff792a56d7' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module workspace 'br/public:avm/res/desktop-virtualization/workspace:' = { + name: 'workspaceDeployment' + params: { + // Required parameters + name: 'dvwswaf002' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "dvwswaf002" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/workspace:' + +// Required parameters +param name = 'dvwswaf002' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the workspace. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationGroupReferences`](#parameter-applicationgroupreferences) | array | Array of application group references. | +| [`description`](#parameter-description) | string | Description of the workspace. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`friendlyName`](#parameter-friendlyname) | string | Friendly name of the workspace. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Public network access for the workspace. Enabled by default. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `name` + +Name of the workspace. + +- Required: Yes +- Type: string + +### Parameter: `applicationGroupReferences` + +Array of application group references. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `description` + +Description of the workspace. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `friendlyName` + +Friendly name of the workspace. + +- Required: No +- Type: string +- Default: `[parameters('name')]` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints` + +Configuration details for private endpoints. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationSecurityGroupResourceIds`](#parameter-privateendpointsapplicationsecuritygroupresourceids) | array | Application security groups in which the private endpoint IP configuration is included. | +| [`customDnsConfigs`](#parameter-privateendpointscustomdnsconfigs) | array | Custom DNS configurations. | +| [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | +| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | +| [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | +| [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | +| [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | +| [`privateDnsZoneGroup`](#parameter-privateendpointsprivatednszonegroup) | object | The private DNS zone group to configure for the private endpoint. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | +| [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | +| [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | + +### Parameter: `privateEndpoints.subnetResourceId` + +Resource ID of the subnet where the endpoint needs to be created. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.applicationSecurityGroupResourceIds` + +Application security groups in which the private endpoint IP configuration is included. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs` + +Custom DNS configurations. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | FQDN that resolves to private endpoint IP address. | + +### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +A list of private IP addresses of the private endpoint. + +- Required: Yes +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +FQDN that resolves to private endpoint IP address. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.customNetworkInterfaceName` + +The custom name of the network interface attached to the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.ipConfigurations` + +A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsipconfigurationsname) | string | The name of the resource that is unique within a resource group. | +| [`properties`](#parameter-privateendpointsipconfigurationsproperties) | object | Properties of private endpoint IP configurations. | + +### Parameter: `privateEndpoints.ipConfigurations.name` + +The name of the resource that is unique within a resource group. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties` + +Properties of private endpoint IP configurations. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private IP address obtained from the private endpoint's subnet. | + +### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` + +The ID of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.memberName` + +The member name of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` + +A private IP address obtained from the private endpoint's subnet. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.location` + +The location to deploy the private endpoint to. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.lock` + +Specify the type of lock. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-privateendpointslockkind) | string | Specify the type of lock. | +| [`name`](#parameter-privateendpointslockname) | string | Specify the name of lock. | + +### Parameter: `privateEndpoints.lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `privateEndpoints.lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.manualConnectionRequestMessage` + +A message passed to the owner of the remote resource with the manual connection request. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.name` + +The name of the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup` + +The private DNS zone group to configure for the private endpoint. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneGroupConfigs`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigs) | array | The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the Private DNS Zone Group. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs` + +The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneResourceId`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsprivatednszoneresourceid) | string | The resource id of the private DNS zone. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsname) | string | The name of the private DNS zone group config. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.privateDnsZoneResourceId` + +The resource id of the private DNS zone. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.name` + +The name of the private DNS zone group config. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.name` + +The name of the Private DNS Zone Group. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.resourceGroupName` + +Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-privateendpointsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-privateendpointsroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-privateendpointsroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-privateendpointsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-privateendpointsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-privateendpointsroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-privateendpointsroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-privateendpointsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `privateEndpoints.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `privateEndpoints.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `privateEndpoints.service` + +The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.tags` + +Tags to be applied on all resources/resource groups in this deployment. + +- Required: No +- Type: object + +### Parameter: `publicNetworkAccess` + +Public network access for the workspace. Enabled by default. + +- Required: No +- Type: string +- Default: `'Enabled'` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Owner'` + - `'Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Application Group Contributor'` + - `'Desktop Virtualization Application Group Contributor'` + - `'Desktop Virtualization Application Group Reader'` + - `'Desktop Virtualization Contributor'` + - `'Desktop Virtualization Host Pool Contributor'` + - `'Desktop Virtualization Host Pool Reader'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Reader'` + - `'Desktop Virtualization Session Host Operator'` + - `'Desktop Virtualization User'` + - `'Desktop Virtualization User Session Operator'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'Desktop Virtualization Workspace Contributor'` + - `'Desktop Virtualization Workspace Reader'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location of the workspace. | +| `name` | string | The name of the workspace. | +| `privateEndpoints` | array | The private endpoints of the workspace. | +| `resourceGroupName` | string | The name of the resource group the workspace was created in. | +| `resourceId` | string | The resource ID of the workspace. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/private-endpoint:0.7.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/desktop-virtualization/workspace/main.bicep b/avm/1.1.0/res/desktop-virtualization/workspace/main.bicep new file mode 100644 index 000000000..85c3f855b --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/workspace/main.bicep @@ -0,0 +1,385 @@ +metadata name = 'Workspace' +metadata description = 'This module deploys an Azure Virtual Desktop Workspace.' + +@sys.description('Required. Name of the workspace.') +param name string + +@sys.description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@sys.description('Optional. Tags of the resource.') +param tags object? + +@sys.description('Optional. Array of application group references.') +param applicationGroupReferences array = [] + +@sys.description('Optional. Description of the workspace.') +param description string = '' + +@sys.description('Optional. Friendly name of the workspace.') +param friendlyName string = name + +@sys.description('Optional. Public network access for the workspace. Enabled by default.') +param publicNetworkAccess string = 'Enabled' + +@sys.description('Optional. Configuration details for private endpoints.') +param privateEndpoints privateEndpointType + +@sys.description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@sys.description('Optional. The lock settings of the service.') +param lock lockType + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@sys.description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +var builtInRoleNames = { + Owner: '/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635' + Contributor: '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + Reader: '/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7' + 'Role Based Access Control Administrator': '/providers/Microsoft.Authorization/roleDefinitions/f58310d9-a9f6-439a-9e8d-f62e7b41a168' + 'User Access Administrator': '/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + 'Application Group Contributor': '/providers/Microsoft.Authorization/roleDefinitions/ca6382a4-1721-4bcf-a114-ff0c70227b6b' + 'Desktop Virtualization Application Group Contributor': '/providers/Microsoft.Authorization/roleDefinitions/86240b0e-9422-4c43-887b-b61143f32ba8' + 'Desktop Virtualization Application Group Reader': '/providers/Microsoft.Authorization/roleDefinitions/aebf23d0-b568-4e86-b8f9-fe83a2c6ab55' + 'Desktop Virtualization Contributor': '/providers/Microsoft.Authorization/roleDefinitions/082f0a83-3be5-4ba1-904c-961cca79b387' + 'Desktop Virtualization Host Pool Contributor': '/providers/Microsoft.Authorization/roleDefinitions/e307426c-f9b6-4e81-87de-d99efb3c32bc' + 'Desktop Virtualization Host Pool Reader': '/providers/Microsoft.Authorization/roleDefinitions/ceadfde2-b300-400a-ab7b-6143895aa822' + 'Desktop Virtualization Power On Off Contributor': '/providers/Microsoft.Authorization/roleDefinitions/40c5ff49-9181-41f8-ae61-143b0e78555e' + 'Desktop Virtualization Reader': '/providers/Microsoft.Authorization/roleDefinitions/49a72310-ab8d-41df-bbb0-79b649203868' + 'Desktop Virtualization Session Host Operator': '/providers/Microsoft.Authorization/roleDefinitions/2ad6aaab-ead9-4eaa-8ac5-da422f562408' + 'Desktop Virtualization User': '/providers/Microsoft.Authorization/roleDefinitions/1d18fff3-a72a-46b5-b4a9-0b38a3cd7e63' + 'Desktop Virtualization User Session Operator': '/providers/Microsoft.Authorization/roleDefinitions/ea4bfff8-7fb4-485a-aadd-d4129a0ffaa6' + 'Desktop Virtualization Virtual Machine Contributor': '/providers/Microsoft.Authorization/roleDefinitions/a959dbd1-f747-45e3-8ba6-dd80f235f97c' + 'Desktop Virtualization Workspace Contributor': '/providers/Microsoft.Authorization/roleDefinitions/21efdde3-836f-432b-bf3d-3e8e734d4b2b' + 'Desktop Virtualization Workspace Reader': '/providers/Microsoft.Authorization/roleDefinitions/0fa44ee9-7a7d-466b-9bb2-2bf446b1204d' +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.res.desktopvirtualization-workspace.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource workspace 'Microsoft.DesktopVirtualization/workspaces@2022-10-14-preview' = { + name: name + location: location + tags: tags + properties: { + applicationGroupReferences: applicationGroupReferences + description: description + friendlyName: friendlyName + publicNetworkAccess: publicNetworkAccess + } +} + +module workspace_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.7.1' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-workspace-PrivateEndpoint-${index}' + scope: resourceGroup(privateEndpoint.?resourceGroupName ?? '') + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'connection'}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'connection'}-${index}' + properties: { + privateLinkServiceId: workspace.id + groupIds: [ + privateEndpoint.?service ?? 'connection' + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'connection'}-${index}' + properties: { + privateLinkServiceId: workspace.id + groupIds: [ + privateEndpoint.?service ?? 'connection' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] + : null + subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry + location: privateEndpoint.?location ?? reference( + split(privateEndpoint.subnetResourceId, '/subnets/')[0], + '2020-06-01', + 'Full' + ).location + lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } + } +] + +resource workspace_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: workspace +} + +resource workspace_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(workspace.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: workspace + } +] + +resource workspace_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + logs: diagnosticSetting.?logCategoriesAndGroups ?? [ + { + categoryGroup: 'allLogs' + enabled: true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: workspace + } +] + +@sys.description('The resource ID of the workspace.') +output resourceId string = workspace.id + +@sys.description('The name of the resource group the workspace was created in.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The name of the workspace.') +output name string = workspace.name + +@sys.description('The location of the workspace.') +output location string = workspace.location + +@sys.description('The private endpoints of the workspace.') +output privateEndpoints array = [ + for (pe, i) in (!empty(privateEndpoints) ? array(privateEndpoints) : []): { + name: workspace_privateEndpoints[i].outputs.name + resourceId: workspace_privateEndpoints[i].outputs.resourceId + groupId: workspace_privateEndpoints[i].outputs.groupId + customDnsConfig: workspace_privateEndpoints[i].outputs.customDnsConfig + networkInterfaceIds: workspace_privateEndpoints[i].outputs.networkInterfaceIds + } +] + +// ================ // +// Definitions // +// ================ // + +type diagnosticSettingType = { + @sys.description('Optional. The name of diagnostic setting.') + name: string? + + @sys.description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to \'\' to disable log collection.') + logCategoriesAndGroups: { + @sys.description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @sys.description('Optional. Name of a Diagnostic Log group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + }[]? + + @sys.description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics' | null)? + + @sys.description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @sys.description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @sys.description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @sys.description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @sys.description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? + +type roleAssignmentType = { + @sys.description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @sys.description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @sys.description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @sys.description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @sys.description('Optional. The description of the role assignment.') + 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".') + condition: string? + + @sys.description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @sys.description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type privateEndpointType = { + @sys.description('Optional. The name of the private endpoint.') + name: string? + + @sys.description('Optional. The location to deploy the private endpoint to.') + location: string? + + @sys.description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + + @sys.description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') + service: string? + + @sys.description('Required. Resource ID of the subnet where the endpoint needs to be created.') + subnetResourceId: string + + @sys.description('Optional. The private DNS zone group to configure for the private endpoint.') + privateDnsZoneGroup: { + @sys.description('Optional. The name of the Private DNS Zone Group.') + name: string? + + @sys.description('Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones.') + privateDnsZoneGroupConfigs: { + @sys.description('Optional. The name of the private DNS zone group config.') + name: string? + + @sys.description('Required. The resource id of the private DNS zone.') + privateDnsZoneResourceId: string + }[] + }? + + @sys.description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @sys.description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + + @sys.description('Optional. Custom DNS configurations.') + customDnsConfigs: { + @sys.description('Optional. FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @sys.description('Required. A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[]? + + @sys.description('Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints.') + ipConfigurations: { + @sys.description('Required. The name of the resource that is unique within a resource group.') + name: string + + @sys.description('Required. Properties of private endpoint IP configurations.') + properties: { + @sys.description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') + groupId: string + + @sys.description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') + memberName: string + + @sys.description('Required. A private IP address obtained from the private endpoint\'s subnet.') + privateIPAddress: string + } + }[]? + + @sys.description('Optional. Application security groups in which the private endpoint IP configuration is included.') + applicationSecurityGroupResourceIds: string[]? + + @sys.description('Optional. The custom name of the network interface attached to the private endpoint.') + customNetworkInterfaceName: string? + + @sys.description('Optional. Specify the type of lock.') + lock: lockType + + @sys.description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @sys.description('Optional. Tags to be applied on all resources/resource groups in this deployment.') + tags: object? + + @sys.description('Optional. Enable/Disable usage telemetry for module.') + enableTelemetry: bool? + + @sys.description('Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.') + resourceGroupName: string? +}[]? + +type lockType = { + @sys.description('Optional. Specify the name of lock.') + name: string? + + @sys.description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? diff --git a/avm/1.1.0/res/desktop-virtualization/workspace/main.json b/avm/1.1.0/res/desktop-virtualization/workspace/main.json new file mode 100644 index 000000000..1a6590306 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/workspace/main.json @@ -0,0 +1,1438 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15242596555785609463" + }, + "name": "Workspace", + "description": "This module deploys an Azure Virtual Desktop Workspace." + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroup": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "applicationGroupReferences": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of application group references." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Description of the workspace." + } + }, + "friendlyName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Friendly name of the workspace." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Optional. Public network access for the workspace. Enabled by default." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Owner": "/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635", + "Contributor": "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c", + "Reader": "/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7", + "Role Based Access Control Administrator": "/providers/Microsoft.Authorization/roleDefinitions/f58310d9-a9f6-439a-9e8d-f62e7b41a168", + "User Access Administrator": "/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9", + "Application Group Contributor": "/providers/Microsoft.Authorization/roleDefinitions/ca6382a4-1721-4bcf-a114-ff0c70227b6b", + "Desktop Virtualization Application Group Contributor": "/providers/Microsoft.Authorization/roleDefinitions/86240b0e-9422-4c43-887b-b61143f32ba8", + "Desktop Virtualization Application Group Reader": "/providers/Microsoft.Authorization/roleDefinitions/aebf23d0-b568-4e86-b8f9-fe83a2c6ab55", + "Desktop Virtualization Contributor": "/providers/Microsoft.Authorization/roleDefinitions/082f0a83-3be5-4ba1-904c-961cca79b387", + "Desktop Virtualization Host Pool Contributor": "/providers/Microsoft.Authorization/roleDefinitions/e307426c-f9b6-4e81-87de-d99efb3c32bc", + "Desktop Virtualization Host Pool Reader": "/providers/Microsoft.Authorization/roleDefinitions/ceadfde2-b300-400a-ab7b-6143895aa822", + "Desktop Virtualization Power On Off Contributor": "/providers/Microsoft.Authorization/roleDefinitions/40c5ff49-9181-41f8-ae61-143b0e78555e", + "Desktop Virtualization Reader": "/providers/Microsoft.Authorization/roleDefinitions/49a72310-ab8d-41df-bbb0-79b649203868", + "Desktop Virtualization Session Host Operator": "/providers/Microsoft.Authorization/roleDefinitions/2ad6aaab-ead9-4eaa-8ac5-da422f562408", + "Desktop Virtualization User": "/providers/Microsoft.Authorization/roleDefinitions/1d18fff3-a72a-46b5-b4a9-0b38a3cd7e63", + "Desktop Virtualization User Session Operator": "/providers/Microsoft.Authorization/roleDefinitions/ea4bfff8-7fb4-485a-aadd-d4129a0ffaa6", + "Desktop Virtualization Virtual Machine Contributor": "/providers/Microsoft.Authorization/roleDefinitions/a959dbd1-f747-45e3-8ba6-dd80f235f97c", + "Desktop Virtualization Workspace Contributor": "/providers/Microsoft.Authorization/roleDefinitions/21efdde3-836f-432b-bf3d-3e8e734d4b2b", + "Desktop Virtualization Workspace Reader": "/providers/Microsoft.Authorization/roleDefinitions/0fa44ee9-7a7d-466b-9bb2-2bf446b1204d" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.res.desktopvirtualization-workspace.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "workspace": { + "type": "Microsoft.DesktopVirtualization/workspaces", + "apiVersion": "2022-10-14-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "applicationGroupReferences": "[parameters('applicationGroupReferences')]", + "description": "[parameters('description')]", + "friendlyName": "[parameters('friendlyName')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]" + } + }, + "workspace_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.DesktopVirtualization/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "workspace" + ] + }, + "workspace_roleAssignments": { + "copy": { + "name": "workspace_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.DesktopVirtualization/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "workspace" + ] + }, + "workspace_diagnosticSettings": { + "copy": { + "name": "workspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DesktopVirtualization/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true())))]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "workspace" + ] + }, + "workspace_privateEndpoints": { + "copy": { + "name": "workspace_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-workspace-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "1277254088602407590" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + } + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5805178546717255803" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" + }, + "customDnsConfig": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceIds": { + "type": "array", + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + }, + "value": "[reference('privateEndpoint').networkInterfaces]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(and(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds', 0), ''), if(and(not(empty(reference('privateEndpoint').privateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds', 0), ''), ''))]" + } + } + } + }, + "dependsOn": [ + "workspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the workspace." + }, + "value": "[resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the workspace was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the workspace." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location of the workspace." + }, + "value": "[reference('workspace', '2022-10-14-preview', 'full').location]" + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the workspace." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", + "input": { + "name": "[reference(format('workspace_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('workspace_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('workspace_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('workspace_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('workspace_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..f99089150 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,45 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.workspace-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dvwsmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..41441e38a --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/max/dependencies.bicep @@ -0,0 +1,60 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.wvd.microsoft.com' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..e5b3dc489 --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/max/main.test.bicep @@ -0,0 +1,200 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.workspace-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dvwsmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// Diagnostics +// =========== + +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: substring('dep${uniqueString(deployment().name, resourceLocation)}${serviceShort}03', 0, 24) + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + applicationGroupReferences: [] + friendlyName: 'AVD Workspace' + publicNetworkAccess: 'Disabled' + diagnosticSettings: [ + { + name: 'customSetting' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + roleAssignments: [ + { + name: 'e31e3fcd-816f-49b9-a741-feff792a56d7' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + privateEndpoints: [ + { + service: 'feed' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + subnetResourceId: nestedDependencies.outputs.subnetResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + ipConfigurations: [ + { + name: 'myIPconfig-feed1' + properties: { + groupId: 'feed' + memberName: 'web-r0' + privateIPAddress: '10.0.0.10' + } + } + { + name: 'myIPconfig-feed2' + properties: { + groupId: 'feed' + memberName: 'web-r1' + privateIPAddress: '10.0.0.13' + } + } + ] + customDnsConfigs: [] + } + { + service: 'global' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + subnetResourceId: nestedDependencies.outputs.subnetResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + ipConfigurations: [ + { + name: 'myIPconfig-global' + properties: { + groupId: 'global' + memberName: 'web' + privateIPAddress: '10.0.0.11' + } + } + ] + customDnsConfigs: [] + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..17781985a --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,76 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework.' + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-desktopvirtualization.workspace-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dvwswaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// Diagnostics +// =========== + +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: substring('dep${uniqueString(deployment().name, resourceLocation)}${serviceShort}03', 0, 24) + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + location: resourceLocation + diagnosticSettings: [ + { + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + diagnosticDependencies + ] + } +] diff --git a/avm/1.1.0/res/desktop-virtualization/workspace/version.json b/avm/1.1.0/res/desktop-virtualization/workspace/version.json new file mode 100644 index 000000000..09c3664ce --- /dev/null +++ b/avm/1.1.0/res/desktop-virtualization/workspace/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.7", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/action-group/README.md b/avm/1.1.0/res/insights/action-group/README.md new file mode 100644 index 000000000..a198ad986 --- /dev/null +++ b/avm/1.1.0/res/insights/action-group/README.md @@ -0,0 +1,660 @@ +# Action Groups `[Microsoft.Insights/actionGroups]` + +This module deploys an Action Group. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/actionGroups` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2023-01-01/actionGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/insights/action-group:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module actionGroup 'br/public:avm/res/insights/action-group:' = { + name: 'actionGroupDeployment' + params: { + // Required parameters + groupShortName: 'agiagmin001' + name: 'iagmin001' + // Non-required parameters + location: 'global' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "groupShortName": { + "value": "agiagmin001" + }, + "name": { + "value": "iagmin001" + }, + // Non-required parameters + "location": { + "value": "global" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/action-group:' + +// Required parameters +param groupShortName = 'agiagmin001' +param name = 'iagmin001' +// Non-required parameters +param location = 'global' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module actionGroup 'br/public:avm/res/insights/action-group:' = { + name: 'actionGroupDeployment' + params: { + // Required parameters + groupShortName: 'agiagmax001' + name: 'iagmax001' + // Non-required parameters + emailReceivers: [ + { + emailAddress: 'test.user@testcompany.com' + name: 'TestUser_-EmailAction-' + useCommonAlertSchema: true + } + { + emailAddress: 'test.user2@testcompany.com' + name: 'TestUser2' + useCommonAlertSchema: true + } + ] + location: 'global' + roleAssignments: [ + { + name: 'fc3ee4d9-d0c0-42c2-962f-082cf8d78882' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + smsReceivers: [ + { + countryCode: '1' + name: 'TestUser_-SMSAction-' + phoneNumber: '2345678901' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "groupShortName": { + "value": "agiagmax001" + }, + "name": { + "value": "iagmax001" + }, + // Non-required parameters + "emailReceivers": { + "value": [ + { + "emailAddress": "test.user@testcompany.com", + "name": "TestUser_-EmailAction-", + "useCommonAlertSchema": true + }, + { + "emailAddress": "test.user2@testcompany.com", + "name": "TestUser2", + "useCommonAlertSchema": true + } + ] + }, + "location": { + "value": "global" + }, + "roleAssignments": { + "value": [ + { + "name": "fc3ee4d9-d0c0-42c2-962f-082cf8d78882", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "smsReceivers": { + "value": [ + { + "countryCode": "1", + "name": "TestUser_-SMSAction-", + "phoneNumber": "2345678901" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/action-group:' + +// Required parameters +param groupShortName = 'agiagmax001' +param name = 'iagmax001' +// Non-required parameters +param emailReceivers = [ + { + emailAddress: 'test.user@testcompany.com' + name: 'TestUser_-EmailAction-' + useCommonAlertSchema: true + } + { + emailAddress: 'test.user2@testcompany.com' + name: 'TestUser2' + useCommonAlertSchema: true + } +] +param location = 'global' +param roleAssignments = [ + { + name: 'fc3ee4d9-d0c0-42c2-962f-082cf8d78882' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param smsReceivers = [ + { + countryCode: '1' + name: 'TestUser_-SMSAction-' + phoneNumber: '2345678901' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module actionGroup 'br/public:avm/res/insights/action-group:' = { + name: 'actionGroupDeployment' + params: { + // Required parameters + groupShortName: 'agiagwaf001' + name: 'iagwaf001' + // Non-required parameters + location: 'global' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "groupShortName": { + "value": "agiagwaf001" + }, + "name": { + "value": "iagwaf001" + }, + // Non-required parameters + "location": { + "value": "global" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/action-group:' + +// Required parameters +param groupShortName = 'agiagwaf001' +param name = 'iagwaf001' +// Non-required parameters +param location = 'global' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupShortName`](#parameter-groupshortname) | string | The short name of the action group. | +| [`name`](#parameter-name) | string | The name of the action group. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`armRoleReceivers`](#parameter-armrolereceivers) | array | The list of ARM role receivers that are part of this action group. Roles are Azure RBAC roles and only built-in roles are supported. | +| [`automationRunbookReceivers`](#parameter-automationrunbookreceivers) | array | The list of AutomationRunbook receivers that are part of this action group. | +| [`azureAppPushReceivers`](#parameter-azureapppushreceivers) | array | The list of AzureAppPush receivers that are part of this action group. | +| [`azureFunctionReceivers`](#parameter-azurefunctionreceivers) | array | The list of function receivers that are part of this action group. | +| [`emailReceivers`](#parameter-emailreceivers) | array | The list of email receivers that are part of this action group. | +| [`enabled`](#parameter-enabled) | bool | Indicates whether this action group is enabled. If an action group is not enabled, then none of its receivers will receive communications. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`itsmReceivers`](#parameter-itsmreceivers) | array | The list of ITSM receivers that are part of this action group. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`logicAppReceivers`](#parameter-logicappreceivers) | array | The list of logic app receivers that are part of this action group. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`smsReceivers`](#parameter-smsreceivers) | array | The list of SMS receivers that are part of this action group. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`voiceReceivers`](#parameter-voicereceivers) | array | The list of voice receivers that are part of this action group. | +| [`webhookReceivers`](#parameter-webhookreceivers) | array | The list of webhook receivers that are part of this action group. | + +### Parameter: `groupShortName` + +The short name of the action group. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the action group. + +- Required: Yes +- Type: string + +### Parameter: `armRoleReceivers` + +The list of ARM role receivers that are part of this action group. Roles are Azure RBAC roles and only built-in roles are supported. + +- Required: No +- Type: array + +### Parameter: `automationRunbookReceivers` + +The list of AutomationRunbook receivers that are part of this action group. + +- Required: No +- Type: array + +### Parameter: `azureAppPushReceivers` + +The list of AzureAppPush receivers that are part of this action group. + +- Required: No +- Type: array + +### Parameter: `azureFunctionReceivers` + +The list of function receivers that are part of this action group. + +- Required: No +- Type: array + +### Parameter: `emailReceivers` + +The list of email receivers that are part of this action group. + +- Required: No +- Type: array + +### Parameter: `enabled` + +Indicates whether this action group is enabled. If an action group is not enabled, then none of its receivers will receive communications. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `itsmReceivers` + +The list of ITSM receivers that are part of this action group. + +- Required: No +- Type: array + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `'global'` + +### Parameter: `logicAppReceivers` + +The list of logic app receivers that are part of this action group. + +- Required: No +- Type: array + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `smsReceivers` + +The list of SMS receivers that are part of this action group. + +- Required: No +- Type: array + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `voiceReceivers` + +The list of voice receivers that are part of this action group. + +- Required: No +- Type: array + +### Parameter: `webhookReceivers` + +The list of webhook receivers that are part of this action group. + +- Required: No +- Type: array + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the action group. | +| `resourceGroupName` | string | The resource group the action group was deployed into. | +| `resourceId` | string | The resource ID of the action group. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/insights/action-group/main.bicep b/avm/1.1.0/res/insights/action-group/main.bicep new file mode 100644 index 000000000..bad8c5417 --- /dev/null +++ b/avm/1.1.0/res/insights/action-group/main.bicep @@ -0,0 +1,146 @@ +metadata name = 'Action Groups' +metadata description = 'This module deploys an Action Group.' + +@description('Required. The name of the action group.') +param name string + +@description('Required. The short name of the action group.') +param groupShortName string + +@description('Optional. Indicates whether this action group is enabled. If an action group is not enabled, then none of its receivers will receive communications.') +param enabled bool = true + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. The list of email receivers that are part of this action group.') +param emailReceivers array? + +@description('Optional. The list of SMS receivers that are part of this action group.') +param smsReceivers array? + +@description('Optional. The list of webhook receivers that are part of this action group.') +param webhookReceivers array? + +@description('Optional. The list of ITSM receivers that are part of this action group.') +param itsmReceivers array? + +@description('Optional. The list of AzureAppPush receivers that are part of this action group.') +param azureAppPushReceivers array? + +@description('Optional. The list of AutomationRunbook receivers that are part of this action group.') +param automationRunbookReceivers array? + +@description('Optional. The list of voice receivers that are part of this action group.') +param voiceReceivers array? + +@description('Optional. The list of logic app receivers that are part of this action group.') +param logicAppReceivers array? + +@description('Optional. The list of function receivers that are part of this action group.') +param azureFunctionReceivers array? + +@description('Optional. The list of ARM role receivers that are part of this action group. Roles are Azure RBAC roles and only built-in roles are supported.') +param armRoleReceivers array? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Location for all resources.') +param location string = 'global' + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.insights-actiongroup.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource actionGroup 'Microsoft.Insights/actionGroups@2023-01-01' = { + name: name + location: location + tags: tags + properties: { + groupShortName: groupShortName + enabled: enabled + emailReceivers: emailReceivers + smsReceivers: smsReceivers + webhookReceivers: webhookReceivers + itsmReceivers: itsmReceivers + azureAppPushReceivers: azureAppPushReceivers + automationRunbookReceivers: automationRunbookReceivers + voiceReceivers: voiceReceivers + logicAppReceivers: logicAppReceivers + azureFunctionReceivers: azureFunctionReceivers + armRoleReceivers: armRoleReceivers + } +} + +resource actionGroup_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(actionGroup.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: actionGroup + } +] + +@description('The resource group the action group was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the action group.') +output name string = actionGroup.name + +@description('The resource ID of the action group.') +output resourceId string = actionGroup.id + +@description('The location the resource was deployed into.') +output location string = actionGroup.location diff --git a/avm/1.1.0/res/insights/action-group/main.json b/avm/1.1.0/res/insights/action-group/main.json new file mode 100644 index 000000000..e30d03815 --- /dev/null +++ b/avm/1.1.0/res/insights/action-group/main.json @@ -0,0 +1,324 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "1390192729878803338" + }, + "name": "Action Groups", + "description": "This module deploys an Action Group." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the action group." + } + }, + "groupShortName": { + "type": "string", + "metadata": { + "description": "Required. The short name of the action group." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether this action group is enabled. If an action group is not enabled, then none of its receivers will receive communications." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "emailReceivers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of email receivers that are part of this action group." + } + }, + "smsReceivers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of SMS receivers that are part of this action group." + } + }, + "webhookReceivers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of webhook receivers that are part of this action group." + } + }, + "itsmReceivers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of ITSM receivers that are part of this action group." + } + }, + "azureAppPushReceivers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of AzureAppPush receivers that are part of this action group." + } + }, + "automationRunbookReceivers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of AutomationRunbook receivers that are part of this action group." + } + }, + "voiceReceivers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of voice receivers that are part of this action group." + } + }, + "logicAppReceivers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of logic app receivers that are part of this action group." + } + }, + "azureFunctionReceivers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of function receivers that are part of this action group." + } + }, + "armRoleReceivers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of ARM role receivers that are part of this action group. Roles are Azure RBAC roles and only built-in roles are supported." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. Location for all resources." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-actiongroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "actionGroup": { + "type": "Microsoft.Insights/actionGroups", + "apiVersion": "2023-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "groupShortName": "[parameters('groupShortName')]", + "enabled": "[parameters('enabled')]", + "emailReceivers": "[parameters('emailReceivers')]", + "smsReceivers": "[parameters('smsReceivers')]", + "webhookReceivers": "[parameters('webhookReceivers')]", + "itsmReceivers": "[parameters('itsmReceivers')]", + "azureAppPushReceivers": "[parameters('azureAppPushReceivers')]", + "automationRunbookReceivers": "[parameters('automationRunbookReceivers')]", + "voiceReceivers": "[parameters('voiceReceivers')]", + "logicAppReceivers": "[parameters('logicAppReceivers')]", + "azureFunctionReceivers": "[parameters('azureFunctionReceivers')]", + "armRoleReceivers": "[parameters('armRoleReceivers')]" + } + }, + "actionGroup_roleAssignments": { + "copy": { + "name": "actionGroup_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/actionGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/actionGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "actionGroup" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the action group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the action group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the action group." + }, + "value": "[resourceId('Microsoft.Insights/actionGroups', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('actionGroup', '2023-01-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/action-group/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/insights/action-group/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..9f0d06aa1 --- /dev/null +++ b/avm/1.1.0/res/insights/action-group/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,49 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.actiongroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'iagmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + groupShortName: 'ag${serviceShort}001' + } + } +] diff --git a/avm/1.1.0/res/insights/action-group/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/insights/action-group/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/insights/action-group/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/insights/action-group/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/insights/action-group/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..f601e54f9 --- /dev/null +++ b/avm/1.1.0/res/insights/action-group/tests/e2e/max/main.test.bicep @@ -0,0 +1,104 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.actiongroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'iagmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + groupShortName: 'ag${serviceShort}001' + emailReceivers: [ + { + emailAddress: 'test.user@testcompany.com' + name: 'TestUser_-EmailAction-' + useCommonAlertSchema: true + } + { + emailAddress: 'test.user2@testcompany.com' + name: 'TestUser2' + useCommonAlertSchema: true + } + ] + roleAssignments: [ + { + name: 'fc3ee4d9-d0c0-42c2-962f-082cf8d78882' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + smsReceivers: [ + { + countryCode: '1' + name: 'TestUser_-SMSAction-' + phoneNumber: '2345678901' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/insights/action-group/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/insights/action-group/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/insights/action-group/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/insights/action-group/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/insights/action-group/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..e2195df6e --- /dev/null +++ b/avm/1.1.0/res/insights/action-group/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,63 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.actiongroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'iagwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + groupShortName: 'ag${serviceShort}001' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/insights/action-group/tests/unit/custom.tests.ps1 b/avm/1.1.0/res/insights/action-group/tests/unit/custom.tests.ps1 new file mode 100644 index 000000000..36b53af9c --- /dev/null +++ b/avm/1.1.0/res/insights/action-group/tests/unit/custom.tests.ps1 @@ -0,0 +1,7 @@ +########################### +## Additional unit tests ## +########################### +## +## You can add any custom static validation tests you want here, or add them spread accross multiple test files in the unit folder. +## +########################### diff --git a/avm/1.1.0/res/insights/action-group/version.json b/avm/1.1.0/res/insights/action-group/version.json new file mode 100644 index 000000000..3f863a2be --- /dev/null +++ b/avm/1.1.0/res/insights/action-group/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.4", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/activity-log-alert/README.md b/avm/1.1.0/res/insights/activity-log-alert/README.md new file mode 100644 index 000000000..d8a2bb4dd --- /dev/null +++ b/avm/1.1.0/res/insights/activity-log-alert/README.md @@ -0,0 +1,880 @@ +# Activity Log Alerts `[Microsoft.Insights/activityLogAlerts]` + +This module deploys an Activity Log Alert. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/activityLogAlerts` | [2020-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2020-10-01/activityLogAlerts) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/insights/activity-log-alert:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:' = { + name: 'activityLogAlertDeployment' + params: { + // Required parameters + conditions: [ + { + equals: 'ServiceHealth' + field: 'category' + } + { + anyOf: [ + { + equals: 'Incident' + field: 'properties.incidentType' + } + { + equals: 'Maintenance' + field: 'properties.incidentType' + } + ] + } + { + containsAny: [ + 'Storage' + ] + field: 'properties.impactedServices[*].ServiceName' + } + { + containsAny: [ + 'West Europe' + ] + field: 'properties.impactedServices[*].ImpactedRegions[*].RegionName' + } + ] + name: 'ialamin001' + // Non-required parameters + location: 'global' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "conditions": { + "value": [ + { + "equals": "ServiceHealth", + "field": "category" + }, + { + "anyOf": [ + { + "equals": "Incident", + "field": "properties.incidentType" + }, + { + "equals": "Maintenance", + "field": "properties.incidentType" + } + ] + }, + { + "containsAny": [ + "Storage" + ], + "field": "properties.impactedServices[*].ServiceName" + }, + { + "containsAny": [ + "West Europe" + ], + "field": "properties.impactedServices[*].ImpactedRegions[*].RegionName" + } + ] + }, + "name": { + "value": "ialamin001" + }, + // Non-required parameters + "location": { + "value": "global" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/activity-log-alert:' + +// Required parameters +param conditions = [ + { + equals: 'ServiceHealth' + field: 'category' + } + { + anyOf: [ + { + equals: 'Incident' + field: 'properties.incidentType' + } + { + equals: 'Maintenance' + field: 'properties.incidentType' + } + ] + } + { + containsAny: [ + 'Storage' + ] + field: 'properties.impactedServices[*].ServiceName' + } + { + containsAny: [ + 'West Europe' + ] + field: 'properties.impactedServices[*].ImpactedRegions[*].RegionName' + } +] +param name = 'ialamin001' +// Non-required parameters +param location = 'global' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:' = { + name: 'activityLogAlertDeployment' + params: { + // Required parameters + conditions: [ + { + equals: 'ServiceHealth' + field: 'category' + } + { + anyOf: [ + { + equals: 'Incident' + field: 'properties.incidentType' + } + { + equals: 'Maintenance' + field: 'properties.incidentType' + } + ] + } + { + containsAny: [ + 'Action Groups' + 'Activity Logs & Alerts' + ] + field: 'properties.impactedServices[*].ServiceName' + } + { + containsAny: [ + 'Global' + 'West Europe' + ] + field: 'properties.impactedServices[*].ImpactedRegions[*].RegionName' + } + ] + name: 'ialamax001' + // Non-required parameters + actions: [ + { + actionGroupId: '' + } + ] + location: 'global' + roleAssignments: [ + { + name: 'be96d7a9-6596-40c7-9acd-db6acd5cd41b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + scopes: [ + '' + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "conditions": { + "value": [ + { + "equals": "ServiceHealth", + "field": "category" + }, + { + "anyOf": [ + { + "equals": "Incident", + "field": "properties.incidentType" + }, + { + "equals": "Maintenance", + "field": "properties.incidentType" + } + ] + }, + { + "containsAny": [ + "Action Groups", + "Activity Logs & Alerts" + ], + "field": "properties.impactedServices[*].ServiceName" + }, + { + "containsAny": [ + "Global", + "West Europe" + ], + "field": "properties.impactedServices[*].ImpactedRegions[*].RegionName" + } + ] + }, + "name": { + "value": "ialamax001" + }, + // Non-required parameters + "actions": { + "value": [ + { + "actionGroupId": "" + } + ] + }, + "location": { + "value": "global" + }, + "roleAssignments": { + "value": [ + { + "name": "be96d7a9-6596-40c7-9acd-db6acd5cd41b", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "scopes": { + "value": [ + "" + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/activity-log-alert:' + +// Required parameters +param conditions = [ + { + equals: 'ServiceHealth' + field: 'category' + } + { + anyOf: [ + { + equals: 'Incident' + field: 'properties.incidentType' + } + { + equals: 'Maintenance' + field: 'properties.incidentType' + } + ] + } + { + containsAny: [ + 'Action Groups' + 'Activity Logs & Alerts' + ] + field: 'properties.impactedServices[*].ServiceName' + } + { + containsAny: [ + 'Global' + 'West Europe' + ] + field: 'properties.impactedServices[*].ImpactedRegions[*].RegionName' + } +] +param name = 'ialamax001' +// Non-required parameters +param actions = [ + { + actionGroupId: '' + } +] +param location = 'global' +param roleAssignments = [ + { + name: 'be96d7a9-6596-40c7-9acd-db6acd5cd41b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scopes = [ + '' +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:' = { + name: 'activityLogAlertDeployment' + params: { + // Required parameters + conditions: [ + { + equals: 'ServiceHealth' + field: 'category' + } + { + anyOf: [ + { + equals: 'Incident' + field: 'properties.incidentType' + } + { + equals: 'Maintenance' + field: 'properties.incidentType' + } + ] + } + { + containsAny: [ + 'Action Groups' + 'Activity Logs & Alerts' + ] + field: 'properties.impactedServices[*].ServiceName' + } + { + containsAny: [ + 'Global' + 'West Europe' + ] + field: 'properties.impactedServices[*].ImpactedRegions[*].RegionName' + } + ] + name: 'ialawaf001' + // Non-required parameters + actions: [ + { + actionGroupId: '' + } + ] + location: 'global' + scopes: [ + '' + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "conditions": { + "value": [ + { + "equals": "ServiceHealth", + "field": "category" + }, + { + "anyOf": [ + { + "equals": "Incident", + "field": "properties.incidentType" + }, + { + "equals": "Maintenance", + "field": "properties.incidentType" + } + ] + }, + { + "containsAny": [ + "Action Groups", + "Activity Logs & Alerts" + ], + "field": "properties.impactedServices[*].ServiceName" + }, + { + "containsAny": [ + "Global", + "West Europe" + ], + "field": "properties.impactedServices[*].ImpactedRegions[*].RegionName" + } + ] + }, + "name": { + "value": "ialawaf001" + }, + // Non-required parameters + "actions": { + "value": [ + { + "actionGroupId": "" + } + ] + }, + "location": { + "value": "global" + }, + "scopes": { + "value": [ + "" + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/activity-log-alert:' + +// Required parameters +param conditions = [ + { + equals: 'ServiceHealth' + field: 'category' + } + { + anyOf: [ + { + equals: 'Incident' + field: 'properties.incidentType' + } + { + equals: 'Maintenance' + field: 'properties.incidentType' + } + ] + } + { + containsAny: [ + 'Action Groups' + 'Activity Logs & Alerts' + ] + field: 'properties.impactedServices[*].ServiceName' + } + { + containsAny: [ + 'Global' + 'West Europe' + ] + field: 'properties.impactedServices[*].ImpactedRegions[*].RegionName' + } +] +param name = 'ialawaf001' +// Non-required parameters +param actions = [ + { + actionGroupId: '' + } +] +param location = 'global' +param scopes = [ + '' +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`conditions`](#parameter-conditions) | array | An Array of objects containing conditions that will cause this alert to activate. Conditions can also be combined with logical operators `allOf` and `anyOf`. Each condition can specify only one field between `equals` and `containsAny`. An alert rule condition must have exactly one category (Administrative, ServiceHealth, ResourceHealth, Alert, Autoscale, Recommendation, Security, or Policy). | +| [`name`](#parameter-name) | string | The name of the alert. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`actions`](#parameter-actions) | array | The list of actions to take when alert triggers. | +| [`alertDescription`](#parameter-alertdescription) | string | Description of the alert. | +| [`enabled`](#parameter-enabled) | bool | Indicates whether this alert is enabled. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`scopes`](#parameter-scopes) | array | The list of resource IDs that this Activity Log Alert is scoped to. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `conditions` + +An Array of objects containing conditions that will cause this alert to activate. Conditions can also be combined with logical operators `allOf` and `anyOf`. Each condition can specify only one field between `equals` and `containsAny`. An alert rule condition must have exactly one category (Administrative, ServiceHealth, ResourceHealth, Alert, Autoscale, Recommendation, Security, or Policy). + +- Required: Yes +- Type: array + +### Parameter: `name` + +The name of the alert. + +- Required: Yes +- Type: string + +### Parameter: `actions` + +The list of actions to take when alert triggers. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `alertDescription` + +Description of the alert. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `enabled` + +Indicates whether this alert is enabled. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `'global'` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `scopes` + +The list of resource IDs that this Activity Log Alert is scoped to. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + '[subscription().id]' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the activity log alert. | +| `resourceGroupName` | string | The resource group the activity log alert was deployed into. | +| `resourceId` | string | The resource ID of the activity log alert. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/insights/activity-log-alert/main.bicep b/avm/1.1.0/res/insights/activity-log-alert/main.bicep new file mode 100644 index 000000000..2401ab156 --- /dev/null +++ b/avm/1.1.0/res/insights/activity-log-alert/main.bicep @@ -0,0 +1,131 @@ +metadata name = 'Activity Log Alerts' +metadata description = 'This module deploys an Activity Log Alert.' + +@description('Required. The name of the alert.') +param name string + +@description('Optional. Description of the alert.') +param alertDescription string = '' + +@description('Optional. Location for all resources.') +param location string = 'global' + +@description('Optional. Indicates whether this alert is enabled.') +param enabled bool = true + +@description('Optional. The list of resource IDs that this Activity Log Alert is scoped to.') +param scopes array = [ + subscription().id +] + +@description('Optional. The list of actions to take when alert triggers.') +param actions array = [] + +@description('Required. An Array of objects containing conditions that will cause this alert to activate. Conditions can also be combined with logical operators `allOf` and `anyOf`. Each condition can specify only one field between `equals` and `containsAny`. An alert rule condition must have exactly one category (Administrative, ServiceHealth, ResourceHealth, Alert, Autoscale, Recommendation, Security, or Policy).') +param conditions array + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var actionGroups = [ + for action in actions: { + actionGroupId: action.?actionGroupId ?? action + webhookProperties: action.?webhookProperties + } +] + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.insights-activitylogalert.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource activityLogAlert 'Microsoft.Insights/activityLogAlerts@2020-10-01' = { + name: name + location: location + tags: tags + properties: { + scopes: scopes + condition: { + allOf: conditions + } + actions: { + actionGroups: actionGroups + } + enabled: enabled + description: alertDescription + } +} + +resource activityLogAlert_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(activityLogAlert.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: activityLogAlert + } +] + +@description('The name of the activity log alert.') +output name string = activityLogAlert.name + +@description('The resource ID of the activity log alert.') +output resourceId string = activityLogAlert.id + +@description('The resource group the activity log alert was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = activityLogAlert.location diff --git a/avm/1.1.0/res/insights/activity-log-alert/main.json b/avm/1.1.0/res/insights/activity-log-alert/main.json new file mode 100644 index 000000000..b9334b0a7 --- /dev/null +++ b/avm/1.1.0/res/insights/activity-log-alert/main.json @@ -0,0 +1,282 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "3537417410371628791" + }, + "name": "Activity Log Alerts", + "description": "This module deploys an Activity Log Alert." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the alert." + } + }, + "alertDescription": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Description of the alert." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether this alert is enabled." + } + }, + "scopes": { + "type": "array", + "defaultValue": [ + "[subscription().id]" + ], + "metadata": { + "description": "Optional. The list of resource IDs that this Activity Log Alert is scoped to." + } + }, + "actions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The list of actions to take when alert triggers." + } + }, + "conditions": { + "type": "array", + "metadata": { + "description": "Required. An Array of objects containing conditions that will cause this alert to activate. Conditions can also be combined with logical operators `allOf` and `anyOf`. Each condition can specify only one field between `equals` and `containsAny`. An alert rule condition must have exactly one category (Administrative, ServiceHealth, ResourceHealth, Alert, Autoscale, Recommendation, Security, or Policy)." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "actionGroups", + "count": "[length(parameters('actions'))]", + "input": { + "actionGroupId": "[coalesce(tryGet(parameters('actions')[copyIndex('actionGroups')], 'actionGroupId'), parameters('actions')[copyIndex('actionGroups')])]", + "webhookProperties": "[tryGet(parameters('actions')[copyIndex('actionGroups')], 'webhookProperties')]" + } + }, + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-activitylogalert.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "activityLogAlert": { + "type": "Microsoft.Insights/activityLogAlerts", + "apiVersion": "2020-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "scopes": "[parameters('scopes')]", + "condition": { + "allOf": "[parameters('conditions')]" + }, + "actions": { + "actionGroups": "[variables('actionGroups')]" + }, + "enabled": "[parameters('enabled')]", + "description": "[parameters('alertDescription')]" + } + }, + "activityLogAlert_roleAssignments": { + "copy": { + "name": "activityLogAlert_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/activityLogAlerts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/activityLogAlerts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "activityLogAlert" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the activity log alert." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the activity log alert." + }, + "value": "[resourceId('Microsoft.Insights/activityLogAlerts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the activity log alert was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('activityLogAlert', '2020-10-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..5b099760e --- /dev/null +++ b/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,78 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.activityLogAlerts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ialamin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + conditions: [ + { + field: 'category' + equals: 'ServiceHealth' + } + { + anyOf: [ + { + field: 'properties.incidentType' + equals: 'Incident' + } + { + field: 'properties.incidentType' + equals: 'Maintenance' + } + ] + } + { + field: 'properties.impactedServices[*].ServiceName' + containsAny: [ + 'Storage' + ] + } + { + field: 'properties.impactedServices[*].ImpactedRegions[*].RegionName' + containsAny: [ + 'West Europe' + ] + } + ] + } + } +] diff --git a/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..f03108936 --- /dev/null +++ b/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/max/dependencies.bicep @@ -0,0 +1,28 @@ +@description('Required. The name of the Action Group to create.') +param actionGroupName string + +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource actionGroup 'Microsoft.Insights/actionGroups@2022-06-01' = { + name: actionGroupName + location: 'global' + properties: { + groupShortName: substring(replace(actionGroupName, '-', ''), 0, 11) + enabled: true + } +} + +@description('The resource ID of the created Action Group.') +output actionGroupResourceId string = actionGroup.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..dd3120e2a --- /dev/null +++ b/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/max/main.test.bicep @@ -0,0 +1,125 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.activityLogAlerts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ialamax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + actionGroupName: 'dep-${namePrefix}-ag-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + conditions: [ + { + field: 'category' + equals: 'ServiceHealth' + } + { + anyOf: [ + { + field: 'properties.incidentType' + equals: 'Incident' + } + { + field: 'properties.incidentType' + equals: 'Maintenance' + } + ] + } + { + field: 'properties.impactedServices[*].ServiceName' + containsAny: [ + 'Action Groups' + 'Activity Logs & Alerts' + ] + } + { + field: 'properties.impactedServices[*].ImpactedRegions[*].RegionName' + containsAny: [ + 'West Europe' + 'Global' + ] + } + ] + actions: [ + { + actionGroupId: nestedDependencies.outputs.actionGroupResourceId + } + ] + roleAssignments: [ + { + name: 'be96d7a9-6596-40c7-9acd-db6acd5cd41b' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + scopes: [ + subscription().id + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..3f76856cb --- /dev/null +++ b/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,14 @@ +@description('Required. The name of the Action Group to create.') +param actionGroupName string + +resource actionGroup 'Microsoft.Insights/actionGroups@2022-06-01' = { + name: actionGroupName + location: 'global' + properties: { + groupShortName: substring(replace(actionGroupName, '-', ''), 0, 11) + enabled: true + } +} + +@description('The resource ID of the created Action Group.') +output actionGroupResourceId string = actionGroup.id diff --git a/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..e86926d0b --- /dev/null +++ b/avm/1.1.0/res/insights/activity-log-alert/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,101 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.activityLogAlerts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ialawaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + actionGroupName: 'dep-${namePrefix}-ag-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + conditions: [ + { + field: 'category' + equals: 'ServiceHealth' + } + { + anyOf: [ + { + field: 'properties.incidentType' + equals: 'Incident' + } + { + field: 'properties.incidentType' + equals: 'Maintenance' + } + ] + } + { + field: 'properties.impactedServices[*].ServiceName' + containsAny: [ + 'Action Groups' + 'Activity Logs & Alerts' + ] + } + { + field: 'properties.impactedServices[*].ImpactedRegions[*].RegionName' + containsAny: [ + 'West Europe' + 'Global' + ] + } + ] + actions: [ + { + actionGroupId: nestedDependencies.outputs.actionGroupResourceId + } + ] + scopes: [ + subscription().id + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/insights/activity-log-alert/version.json b/avm/1.1.0/res/insights/activity-log-alert/version.json new file mode 100644 index 000000000..c177b1bb5 --- /dev/null +++ b/avm/1.1.0/res/insights/activity-log-alert/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/component/README.md b/avm/1.1.0/res/insights/component/README.md new file mode 100644 index 000000000..438d8a2ed --- /dev/null +++ b/avm/1.1.0/res/insights/component/README.md @@ -0,0 +1,981 @@ +# Application Insights `[Microsoft.Insights/components]` + +This component deploys an Application Insights instance. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/components` | [2020-02-02](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2020-02-02/components) | +| `microsoft.insights/components/linkedStorageAccounts` | [2020-03-01-preview](https://learn.microsoft.com/en-us/azure/templates/microsoft.insights/2020-03-01-preview/components/linkedStorageAccounts) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/insights/component:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module component 'br/public:avm/res/insights/component:' = { + name: 'componentDeployment' + params: { + // Required parameters + name: 'icmin001' + workspaceResourceId: '' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "icmin001" + }, + "workspaceResourceId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/component:' + +// Required parameters +param name = 'icmin001' +param workspaceResourceId = '' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module component 'br/public:avm/res/insights/component:' = { + name: 'componentDeployment' + params: { + // Required parameters + name: 'icmax001' + workspaceResourceId: '' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + disableIpMasking: false + disableLocalAuth: true + flowType: 'Redfield' + forceCustomerStorageForProfiler: true + linkedStorageAccountResourceId: '' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + requestSource: 'Azure' + roleAssignments: [ + { + name: '8aacced3-3fce-41bc-a416-959df1acec57' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "icmax001" + }, + "workspaceResourceId": { + "value": "" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "disableIpMasking": { + "value": false + }, + "disableLocalAuth": { + "value": true + }, + "flowType": { + "value": "Redfield" + }, + "forceCustomerStorageForProfiler": { + "value": true + }, + "linkedStorageAccountResourceId": { + "value": "" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "requestSource": { + "value": "Azure" + }, + "roleAssignments": { + "value": [ + { + "name": "8aacced3-3fce-41bc-a416-959df1acec57", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/component:' + +// Required parameters +param name = 'icmax001' +param workspaceResourceId = '' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableIpMasking = false +param disableLocalAuth = true +param flowType = 'Redfield' +param forceCustomerStorageForProfiler = true +param linkedStorageAccountResourceId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param requestSource = 'Azure' +param roleAssignments = [ + { + name: '8aacced3-3fce-41bc-a416-959df1acec57' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module component 'br/public:avm/res/insights/component:' = { + name: 'componentDeployment' + params: { + // Required parameters + name: 'icwaf001' + workspaceResourceId: '' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "icwaf001" + }, + "workspaceResourceId": { + "value": "" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/component:' + +// Required parameters +param name = 'icwaf001' +param workspaceResourceId = '' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Application Insights. | +| [`workspaceResourceId`](#parameter-workspaceresourceid) | string | Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationType`](#parameter-applicationtype) | string | Application type. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`disableIpMasking`](#parameter-disableipmasking) | bool | Disable IP masking. Default value is set to true. | +| [`disableLocalAuth`](#parameter-disablelocalauth) | bool | Disable Non-AAD based Auth. Default value is set to false. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`flowType`](#parameter-flowtype) | string | Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API. | +| [`forceCustomerStorageForProfiler`](#parameter-forcecustomerstorageforprofiler) | bool | Force users to create their own storage account for profiler and debugger. | +| [`kind`](#parameter-kind) | string | The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone. | +| [`linkedStorageAccountResourceId`](#parameter-linkedstorageaccountresourceid) | string | Linked storage account resource ID. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`publicNetworkAccessForIngestion`](#parameter-publicnetworkaccessforingestion) | string | The network access type for accessing Application Insights ingestion. - Enabled or Disabled. | +| [`publicNetworkAccessForQuery`](#parameter-publicnetworkaccessforquery) | string | The network access type for accessing Application Insights query. - Enabled or Disabled. | +| [`requestSource`](#parameter-requestsource) | string | Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'. | +| [`retentionInDays`](#parameter-retentionindays) | int | Retention period in days. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`samplingPercentage`](#parameter-samplingpercentage) | int | Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `name` + +Name of the Application Insights. + +- Required: Yes +- Type: string + +### Parameter: `workspaceResourceId` + +Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property. + +- Required: Yes +- Type: string + +### Parameter: `applicationType` + +Application type. + +- Required: No +- Type: string +- Default: `'web'` +- Allowed: + ```Bicep + [ + 'other' + 'web' + ] + ``` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of the diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of the diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `disableIpMasking` + +Disable IP masking. Default value is set to true. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `disableLocalAuth` + +Disable Non-AAD based Auth. Default value is set to false. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `flowType` + +Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API. + +- Required: No +- Type: string + +### Parameter: `forceCustomerStorageForProfiler` + +Force users to create their own storage account for profiler and debugger. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `kind` + +The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `linkedStorageAccountResourceId` + +Linked storage account resource ID. + +- Required: No +- Type: string + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `publicNetworkAccessForIngestion` + +The network access type for accessing Application Insights ingestion. - Enabled or Disabled. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `publicNetworkAccessForQuery` + +The network access type for accessing Application Insights query. - Enabled or Disabled. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `requestSource` + +Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'. + +- Required: No +- Type: string + +### Parameter: `retentionInDays` + +Retention period in days. + +- Required: No +- Type: int +- Default: `365` +- Allowed: + ```Bicep + [ + 30 + 60 + 90 + 120 + 180 + 270 + 365 + 550 + 730 + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Monitoring Metrics Publisher'` + - `'Application Insights Component Contributor'` + - `'Application Insights Snapshot Debugger'` + - `'Monitoring Contributor'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `samplingPercentage` + +Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry. + +- Required: No +- Type: int +- Default: `100` +- MinValue: 0 +- MaxValue: 100 + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 100 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `applicationId` | string | The application ID of the application insights component. | +| `connectionString` | string | Application Insights Connection String. | +| `instrumentationKey` | string | Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the application insights component. | +| `resourceGroupName` | string | The resource group the application insights component was deployed into. | +| `resourceId` | string | The resource ID of the application insights component. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.3.0` | Remote reference | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/insights/component/linkedStorageAccounts/README.md b/avm/1.1.0/res/insights/component/linkedStorageAccounts/README.md new file mode 100644 index 000000000..ad26f5698 --- /dev/null +++ b/avm/1.1.0/res/insights/component/linkedStorageAccounts/README.md @@ -0,0 +1,51 @@ +# Application Insights Linked Storage Account `[microsoft.insights/components/linkedStorageAccounts]` + +This component deploys an Application Insights Linked Storage Account. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `microsoft.insights/components/linkedStorageAccounts` | [2020-03-01-preview](https://learn.microsoft.com/en-us/azure/templates/microsoft.insights/2020-03-01-preview/components/linkedStorageAccounts) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageAccountResourceId`](#parameter-storageaccountresourceid) | string | Linked storage account resource ID. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appInsightsName`](#parameter-appinsightsname) | string | The name of the parent Application Insights instance. Required if the template is used in a standalone deployment. | + +### Parameter: `storageAccountResourceId` + +Linked storage account resource ID. + +- Required: Yes +- Type: string + +### Parameter: `appInsightsName` + +The name of the parent Application Insights instance. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the Linked Storage Account. | +| `resourceGroupName` | string | The resource group the agent pool was deployed into. | +| `resourceId` | string | The resource ID of the Linked Storage Account. | diff --git a/avm/1.1.0/res/insights/component/linkedStorageAccounts/main.bicep b/avm/1.1.0/res/insights/component/linkedStorageAccounts/main.bicep new file mode 100644 index 000000000..4239327d7 --- /dev/null +++ b/avm/1.1.0/res/insights/component/linkedStorageAccounts/main.bicep @@ -0,0 +1,29 @@ +metadata name = 'Application Insights Linked Storage Account' +metadata description = 'This component deploys an Application Insights Linked Storage Account.' + +@description('Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment.') +param appInsightsName string + +@description('Required. Linked storage account resource ID.') +param storageAccountResourceId string + +resource appInsights 'Microsoft.Insights/components@2020-02-02' existing = { + name: appInsightsName +} + +resource linkedStorageAccount 'Microsoft.Insights/components/linkedStorageAccounts@2020-03-01-preview' = { + name: 'ServiceProfiler' + parent: appInsights + properties: { + linkedStorageAccount: storageAccountResourceId + } +} + +@description('The name of the Linked Storage Account.') +output name string = linkedStorageAccount.name + +@description('The resource ID of the Linked Storage Account.') +output resourceId string = linkedStorageAccount.id + +@description('The resource group the agent pool was deployed into.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/insights/component/linkedStorageAccounts/main.json b/avm/1.1.0/res/insights/component/linkedStorageAccounts/main.json new file mode 100644 index 000000000..6e9338590 --- /dev/null +++ b/avm/1.1.0/res/insights/component/linkedStorageAccounts/main.json @@ -0,0 +1,60 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "10861379689695100897" + }, + "name": "Application Insights Linked Storage Account", + "description": "This component deploys an Application Insights Linked Storage Account." + }, + "parameters": { + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Linked storage account resource ID." + } + } + }, + "resources": [ + { + "type": "microsoft.insights/components/linkedStorageAccounts", + "apiVersion": "2020-03-01-preview", + "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", + "properties": { + "linkedStorageAccount": "[parameters('storageAccountResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Linked Storage Account." + }, + "value": "ServiceProfiler" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Linked Storage Account." + }, + "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/component/main.bicep b/avm/1.1.0/res/insights/component/main.bicep new file mode 100644 index 000000000..f08d7d312 --- /dev/null +++ b/avm/1.1.0/res/insights/component/main.bicep @@ -0,0 +1,255 @@ +metadata name = 'Application Insights' +metadata description = 'This component deploys an Application Insights instance.' + +@description('Required. Name of the Application Insights.') +param name string + +@description('Optional. Application type.') +@allowed([ + 'web' + 'other' +]) +param applicationType string = 'web' + +@description('Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property.') +param workspaceResourceId string + +@description('Optional. Disable IP masking. Default value is set to true.') +param disableIpMasking bool = true + +@description('Optional. Disable Non-AAD based Auth. Default value is set to false.') +param disableLocalAuth bool = false + +@description('Optional. Force users to create their own storage account for profiler and debugger.') +param forceCustomerStorageForProfiler bool = false + +@description('Optional. Linked storage account resource ID.') +param linkedStorageAccountResourceId string? + +@description('Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccessForIngestion string = 'Enabled' + +@description('Optional. The network access type for accessing Application Insights query. - Enabled or Disabled.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccessForQuery string = 'Enabled' + +@description('Optional. Retention period in days.') +@allowed([ + 30 + 60 + 90 + 120 + 180 + 270 + 365 + 550 + 730 +]) +param retentionInDays int = 365 + +@description('Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry.') +@minValue(0) +@maxValue(100) +param samplingPercentage int = 100 + +@description('Optional. Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to \'Bluefield\' when creating/updating a component via the REST API.') +param flowType string? + +@description('Optional. Describes what tool created this Application Insights component. Customers using this API should set this to the default \'rest\'.') +param requestSource string? + +@description('Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone.') +param kind string = '' + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.3.0' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.3.0' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) + 'Monitoring Metrics Publisher': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '3913510d-42f4-4e42-8a64-420c390055eb' + ) + 'Application Insights Component Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'ae349356-3a1b-4a5e-921d-050484c6347e' + ) + 'Application Insights Snapshot Debugger': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '08954f03-6346-4c2e-81c0-ec3a5cfae23b' + ) + 'Monitoring Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '749f88d5-cbae-40b8-bcfc-e573ddc772fa' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.insights-component.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource appInsights 'Microsoft.Insights/components@2020-02-02' = { + name: name + location: location + tags: tags + kind: kind + properties: { + Application_Type: applicationType + DisableIpMasking: disableIpMasking + DisableLocalAuth: disableLocalAuth + ForceCustomerStorageForProfiler: forceCustomerStorageForProfiler + WorkspaceResourceId: workspaceResourceId + publicNetworkAccessForIngestion: publicNetworkAccessForIngestion + publicNetworkAccessForQuery: publicNetworkAccessForQuery + RetentionInDays: retentionInDays + SamplingPercentage: samplingPercentage + Flow_Type: flowType + Request_Source: requestSource + } +} + +module linkedStorageAccount 'linkedStorageAccounts/main.bicep' = if (!empty(linkedStorageAccountResourceId)) { + name: '${uniqueString(deployment().name, location)}-appInsights-linkedStorageAccount' + params: { + appInsightsName: appInsights.name + storageAccountResourceId: linkedStorageAccountResourceId ?? '' + } +} + +resource appInsights_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(appInsights.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: appInsights + } +] + +resource appInsights_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: appInsights +} + +resource appInsights_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: appInsights + } +] + +@description('The name of the application insights component.') +output name string = appInsights.name + +@description('The resource ID of the application insights component.') +output resourceId string = appInsights.id + +@description('The resource group the application insights component was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The application ID of the application insights component.') +output applicationId string = appInsights.properties.AppId + +@description('The location the resource was deployed into.') +output location string = appInsights.location + +@description('Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component.') +output instrumentationKey string = appInsights.properties.InstrumentationKey + +@description('Application Insights Connection String.') +output connectionString string = appInsights.properties.ConnectionString diff --git a/avm/1.1.0/res/insights/component/main.json b/avm/1.1.0/res/insights/component/main.json new file mode 100644 index 000000000..e61ab6ae2 --- /dev/null +++ b/avm/1.1.0/res/insights/component/main.json @@ -0,0 +1,688 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "10160470062491934963" + }, + "name": "Application Insights", + "description": "This component deploys an Application Insights instance." + }, + "definitions": { + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application Insights." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], + "metadata": { + "description": "Optional. Application type." + } + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." + } + }, + "disableIpMasking": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable IP masking. Default value is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." + } + }, + "forceCustomerStorageForProfiler": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Force users to create their own storage account for profiler and debugger." + } + }, + "linkedStorageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Linked storage account resource ID." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "allowedValues": [ + 30, + 60, + 90, + 120, + 180, + 270, + 365, + 550, + 730 + ], + "metadata": { + "description": "Optional. Retention period in days." + } + }, + "samplingPercentage": { + "type": "int", + "defaultValue": 100, + "minValue": 0, + "maxValue": 100, + "metadata": { + "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." + } + }, + "flowType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API." + } + }, + "requestSource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'." + } + }, + "kind": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", + "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "appInsights": { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "properties": { + "Application_Type": "[parameters('applicationType')]", + "DisableIpMasking": "[parameters('disableIpMasking')]", + "DisableLocalAuth": "[parameters('disableLocalAuth')]", + "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "SamplingPercentage": "[parameters('samplingPercentage')]", + "Flow_Type": "[parameters('flowType')]", + "Request_Source": "[parameters('requestSource')]" + } + }, + "appInsights_roleAssignments": { + "copy": { + "name": "appInsights_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "appInsights_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "appInsights_diagnosticSettings": { + "copy": { + "name": "appInsights_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "linkedStorageAccount": { + "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appInsightsName": { + "value": "[parameters('name')]" + }, + "storageAccountResourceId": { + "value": "[coalesce(parameters('linkedStorageAccountResourceId'), '')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "10861379689695100897" + }, + "name": "Application Insights Linked Storage Account", + "description": "This component deploys an Application Insights Linked Storage Account." + }, + "parameters": { + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Linked storage account resource ID." + } + } + }, + "resources": [ + { + "type": "microsoft.insights/components/linkedStorageAccounts", + "apiVersion": "2020-03-01-preview", + "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", + "properties": { + "linkedStorageAccount": "[parameters('storageAccountResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Linked Storage Account." + }, + "value": "ServiceProfiler" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Linked Storage Account." + }, + "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "appInsights" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the application insights component." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights component." + }, + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights component was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationId": { + "type": "string", + "metadata": { + "description": "The application ID of the application insights component." + }, + "value": "[reference('appInsights').AppId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('appInsights', '2020-02-02', 'full').location]" + }, + "instrumentationKey": { + "type": "string", + "metadata": { + "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." + }, + "value": "[reference('appInsights').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Application Insights Connection String." + }, + "value": "[reference('appInsights').ConnectionString]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/component/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/insights/component/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..63e7a207d --- /dev/null +++ b/avm/1.1.0/res/insights/component/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id diff --git a/avm/1.1.0/res/insights/component/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/insights/component/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..d2fe9e244 --- /dev/null +++ b/avm/1.1.0/res/insights/component/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,55 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.components-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'icmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + workspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + } +} diff --git a/avm/1.1.0/res/insights/component/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/insights/component/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..dfc9e8a89 --- /dev/null +++ b/avm/1.1.0/res/insights/component/tests/e2e/max/dependencies.bicep @@ -0,0 +1,35 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + allowBlobPublicAccess: false + networkAcls: { + defaultAction: 'Deny' + bypass: 'AzureServices' + } + } +} + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/insights/component/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/insights/component/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..1fa947726 --- /dev/null +++ b/avm/1.1.0/res/insights/component/tests/e2e/max/main.test.bicep @@ -0,0 +1,121 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.components-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'icmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}sa${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + disableIpMasking: false + disableLocalAuth: true + forceCustomerStorageForProfiler: true + linkedStorageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + flowType: 'Redfield' + requestSource: 'Azure' + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '8aacced3-3fce-41bc-a416-959df1acec57' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} diff --git a/avm/1.1.0/res/insights/component/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/insights/component/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/insights/component/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/insights/component/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/insights/component/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..7104c68d2 --- /dev/null +++ b/avm/1.1.0/res/insights/component/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,88 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.components-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'icwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} diff --git a/avm/1.1.0/res/insights/component/version.json b/avm/1.1.0/res/insights/component/version.json new file mode 100644 index 000000000..21226dd43 --- /dev/null +++ b/avm/1.1.0/res/insights/component/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.6", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/data-collection-endpoint/README.md b/avm/1.1.0/res/insights/data-collection-endpoint/README.md new file mode 100644 index 000000000..b6350fd2f --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-endpoint/README.md @@ -0,0 +1,605 @@ +# Data Collection Endpoints `[Microsoft.Insights/dataCollectionEndpoints]` + +This module deploys a Data Collection Endpoint. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/dataCollectionEndpoints` | [2023-03-11](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2023-03-11/dataCollectionEndpoints) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/insights/data-collection-endpoint:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoint:' = { + name: 'dataCollectionEndpointDeployment' + params: { + // Required parameters + name: 'idcemin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "idcemin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-endpoint:' + +// Required parameters +param name = 'idcemin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoint:' = { + name: 'dataCollectionEndpointDeployment' + params: { + // Required parameters + name: 'idcemax001' + // Non-required parameters + description: 'This is a test data collection endpoint.' + kind: 'Windows' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + publicNetworkAccess: 'Enabled' + roleAssignments: [ + { + name: 'db496446-89ac-4d91-a189-71544de0150a' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "idcemax001" + }, + // Non-required parameters + "description": { + "value": "This is a test data collection endpoint." + }, + "kind": { + "value": "Windows" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "publicNetworkAccess": { + "value": "Enabled" + }, + "roleAssignments": { + "value": [ + { + "name": "db496446-89ac-4d91-a189-71544de0150a", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name", + "kind": "Windows", + "resourceType": "Data Collection Rules" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-endpoint:' + +// Required parameters +param name = 'idcemax001' +// Non-required parameters +param description = 'This is a test data collection endpoint.' +param kind = 'Windows' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param publicNetworkAccess = 'Enabled' +param roleAssignments = [ + { + name: 'db496446-89ac-4d91-a189-71544de0150a' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoint:' = { + name: 'dataCollectionEndpointDeployment' + params: { + // Required parameters + name: 'idcewaf001' + // Non-required parameters + kind: 'Windows' + location: '' + publicNetworkAccess: 'Disabled' + tags: { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "idcewaf001" + }, + // Non-required parameters + "kind": { + "value": "Windows" + }, + "location": { + "value": "" + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name", + "kind": "Windows", + "resourceType": "Data Collection Rules" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-endpoint:' + +// Required parameters +param name = 'idcewaf001' +// Non-required parameters +param kind = 'Windows' +param location = '' +param publicNetworkAccess = 'Disabled' +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the data collection endpoint. The name is case insensitive. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | Description of the data collection endpoint. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`kind`](#parameter-kind) | string | The kind of the resource. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | The configuration to set whether network access from public internet to the endpoints are allowed. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Resource tags. | + +### Parameter: `name` + +The name of the data collection endpoint. The name is case insensitive. + +- Required: Yes +- Type: string + +### Parameter: `description` + +Description of the data collection endpoint. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `kind` + +The kind of the resource. + +- Required: No +- Type: string +- Default: `'Linux'` +- Allowed: + ```Bicep + [ + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `publicNetworkAccess` + +The configuration to set whether network access from public internet to the endpoints are allowed. + +- Required: No +- Type: string +- Default: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + 'SecuredByPerimeter' + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the dataCollectionEndpoint. | +| `resourceGroupName` | string | The name of the resource group the dataCollectionEndpoint was created in. | +| `resourceId` | string | The resource ID of the dataCollectionEndpoint. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.3.0` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/insights/data-collection-endpoint/main.bicep b/avm/1.1.0/res/insights/data-collection-endpoint/main.bicep new file mode 100644 index 000000000..4e2003b7c --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-endpoint/main.bicep @@ -0,0 +1,152 @@ +metadata name = 'Data Collection Endpoints' +metadata description = 'This module deploys a Data Collection Endpoint.' + +// ============== // +// Parameters // +// ============== // + +@sys.description('Required. The name of the data collection endpoint. The name is case insensitive.') +param name string + +@sys.description('Optional. Description of the data collection endpoint.') +param description string? + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@sys.description('Optional. The kind of the resource.') +@allowed([ + 'Linux' + 'Windows' +]) +param kind string = 'Linux' + +@sys.description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.3.0' +@sys.description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.3.0' +@sys.description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@sys.description('Optional. The configuration to set whether network access from public internet to the endpoints are allowed.') +@allowed([ + 'Enabled' + 'Disabled' + 'SecuredByPerimeter' +]) +param publicNetworkAccess string = 'Disabled' + +@sys.description('Optional. Resource tags.') +param tags object? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +// =============== // +// Deployments // +// =============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.insights-datacollectionendpoint.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource dataCollectionEndpoint 'Microsoft.Insights/dataCollectionEndpoints@2023-03-11' = { + kind: kind + location: location + name: name + tags: tags + properties: { + networkAcls: { + publicNetworkAccess: publicNetworkAccess + } + description: description + } +} + +resource dataCollectionEndpoint_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: dataCollectionEndpoint +} + +resource dataCollectionEndpoint_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + dataCollectionEndpoint.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: dataCollectionEndpoint + } +] + +// =========== // +// Outputs // +// =========== // + +@sys.description('The name of the dataCollectionEndpoint.') +output name string = dataCollectionEndpoint.name + +@sys.description('The resource ID of the dataCollectionEndpoint.') +output resourceId string = dataCollectionEndpoint.id + +@sys.description('The name of the resource group the dataCollectionEndpoint was created in.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The location the resource was deployed into.') +output location string = dataCollectionEndpoint.location diff --git a/avm/1.1.0/res/insights/data-collection-endpoint/main.json b/avm/1.1.0/res/insights/data-collection-endpoint/main.json new file mode 100644 index 000000000..ea1ba7661 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-endpoint/main.json @@ -0,0 +1,315 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "7213729546976713833" + }, + "name": "Data Collection Endpoints", + "description": "This module deploys a Data Collection Endpoint." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the data collection endpoint. The name is case insensitive." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection endpoint." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "kind": { + "type": "string", + "defaultValue": "Linux", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "Optional. The kind of the resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. The configuration to set whether network access from public internet to the endpoints are allowed." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-datacollectionendpoint.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "dataCollectionEndpoint": { + "type": "Microsoft.Insights/dataCollectionEndpoints", + "apiVersion": "2023-03-11", + "name": "[parameters('name')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "networkAcls": { + "publicNetworkAccess": "[parameters('publicNetworkAccess')]" + }, + "description": "[parameters('description')]" + } + }, + "dataCollectionEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Insights/dataCollectionEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "dataCollectionEndpoint" + ] + }, + "dataCollectionEndpoint_roleAssignments": { + "copy": { + "name": "dataCollectionEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/dataCollectionEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/dataCollectionEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "dataCollectionEndpoint" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the dataCollectionEndpoint." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dataCollectionEndpoint." + }, + "value": "[resourceId('Microsoft.Insights/dataCollectionEndpoints', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the dataCollectionEndpoint was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('dataCollectionEndpoint', '2023-03-11', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..81f6756b6 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,47 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.dataCollectionEndpoints-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idcemin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..a51da4e72 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created managed identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..20b770a8a --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/max/main.test.bicep @@ -0,0 +1,90 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.dataCollectionEndpoints-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idcemax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + description: 'This is a test data collection endpoint.' + location: resourceLocation + publicNetworkAccess: 'Enabled' + kind: 'Windows' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'db496446-89ac-4d91-a189-71544de0150a' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Data Collection Rules' + kind: 'Windows' + } + } + } +] diff --git a/avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..67b76b77d --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-endpoint/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,54 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.dataCollectionEndpoints-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idcewaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + publicNetworkAccess: 'Disabled' + kind: 'Windows' + tags: { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Data Collection Rules' + kind: 'Windows' + } + } + } +] diff --git a/avm/1.1.0/res/insights/data-collection-endpoint/version.json b/avm/1.1.0/res/insights/data-collection-endpoint/version.json new file mode 100644 index 000000000..ea4f3b6e6 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-endpoint/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/data-collection-rule/README.md b/avm/1.1.0/res/insights/data-collection-rule/README.md new file mode 100644 index 000000000..073628f6c --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/README.md @@ -0,0 +1,3036 @@ +# Data Collection Rules `[Microsoft.Insights/dataCollectionRules]` + +This module deploys a Data Collection Rule. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/dataCollectionRules` | [2023-03-11](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2023-03-11/dataCollectionRules) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/insights/data-collection-rule:`. + +- [Agent Settings](#example-1-agent-settings) +- [Collecting custom text logs with ingestion-time transformation](#example-2-collecting-custom-text-logs-with-ingestion-time-transformation) +- [Collecting custom text logs](#example-3-collecting-custom-text-logs) +- [Collecting IIS logs](#example-4-collecting-iis-logs) +- [Using only defaults](#example-5-using-only-defaults) +- [Collecting Linux-specific information](#example-6-collecting-linux-specific-information) +- [Using large parameter set](#example-7-using-large-parameter-set) +- [WAF-aligned](#example-8-waf-aligned) +- [Collecting Windows-specific information](#example-9-collecting-windows-specific-information) + +### Example 1: _Agent Settings_ + +This instance deploys the module AMA (Azure Monitor Agent) Settings DCR. + + +

+ +via Bicep module + +```bicep +module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:' = { + name: 'dataCollectionRuleDeployment' + params: { + // Required parameters + dataCollectionRuleProperties: { + agentSettings: { + logs: [ + { + name: 'MaxDiskQuotaInMB' + value: '5000' + } + ] + } + description: 'Agent Settings' + kind: 'AgentSettings' + } + name: 'idcrags001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataCollectionRuleProperties": { + "value": { + "agentSettings": { + "logs": [ + { + "name": "MaxDiskQuotaInMB", + "value": "5000" + } + ] + }, + "description": "Agent Settings", + "kind": "AgentSettings" + } + }, + "name": { + "value": "idcrags001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + agentSettings: { + logs: [ + { + name: 'MaxDiskQuotaInMB' + value: '5000' + } + ] + } + description: 'Agent Settings' + kind: 'AgentSettings' +} +param name = 'idcrags001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Collecting custom text logs with ingestion-time transformation_ + +This instance deploys the module to setup collection of custom logs and ingestion-time transformation. + + +

+ +via Bicep module + +```bicep +module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:' = { + name: 'dataCollectionRuleDeployment' + params: { + // Required parameters + dataCollectionRuleProperties: { + dataCollectionEndpointResourceId: '' + dataFlows: [ + { + destinations: [ + '' + ] + outputStream: 'Custom-CustomTableAdvanced_CL' + streams: [ + 'Custom-CustomTableAdvanced_CL' + ] + transformKql: 'source | extend LogFields = split(RawData, \',\') | extend EventTime = todatetime(LogFields[0]) | extend EventLevel = tostring(LogFields[1]) | extend EventCode = toint(LogFields[2]) | extend Message = tostring(LogFields[3]) | project TimeGenerated, EventTime, EventLevel, EventCode, Message' + } + ] + dataSources: { + logFiles: [ + { + filePatterns: [ + 'C:\\TestLogsAdvanced\\TestLog*.log' + ] + format: 'text' + name: 'CustomTableAdvanced_CL' + samplingFrequencyInSeconds: 60 + settings: { + text: { + recordStartTimestampFormat: 'ISO 8601' + } + } + streams: [ + 'Custom-CustomTableAdvanced_CL' + ] + } + ] + } + description: 'Collecting custom text logs with ingestion-time transformation to columns. Expected format of a log line (comma separated values): \',,,\', for example: \'2023-01-25T20:15:05Z,ERROR,404,Page not found\'' + destinations: { + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' + streamDeclarations: { + 'Custom-CustomTableAdvanced_CL': { + columns: [ + { + name: 'TimeGenerated' + type: 'datetime' + } + { + name: 'EventTime' + type: 'datetime' + } + { + name: 'EventLevel' + type: 'string' + } + { + name: 'EventCode' + type: 'int' + } + { + name: 'Message' + type: 'string' + } + { + name: 'RawData' + type: 'string' + } + ] + } + } + } + name: 'idcrcusadv001' + // Non-required parameters + location: '' + managedIdentities: { + systemAssigned: true + } + tags: { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataCollectionRuleProperties": { + "value": { + "dataCollectionEndpointResourceId": "", + "dataFlows": [ + { + "destinations": [ + "" + ], + "outputStream": "Custom-CustomTableAdvanced_CL", + "streams": [ + "Custom-CustomTableAdvanced_CL" + ], + "transformKql": "source | extend LogFields = split(RawData, \",\") | extend EventTime = todatetime(LogFields[0]) | extend EventLevel = tostring(LogFields[1]) | extend EventCode = toint(LogFields[2]) | extend Message = tostring(LogFields[3]) | project TimeGenerated, EventTime, EventLevel, EventCode, Message" + } + ], + "dataSources": { + "logFiles": [ + { + "filePatterns": [ + "C:\\TestLogsAdvanced\\TestLog*.log" + ], + "format": "text", + "name": "CustomTableAdvanced_CL", + "samplingFrequencyInSeconds": 60, + "settings": { + "text": { + "recordStartTimestampFormat": "ISO 8601" + } + }, + "streams": [ + "Custom-CustomTableAdvanced_CL" + ] + } + ] + }, + "description": "Collecting custom text logs with ingestion-time transformation to columns. Expected format of a log line (comma separated values): \",,,\", for example: \"2023-01-25T20:15:05Z,ERROR,404,Page not found\"", + "destinations": { + "logAnalytics": [ + { + "name": "", + "workspaceResourceId": "" + } + ] + }, + "kind": "Windows", + "streamDeclarations": { + "Custom-CustomTableAdvanced_CL": { + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "EventTime", + "type": "datetime" + }, + { + "name": "EventLevel", + "type": "string" + }, + { + "name": "EventCode", + "type": "int" + }, + { + "name": "Message", + "type": "string" + }, + { + "name": "RawData", + "type": "string" + } + ] + } + } + } + }, + "name": { + "value": "idcrcusadv001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name", + "kind": "Windows", + "resourceType": "Data Collection Rules" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataCollectionEndpointResourceId: '' + dataFlows: [ + { + destinations: [ + '' + ] + outputStream: 'Custom-CustomTableAdvanced_CL' + streams: [ + 'Custom-CustomTableAdvanced_CL' + ] + transformKql: 'source | extend LogFields = split(RawData, \',\') | extend EventTime = todatetime(LogFields[0]) | extend EventLevel = tostring(LogFields[1]) | extend EventCode = toint(LogFields[2]) | extend Message = tostring(LogFields[3]) | project TimeGenerated, EventTime, EventLevel, EventCode, Message' + } + ] + dataSources: { + logFiles: [ + { + filePatterns: [ + 'C:\\TestLogsAdvanced\\TestLog*.log' + ] + format: 'text' + name: 'CustomTableAdvanced_CL' + samplingFrequencyInSeconds: 60 + settings: { + text: { + recordStartTimestampFormat: 'ISO 8601' + } + } + streams: [ + 'Custom-CustomTableAdvanced_CL' + ] + } + ] + } + description: 'Collecting custom text logs with ingestion-time transformation to columns. Expected format of a log line (comma separated values): \',,,\', for example: \'2023-01-25T20:15:05Z,ERROR,404,Page not found\'' + destinations: { + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' + streamDeclarations: { + 'Custom-CustomTableAdvanced_CL': { + columns: [ + { + name: 'TimeGenerated' + type: 'datetime' + } + { + name: 'EventTime' + type: 'datetime' + } + { + name: 'EventLevel' + type: 'string' + } + { + name: 'EventCode' + type: 'int' + } + { + name: 'Message' + type: 'string' + } + { + name: 'RawData' + type: 'string' + } + ] + } + } +} +param name = 'idcrcusadv001' +// Non-required parameters +param location = '' +param managedIdentities = { + systemAssigned: true +} +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
+

+ +### Example 3: _Collecting custom text logs_ + +This instance deploys the module to setup collection of custom logs. + + +

+ +via Bicep module + +```bicep +module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:' = { + name: 'dataCollectionRuleDeployment' + params: { + // Required parameters + dataCollectionRuleProperties: { + dataCollectionEndpointResourceId: '' + dataFlows: [ + { + destinations: [ + '' + ] + outputStream: 'Custom-CustomTableBasic_CL' + streams: [ + 'Custom-CustomTableBasic_CL' + ] + transformKql: 'source' + } + ] + dataSources: { + logFiles: [ + { + filePatterns: [ + 'C:\\TestLogsBasic\\TestLog*.log' + ] + format: 'text' + name: 'CustomTableBasic_CL' + samplingFrequencyInSeconds: 60 + settings: { + text: { + recordStartTimestampFormat: 'ISO 8601' + } + } + streams: [ + 'Custom-CustomTableBasic_CL' + ] + } + ] + } + description: 'Collecting custom text logs without ingestion-time transformation.' + destinations: { + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'All' + streamDeclarations: { + 'Custom-CustomTableBasic_CL': { + columns: [ + { + name: 'TimeGenerated' + type: 'datetime' + } + { + name: 'RawData' + type: 'string' + } + ] + } + } + } + name: 'idcrcusbas001' + // Non-required parameters + location: '' + tags: { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataCollectionRuleProperties": { + "value": { + "dataCollectionEndpointResourceId": "", + "dataFlows": [ + { + "destinations": [ + "" + ], + "outputStream": "Custom-CustomTableBasic_CL", + "streams": [ + "Custom-CustomTableBasic_CL" + ], + "transformKql": "source" + } + ], + "dataSources": { + "logFiles": [ + { + "filePatterns": [ + "C:\\TestLogsBasic\\TestLog*.log" + ], + "format": "text", + "name": "CustomTableBasic_CL", + "samplingFrequencyInSeconds": 60, + "settings": { + "text": { + "recordStartTimestampFormat": "ISO 8601" + } + }, + "streams": [ + "Custom-CustomTableBasic_CL" + ] + } + ] + }, + "description": "Collecting custom text logs without ingestion-time transformation.", + "destinations": { + "logAnalytics": [ + { + "name": "", + "workspaceResourceId": "" + } + ] + }, + "kind": "All", + "streamDeclarations": { + "Custom-CustomTableBasic_CL": { + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "RawData", + "type": "string" + } + ] + } + } + } + }, + "name": { + "value": "idcrcusbas001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name", + "kind": "Windows", + "resourceType": "Data Collection Rules" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataCollectionEndpointResourceId: '' + dataFlows: [ + { + destinations: [ + '' + ] + outputStream: 'Custom-CustomTableBasic_CL' + streams: [ + 'Custom-CustomTableBasic_CL' + ] + transformKql: 'source' + } + ] + dataSources: { + logFiles: [ + { + filePatterns: [ + 'C:\\TestLogsBasic\\TestLog*.log' + ] + format: 'text' + name: 'CustomTableBasic_CL' + samplingFrequencyInSeconds: 60 + settings: { + text: { + recordStartTimestampFormat: 'ISO 8601' + } + } + streams: [ + 'Custom-CustomTableBasic_CL' + ] + } + ] + } + description: 'Collecting custom text logs without ingestion-time transformation.' + destinations: { + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'All' + streamDeclarations: { + 'Custom-CustomTableBasic_CL': { + columns: [ + { + name: 'TimeGenerated' + type: 'datetime' + } + { + name: 'RawData' + type: 'string' + } + ] + } + } +} +param name = 'idcrcusbas001' +// Non-required parameters +param location = '' +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
+

+ +### Example 4: _Collecting IIS logs_ + +This instance deploys the module to setup the collection of IIS logs. + + +

+ +via Bicep module + +```bicep +module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:' = { + name: 'dataCollectionRuleDeployment' + params: { + // Required parameters + dataCollectionRuleProperties: { + dataCollectionEndpointResourceId: '' + dataFlows: [ + { + destinations: [ + '' + ] + outputStream: 'Microsoft-W3CIISLog' + streams: [ + 'Microsoft-W3CIISLog' + ] + transformKql: 'source' + } + ] + dataSources: { + iisLogs: [ + { + logDirectories: [ + 'C:\\inetpub\\logs\\LogFiles\\W3SVC1' + ] + name: 'iisLogsDataSource' + streams: [ + 'Microsoft-W3CIISLog' + ] + } + ] + } + description: 'Collecting IIS logs.' + destinations: { + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' + } + name: 'idcrcusiis001' + // Non-required parameters + location: '' + tags: { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataCollectionRuleProperties": { + "value": { + "dataCollectionEndpointResourceId": "", + "dataFlows": [ + { + "destinations": [ + "" + ], + "outputStream": "Microsoft-W3CIISLog", + "streams": [ + "Microsoft-W3CIISLog" + ], + "transformKql": "source" + } + ], + "dataSources": { + "iisLogs": [ + { + "logDirectories": [ + "C:\\inetpub\\logs\\LogFiles\\W3SVC1" + ], + "name": "iisLogsDataSource", + "streams": [ + "Microsoft-W3CIISLog" + ] + } + ] + }, + "description": "Collecting IIS logs.", + "destinations": { + "logAnalytics": [ + { + "name": "", + "workspaceResourceId": "" + } + ] + }, + "kind": "Windows" + } + }, + "name": { + "value": "idcrcusiis001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name", + "kind": "Windows", + "resourceType": "Data Collection Rules" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataCollectionEndpointResourceId: '' + dataFlows: [ + { + destinations: [ + '' + ] + outputStream: 'Microsoft-W3CIISLog' + streams: [ + 'Microsoft-W3CIISLog' + ] + transformKql: 'source' + } + ] + dataSources: { + iisLogs: [ + { + logDirectories: [ + 'C:\\inetpub\\logs\\LogFiles\\W3SVC1' + ] + name: 'iisLogsDataSource' + streams: [ + 'Microsoft-W3CIISLog' + ] + } + ] + } + description: 'Collecting IIS logs.' + destinations: { + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' +} +param name = 'idcrcusiis001' +// Non-required parameters +param location = '' +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
+

+ +### Example 5: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:' = { + name: 'dataCollectionRuleDeployment' + params: { + // Required parameters + dataCollectionRuleProperties: { + dataFlows: [ + { + destinations: [ + 'azureMonitorMetrics-default' + ] + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + dataSources: { + performanceCounters: [ + { + counterSpecifiers: [ + '\\Process(_Total)\\Handle Count' + '\\Process(_Total)\\Thread Count' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Context Switches/sec' + '\\System\\Processes' + '\\System\\Processor Queue Length' + '\\System\\System Up Time' + ] + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + } + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + } + kind: 'Windows' + } + name: 'idcrmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataCollectionRuleProperties": { + "value": { + "dataFlows": [ + { + "destinations": [ + "azureMonitorMetrics-default" + ], + "streams": [ + "Microsoft-InsightsMetrics" + ] + } + ], + "dataSources": { + "performanceCounters": [ + { + "counterSpecifiers": [ + "\\Process(_Total)\\Handle Count", + "\\Process(_Total)\\Thread Count", + "\\Processor Information(_Total)\\% Privileged Time", + "\\Processor Information(_Total)\\% Processor Time", + "\\Processor Information(_Total)\\% User Time", + "\\Processor Information(_Total)\\Processor Frequency", + "\\System\\Context Switches/sec", + "\\System\\Processes", + "\\System\\Processor Queue Length", + "\\System\\System Up Time" + ], + "name": "perfCounterDataSource60", + "samplingFrequencyInSeconds": 60, + "streams": [ + "Microsoft-InsightsMetrics" + ] + } + ] + }, + "destinations": { + "azureMonitorMetrics": { + "name": "azureMonitorMetrics-default" + } + }, + "kind": "Windows" + } + }, + "name": { + "value": "idcrmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataFlows: [ + { + destinations: [ + 'azureMonitorMetrics-default' + ] + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + dataSources: { + performanceCounters: [ + { + counterSpecifiers: [ + '\\Process(_Total)\\Handle Count' + '\\Process(_Total)\\Thread Count' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Context Switches/sec' + '\\System\\Processes' + '\\System\\Processor Queue Length' + '\\System\\System Up Time' + ] + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + } + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + } + kind: 'Windows' +} +param name = 'idcrmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 6: _Collecting Linux-specific information_ + +This instance deploys the module to setup the collection of Linux-specific performance counters and Linux Syslog. + + +

+ +via Bicep module + +```bicep +module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:' = { + name: 'dataCollectionRuleDeployment' + params: { + // Required parameters + dataCollectionRuleProperties: { + dataFlows: [ + { + destinations: [ + 'azureMonitorMetrics-default' + ] + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + { + destinations: [ + '' + ] + streams: [ + 'Microsoft-Syslog' + ] + } + ] + dataSources: { + performanceCounters: [ + { + counterSpecifiers: [ + 'Logical Disk(*)\\% Free Inodes' + 'Logical Disk(*)\\% Free Space' + 'Logical Disk(*)\\% Used Inodes' + 'Logical Disk(*)\\% Used Space' + 'Logical Disk(*)\\Disk Read Bytes/sec' + 'Logical Disk(*)\\Disk Reads/sec' + 'Logical Disk(*)\\Disk Transfers/sec' + 'Logical Disk(*)\\Disk Write Bytes/sec' + 'Logical Disk(*)\\Disk Writes/sec' + 'Logical Disk(*)\\Free Megabytes' + 'Logical Disk(*)\\Logical Disk Bytes/sec' + 'Memory(*)\\% Available Memory' + 'Memory(*)\\% Available Swap Space' + 'Memory(*)\\% Used Memory' + 'Memory(*)\\% Used Swap Space' + 'Memory(*)\\Available MBytes Memory' + 'Memory(*)\\Available MBytes Swap' + 'Memory(*)\\Page Reads/sec' + 'Memory(*)\\Page Writes/sec' + 'Memory(*)\\Pages/sec' + 'Memory(*)\\Used MBytes Swap Space' + 'Memory(*)\\Used Memory MBytes' + 'Network(*)\\Total Bytes' + 'Network(*)\\Total Bytes Received' + 'Network(*)\\Total Bytes Transmitted' + 'Network(*)\\Total Collisions' + 'Network(*)\\Total Packets Received' + 'Network(*)\\Total Packets Transmitted' + 'Network(*)\\Total Rx Errors' + 'Network(*)\\Total Tx Errors' + 'Processor(*)\\% DPC Time' + 'Processor(*)\\% Idle Time' + 'Processor(*)\\% Interrupt Time' + 'Processor(*)\\% IO Wait Time' + 'Processor(*)\\% Nice Time' + 'Processor(*)\\% Privileged Time' + 'Processor(*)\\% Processor Time' + 'Processor(*)\\% User Time' + ] + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + syslog: [ + { + facilityNames: [ + 'auth' + 'authpriv' + ] + logLevels: [ + 'Alert' + 'Critical' + 'Debug' + 'Emergency' + 'Error' + 'Info' + 'Notice' + 'Warning' + ] + name: 'sysLogsDataSource-debugLevel' + streams: [ + 'Microsoft-Syslog' + ] + } + { + facilityNames: [ + 'cron' + 'daemon' + 'kern' + 'local0' + 'mark' + ] + logLevels: [ + 'Alert' + 'Critical' + 'Emergency' + 'Error' + 'Warning' + ] + name: 'sysLogsDataSource-warningLevel' + streams: [ + 'Microsoft-Syslog' + ] + } + { + facilityNames: [ + 'local1' + 'local2' + 'local3' + 'local4' + 'local5' + 'local6' + 'local7' + 'lpr' + 'mail' + 'news' + 'syslog' + ] + logLevels: [ + 'Alert' + 'Critical' + 'Emergency' + 'Error' + ] + name: 'sysLogsDataSource-errLevel' + streams: [ + 'Microsoft-Syslog' + ] + } + ] + } + description: 'Collecting Linux-specific performance counters and Linux Syslog' + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Linux' + } + name: 'idcrlin001' + // Non-required parameters + location: '' + tags: { + 'hidden-title': 'This is visible in the resource name' + kind: 'Linux' + resourceType: 'Data Collection Rules' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataCollectionRuleProperties": { + "value": { + "dataFlows": [ + { + "destinations": [ + "azureMonitorMetrics-default" + ], + "streams": [ + "Microsoft-InsightsMetrics" + ] + }, + { + "destinations": [ + "" + ], + "streams": [ + "Microsoft-Syslog" + ] + } + ], + "dataSources": { + "performanceCounters": [ + { + "counterSpecifiers": [ + "Logical Disk(*)\\% Free Inodes", + "Logical Disk(*)\\% Free Space", + "Logical Disk(*)\\% Used Inodes", + "Logical Disk(*)\\% Used Space", + "Logical Disk(*)\\Disk Read Bytes/sec", + "Logical Disk(*)\\Disk Reads/sec", + "Logical Disk(*)\\Disk Transfers/sec", + "Logical Disk(*)\\Disk Write Bytes/sec", + "Logical Disk(*)\\Disk Writes/sec", + "Logical Disk(*)\\Free Megabytes", + "Logical Disk(*)\\Logical Disk Bytes/sec", + "Memory(*)\\% Available Memory", + "Memory(*)\\% Available Swap Space", + "Memory(*)\\% Used Memory", + "Memory(*)\\% Used Swap Space", + "Memory(*)\\Available MBytes Memory", + "Memory(*)\\Available MBytes Swap", + "Memory(*)\\Page Reads/sec", + "Memory(*)\\Page Writes/sec", + "Memory(*)\\Pages/sec", + "Memory(*)\\Used MBytes Swap Space", + "Memory(*)\\Used Memory MBytes", + "Network(*)\\Total Bytes", + "Network(*)\\Total Bytes Received", + "Network(*)\\Total Bytes Transmitted", + "Network(*)\\Total Collisions", + "Network(*)\\Total Packets Received", + "Network(*)\\Total Packets Transmitted", + "Network(*)\\Total Rx Errors", + "Network(*)\\Total Tx Errors", + "Processor(*)\\% DPC Time", + "Processor(*)\\% Idle Time", + "Processor(*)\\% Interrupt Time", + "Processor(*)\\% IO Wait Time", + "Processor(*)\\% Nice Time", + "Processor(*)\\% Privileged Time", + "Processor(*)\\% Processor Time", + "Processor(*)\\% User Time" + ], + "name": "perfCounterDataSource60", + "samplingFrequencyInSeconds": 60, + "streams": [ + "Microsoft-InsightsMetrics" + ] + } + ], + "syslog": [ + { + "facilityNames": [ + "auth", + "authpriv" + ], + "logLevels": [ + "Alert", + "Critical", + "Debug", + "Emergency", + "Error", + "Info", + "Notice", + "Warning" + ], + "name": "sysLogsDataSource-debugLevel", + "streams": [ + "Microsoft-Syslog" + ] + }, + { + "facilityNames": [ + "cron", + "daemon", + "kern", + "local0", + "mark" + ], + "logLevels": [ + "Alert", + "Critical", + "Emergency", + "Error", + "Warning" + ], + "name": "sysLogsDataSource-warningLevel", + "streams": [ + "Microsoft-Syslog" + ] + }, + { + "facilityNames": [ + "local1", + "local2", + "local3", + "local4", + "local5", + "local6", + "local7", + "lpr", + "mail", + "news", + "syslog" + ], + "logLevels": [ + "Alert", + "Critical", + "Emergency", + "Error" + ], + "name": "sysLogsDataSource-errLevel", + "streams": [ + "Microsoft-Syslog" + ] + } + ] + }, + "description": "Collecting Linux-specific performance counters and Linux Syslog", + "destinations": { + "azureMonitorMetrics": { + "name": "azureMonitorMetrics-default" + }, + "logAnalytics": [ + { + "name": "", + "workspaceResourceId": "" + } + ] + }, + "kind": "Linux" + } + }, + "name": { + "value": "idcrlin001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name", + "kind": "Linux", + "resourceType": "Data Collection Rules" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataFlows: [ + { + destinations: [ + 'azureMonitorMetrics-default' + ] + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + { + destinations: [ + '' + ] + streams: [ + 'Microsoft-Syslog' + ] + } + ] + dataSources: { + performanceCounters: [ + { + counterSpecifiers: [ + 'Logical Disk(*)\\% Free Inodes' + 'Logical Disk(*)\\% Free Space' + 'Logical Disk(*)\\% Used Inodes' + 'Logical Disk(*)\\% Used Space' + 'Logical Disk(*)\\Disk Read Bytes/sec' + 'Logical Disk(*)\\Disk Reads/sec' + 'Logical Disk(*)\\Disk Transfers/sec' + 'Logical Disk(*)\\Disk Write Bytes/sec' + 'Logical Disk(*)\\Disk Writes/sec' + 'Logical Disk(*)\\Free Megabytes' + 'Logical Disk(*)\\Logical Disk Bytes/sec' + 'Memory(*)\\% Available Memory' + 'Memory(*)\\% Available Swap Space' + 'Memory(*)\\% Used Memory' + 'Memory(*)\\% Used Swap Space' + 'Memory(*)\\Available MBytes Memory' + 'Memory(*)\\Available MBytes Swap' + 'Memory(*)\\Page Reads/sec' + 'Memory(*)\\Page Writes/sec' + 'Memory(*)\\Pages/sec' + 'Memory(*)\\Used MBytes Swap Space' + 'Memory(*)\\Used Memory MBytes' + 'Network(*)\\Total Bytes' + 'Network(*)\\Total Bytes Received' + 'Network(*)\\Total Bytes Transmitted' + 'Network(*)\\Total Collisions' + 'Network(*)\\Total Packets Received' + 'Network(*)\\Total Packets Transmitted' + 'Network(*)\\Total Rx Errors' + 'Network(*)\\Total Tx Errors' + 'Processor(*)\\% DPC Time' + 'Processor(*)\\% Idle Time' + 'Processor(*)\\% Interrupt Time' + 'Processor(*)\\% IO Wait Time' + 'Processor(*)\\% Nice Time' + 'Processor(*)\\% Privileged Time' + 'Processor(*)\\% Processor Time' + 'Processor(*)\\% User Time' + ] + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + syslog: [ + { + facilityNames: [ + 'auth' + 'authpriv' + ] + logLevels: [ + 'Alert' + 'Critical' + 'Debug' + 'Emergency' + 'Error' + 'Info' + 'Notice' + 'Warning' + ] + name: 'sysLogsDataSource-debugLevel' + streams: [ + 'Microsoft-Syslog' + ] + } + { + facilityNames: [ + 'cron' + 'daemon' + 'kern' + 'local0' + 'mark' + ] + logLevels: [ + 'Alert' + 'Critical' + 'Emergency' + 'Error' + 'Warning' + ] + name: 'sysLogsDataSource-warningLevel' + streams: [ + 'Microsoft-Syslog' + ] + } + { + facilityNames: [ + 'local1' + 'local2' + 'local3' + 'local4' + 'local5' + 'local6' + 'local7' + 'lpr' + 'mail' + 'news' + 'syslog' + ] + logLevels: [ + 'Alert' + 'Critical' + 'Emergency' + 'Error' + ] + name: 'sysLogsDataSource-errLevel' + streams: [ + 'Microsoft-Syslog' + ] + } + ] + } + description: 'Collecting Linux-specific performance counters and Linux Syslog' + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Linux' +} +param name = 'idcrlin001' +// Non-required parameters +param location = '' +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Linux' + resourceType: 'Data Collection Rules' +} +``` + +
+

+ +### Example 7: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:' = { + name: 'dataCollectionRuleDeployment' + params: { + // Required parameters + dataCollectionRuleProperties: { + dataCollectionEndpointResourceId: '' + dataFlows: [ + { + destinations: [ + '' + ] + outputStream: 'Custom-CustomTableBasic_CL' + streams: [ + 'Custom-CustomTableBasic_CL' + ] + transformKql: 'source' + } + ] + dataSources: { + logFiles: [ + { + filePatterns: [ + 'C:\\TestLogsBasic\\TestLog*.log' + ] + format: 'text' + name: 'CustomTableBasic_CL' + samplingFrequencyInSeconds: 60 + settings: { + text: { + recordStartTimestampFormat: 'ISO 8601' + } + } + streams: [ + 'Custom-CustomTableBasic_CL' + ] + } + ] + } + description: 'Collecting custom text logs without ingestion-time transformation.' + destinations: { + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' + streamDeclarations: { + 'Custom-CustomTableBasic_CL': { + columns: [ + { + name: 'TimeGenerated' + type: 'datetime' + } + { + name: 'RawData' + type: 'string' + } + ] + } + } + } + name: 'idcrmax001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] + } + roleAssignments: [ + { + name: '89a4d6fa-defb-4099-9196-173d94b91d67' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataCollectionRuleProperties": { + "value": { + "dataCollectionEndpointResourceId": "", + "dataFlows": [ + { + "destinations": [ + "" + ], + "outputStream": "Custom-CustomTableBasic_CL", + "streams": [ + "Custom-CustomTableBasic_CL" + ], + "transformKql": "source" + } + ], + "dataSources": { + "logFiles": [ + { + "filePatterns": [ + "C:\\TestLogsBasic\\TestLog*.log" + ], + "format": "text", + "name": "CustomTableBasic_CL", + "samplingFrequencyInSeconds": 60, + "settings": { + "text": { + "recordStartTimestampFormat": "ISO 8601" + } + }, + "streams": [ + "Custom-CustomTableBasic_CL" + ] + } + ] + }, + "description": "Collecting custom text logs without ingestion-time transformation.", + "destinations": { + "logAnalytics": [ + { + "name": "", + "workspaceResourceId": "" + } + ] + }, + "kind": "Windows", + "streamDeclarations": { + "Custom-CustomTableBasic_CL": { + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "RawData", + "type": "string" + } + ] + } + } + } + }, + "name": { + "value": "idcrmax001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "systemAssigned": false, + "userAssignedResourceIds": [ + "" + ] + } + }, + "roleAssignments": { + "value": [ + { + "name": "89a4d6fa-defb-4099-9196-173d94b91d67", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name", + "kind": "Windows", + "resourceType": "Data Collection Rules" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataCollectionEndpointResourceId: '' + dataFlows: [ + { + destinations: [ + '' + ] + outputStream: 'Custom-CustomTableBasic_CL' + streams: [ + 'Custom-CustomTableBasic_CL' + ] + transformKql: 'source' + } + ] + dataSources: { + logFiles: [ + { + filePatterns: [ + 'C:\\TestLogsBasic\\TestLog*.log' + ] + format: 'text' + name: 'CustomTableBasic_CL' + samplingFrequencyInSeconds: 60 + settings: { + text: { + recordStartTimestampFormat: 'ISO 8601' + } + } + streams: [ + 'Custom-CustomTableBasic_CL' + ] + } + ] + } + description: 'Collecting custom text logs without ingestion-time transformation.' + destinations: { + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' + streamDeclarations: { + 'Custom-CustomTableBasic_CL': { + columns: [ + { + name: 'TimeGenerated' + type: 'datetime' + } + { + name: 'RawData' + type: 'string' + } + ] + } + } +} +param name = 'idcrmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: '89a4d6fa-defb-4099-9196-173d94b91d67' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
+

+ +### Example 8: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:' = { + name: 'dataCollectionRuleDeployment' + params: { + // Required parameters + dataCollectionRuleProperties: { + dataFlows: [ + { + destinations: [ + 'azureMonitorMetrics-default' + ] + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + { + destinations: [ + '' + ] + streams: [ + 'Microsoft-Event' + ] + } + ] + dataSources: { + performanceCounters: [ + { + counterSpecifiers: [ + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Page Faults/sec' + '\\Memory\\Pages/sec' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Process(_Total)\\Handle Count' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Context Switches/sec' + '\\System\\Processes' + '\\System\\Processor Queue Length' + '\\System\\System Up Time' + ] + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + windowsEventLogs: [ + { + name: 'eventLogsDataSource' + streams: [ + 'Microsoft-Event' + ] + xPathQueries: [ + 'Application!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + 'Security!*[System[(band(Keywords,13510798882111488))]]' + 'System!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + ] + } + ] + } + description: 'Collecting Windows-specific performance counters and Windows Event Logs' + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' + } + name: 'idcrwaf001' + // Non-required parameters + location: '' + tags: { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataCollectionRuleProperties": { + "value": { + "dataFlows": [ + { + "destinations": [ + "azureMonitorMetrics-default" + ], + "streams": [ + "Microsoft-InsightsMetrics" + ] + }, + { + "destinations": [ + "" + ], + "streams": [ + "Microsoft-Event" + ] + } + ], + "dataSources": { + "performanceCounters": [ + { + "counterSpecifiers": [ + "\\LogicalDisk(_Total)\\% Disk Read Time", + "\\LogicalDisk(_Total)\\% Disk Time", + "\\LogicalDisk(_Total)\\% Disk Write Time", + "\\LogicalDisk(_Total)\\% Free Space", + "\\LogicalDisk(_Total)\\% Idle Time", + "\\LogicalDisk(_Total)\\Avg. Disk Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Read", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Write", + "\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length", + "\\LogicalDisk(_Total)\\Disk Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Read Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Reads/sec", + "\\LogicalDisk(_Total)\\Disk Transfers/sec", + "\\LogicalDisk(_Total)\\Disk Write Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Writes/sec", + "\\LogicalDisk(_Total)\\Free Megabytes", + "\\Memory\\% Committed Bytes In Use", + "\\Memory\\Available Bytes", + "\\Memory\\Cache Bytes", + "\\Memory\\Committed Bytes", + "\\Memory\\Page Faults/sec", + "\\Memory\\Pages/sec", + "\\Memory\\Pool Nonpaged Bytes", + "\\Memory\\Pool Paged Bytes", + "\\Network Interface(*)\\Bytes Received/sec", + "\\Network Interface(*)\\Bytes Sent/sec", + "\\Network Interface(*)\\Bytes Total/sec", + "\\Network Interface(*)\\Packets Outbound Errors", + "\\Network Interface(*)\\Packets Received Errors", + "\\Network Interface(*)\\Packets Received/sec", + "\\Network Interface(*)\\Packets Sent/sec", + "\\Network Interface(*)\\Packets/sec", + "\\Process(_Total)\\Handle Count", + "\\Process(_Total)\\Thread Count", + "\\Process(_Total)\\Working Set", + "\\Process(_Total)\\Working Set - Private", + "\\Processor Information(_Total)\\% Privileged Time", + "\\Processor Information(_Total)\\% Processor Time", + "\\Processor Information(_Total)\\% User Time", + "\\Processor Information(_Total)\\Processor Frequency", + "\\System\\Context Switches/sec", + "\\System\\Processes", + "\\System\\Processor Queue Length", + "\\System\\System Up Time" + ], + "name": "perfCounterDataSource60", + "samplingFrequencyInSeconds": 60, + "streams": [ + "Microsoft-InsightsMetrics" + ] + } + ], + "windowsEventLogs": [ + { + "name": "eventLogsDataSource", + "streams": [ + "Microsoft-Event" + ], + "xPathQueries": [ + "Application!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]", + "Security!*[System[(band(Keywords,13510798882111488))]]", + "System!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]" + ] + } + ] + }, + "description": "Collecting Windows-specific performance counters and Windows Event Logs", + "destinations": { + "azureMonitorMetrics": { + "name": "azureMonitorMetrics-default" + }, + "logAnalytics": [ + { + "name": "", + "workspaceResourceId": "" + } + ] + }, + "kind": "Windows" + } + }, + "name": { + "value": "idcrwaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name", + "kind": "Windows", + "resourceType": "Data Collection Rules" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataFlows: [ + { + destinations: [ + 'azureMonitorMetrics-default' + ] + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + { + destinations: [ + '' + ] + streams: [ + 'Microsoft-Event' + ] + } + ] + dataSources: { + performanceCounters: [ + { + counterSpecifiers: [ + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Page Faults/sec' + '\\Memory\\Pages/sec' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Process(_Total)\\Handle Count' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Context Switches/sec' + '\\System\\Processes' + '\\System\\Processor Queue Length' + '\\System\\System Up Time' + ] + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + windowsEventLogs: [ + { + name: 'eventLogsDataSource' + streams: [ + 'Microsoft-Event' + ] + xPathQueries: [ + 'Application!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + 'Security!*[System[(band(Keywords,13510798882111488))]]' + 'System!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + ] + } + ] + } + description: 'Collecting Windows-specific performance counters and Windows Event Logs' + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' +} +param name = 'idcrwaf001' +// Non-required parameters +param location = '' +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
+

+ +### Example 9: _Collecting Windows-specific information_ + +This instance deploys the module to setup the connection of Windows-specific performance counters and Windows Event Logs. + + +

+ +via Bicep module + +```bicep +module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:' = { + name: 'dataCollectionRuleDeployment' + params: { + // Required parameters + dataCollectionRuleProperties: { + dataFlows: [ + { + destinations: [ + 'azureMonitorMetrics-default' + ] + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + { + destinations: [ + '' + ] + streams: [ + 'Microsoft-Event' + ] + } + ] + dataSources: { + performanceCounters: [ + { + counterSpecifiers: [ + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Page Faults/sec' + '\\Memory\\Pages/sec' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Process(_Total)\\Handle Count' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Context Switches/sec' + '\\System\\Processes' + '\\System\\Processor Queue Length' + '\\System\\System Up Time' + ] + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + windowsEventLogs: [ + { + name: 'eventLogsDataSource' + streams: [ + 'Microsoft-Event' + ] + xPathQueries: [ + 'Application!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + 'Security!*[System[(band(Keywords,13510798882111488))]]' + 'System!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + ] + } + ] + } + description: 'Collecting Windows-specific performance counters and Windows Event Logs' + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' + } + name: 'idcrwin001' + // Non-required parameters + location: '' + tags: { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dataCollectionRuleProperties": { + "value": { + "dataFlows": [ + { + "destinations": [ + "azureMonitorMetrics-default" + ], + "streams": [ + "Microsoft-InsightsMetrics" + ] + }, + { + "destinations": [ + "" + ], + "streams": [ + "Microsoft-Event" + ] + } + ], + "dataSources": { + "performanceCounters": [ + { + "counterSpecifiers": [ + "\\LogicalDisk(_Total)\\% Disk Read Time", + "\\LogicalDisk(_Total)\\% Disk Time", + "\\LogicalDisk(_Total)\\% Disk Write Time", + "\\LogicalDisk(_Total)\\% Free Space", + "\\LogicalDisk(_Total)\\% Idle Time", + "\\LogicalDisk(_Total)\\Avg. Disk Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Read", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer", + "\\LogicalDisk(_Total)\\Avg. Disk sec/Write", + "\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length", + "\\LogicalDisk(_Total)\\Disk Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Read Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Reads/sec", + "\\LogicalDisk(_Total)\\Disk Transfers/sec", + "\\LogicalDisk(_Total)\\Disk Write Bytes/sec", + "\\LogicalDisk(_Total)\\Disk Writes/sec", + "\\LogicalDisk(_Total)\\Free Megabytes", + "\\Memory\\% Committed Bytes In Use", + "\\Memory\\Available Bytes", + "\\Memory\\Cache Bytes", + "\\Memory\\Committed Bytes", + "\\Memory\\Page Faults/sec", + "\\Memory\\Pages/sec", + "\\Memory\\Pool Nonpaged Bytes", + "\\Memory\\Pool Paged Bytes", + "\\Network Interface(*)\\Bytes Received/sec", + "\\Network Interface(*)\\Bytes Sent/sec", + "\\Network Interface(*)\\Bytes Total/sec", + "\\Network Interface(*)\\Packets Outbound Errors", + "\\Network Interface(*)\\Packets Received Errors", + "\\Network Interface(*)\\Packets Received/sec", + "\\Network Interface(*)\\Packets Sent/sec", + "\\Network Interface(*)\\Packets/sec", + "\\Process(_Total)\\Handle Count", + "\\Process(_Total)\\Thread Count", + "\\Process(_Total)\\Working Set", + "\\Process(_Total)\\Working Set - Private", + "\\Processor Information(_Total)\\% Privileged Time", + "\\Processor Information(_Total)\\% Processor Time", + "\\Processor Information(_Total)\\% User Time", + "\\Processor Information(_Total)\\Processor Frequency", + "\\System\\Context Switches/sec", + "\\System\\Processes", + "\\System\\Processor Queue Length", + "\\System\\System Up Time" + ], + "name": "perfCounterDataSource60", + "samplingFrequencyInSeconds": 60, + "streams": [ + "Microsoft-InsightsMetrics" + ] + } + ], + "windowsEventLogs": [ + { + "name": "eventLogsDataSource", + "streams": [ + "Microsoft-Event" + ], + "xPathQueries": [ + "Application!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]", + "Security!*[System[(band(Keywords,13510798882111488))]]", + "System!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]" + ] + } + ] + }, + "description": "Collecting Windows-specific performance counters and Windows Event Logs", + "destinations": { + "azureMonitorMetrics": { + "name": "azureMonitorMetrics-default" + }, + "logAnalytics": [ + { + "name": "", + "workspaceResourceId": "" + } + ] + }, + "kind": "Windows" + } + }, + "name": { + "value": "idcrwin001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name", + "kind": "Windows", + "resourceType": "Data Collection Rules" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataFlows: [ + { + destinations: [ + 'azureMonitorMetrics-default' + ] + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + { + destinations: [ + '' + ] + streams: [ + 'Microsoft-Event' + ] + } + ] + dataSources: { + performanceCounters: [ + { + counterSpecifiers: [ + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Page Faults/sec' + '\\Memory\\Pages/sec' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Process(_Total)\\Handle Count' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Context Switches/sec' + '\\System\\Processes' + '\\System\\Processor Queue Length' + '\\System\\System Up Time' + ] + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + windowsEventLogs: [ + { + name: 'eventLogsDataSource' + streams: [ + 'Microsoft-Event' + ] + xPathQueries: [ + 'Application!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + 'Security!*[System[(band(Keywords,13510798882111488))]]' + 'System!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + ] + } + ] + } + description: 'Collecting Windows-specific performance counters and Windows Event Logs' + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' +} +param name = 'idcrwin001' +// Non-required parameters +param location = '' +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dataCollectionRuleProperties`](#parameter-datacollectionruleproperties) | object | The kind of data collection rule. | +| [`name`](#parameter-name) | string | The name of the data collection rule. The name is case insensitive. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Resource tags. | + +### Parameter: `dataCollectionRuleProperties` + +The kind of data collection rule. + +- Required: Yes +- Type: object + +### Parameter: `name` + +The name of the data collection rule. The name is case insensitive. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. + +- Required: No +- Type: array + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the dataCollectionRule. | +| `resourceGroupName` | string | The name of the resource group the dataCollectionRule was created in. | +| `resourceId` | string | The resource ID of the dataCollectionRule. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.3.0` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/insights/data-collection-rule/main.bicep b/avm/1.1.0/res/insights/data-collection-rule/main.bicep new file mode 100644 index 000000000..ea79dc262 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/main.bicep @@ -0,0 +1,263 @@ +metadata name = 'Data Collection Rules' +metadata description = 'This module deploys a Data Collection Rule.' + +// ============== // +// Parameters // +// ============== // + +@description('Required. The name of the data collection rule. The name is case insensitive.') +param name string + +@description('Required. The kind of data collection rule.') +param dataCollectionRuleProperties dataCollectionRulePropertiesType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.3.0' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { managedIdentityAllType } from 'br/public:avm/utl/types/avm-common-types:0.3.0' +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentityAllType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.3.0' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Resource tags.') +param tags object? + +// =============== // +// Deployments // +// =============== // + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var dataCollectionRulePropertiesUnion = union( + { + description: dataCollectionRuleProperties.?description + }, + dataCollectionRuleProperties.kind == 'Linux' || dataCollectionRuleProperties.kind == 'Windows' || dataCollectionRuleProperties.kind == 'All' + ? { + dataSources: dataCollectionRuleProperties.dataSources + dataFlows: dataCollectionRuleProperties.dataFlows + destinations: dataCollectionRuleProperties.destinations + dataCollectionEndpointId: dataCollectionRuleProperties.?dataCollectionEndpointResourceId + streamDeclarations: dataCollectionRuleProperties.?streamDeclarations + } + : {}, + dataCollectionRuleProperties.kind == 'AgentSettings' + ? { + agentSettings: dataCollectionRuleProperties.agentSettings + } + : {} +) + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.insights-datacollectionrule.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource dataCollectionRule 'Microsoft.Insights/dataCollectionRules@2023-03-11' = if (dataCollectionRuleProperties.kind != 'All') { + kind: dataCollectionRuleProperties.kind + location: location + name: name + tags: tags + identity: identity + properties: dataCollectionRulePropertiesUnion +} + +// Using a separate resource for parameter kind: 'All' as it requires that the "kind' is not set on the resource and 'kind: null' is not allowed for this resource type +resource dataCollectionRuleAll 'Microsoft.Insights/dataCollectionRules@2023-03-11' = if (dataCollectionRuleProperties.kind == 'All') { + location: location + name: name + tags: tags + identity: identity + properties: dataCollectionRulePropertiesUnion +} + +// Using a module as a workaround for issues with conditional scope: https://github.com/Azure/bicep/issues/7367 +module dataCollectionRule_conditionalScopeResources 'modules/nested_conditionalScope.bicep' = if ((!empty(lock ?? {}) && lock.?kind != 'None') || (!empty(roleAssignments ?? []))) { + name: '${uniqueString(deployment().name, location)}-DCR-ConditionalScope' + params: { + dataCollectionRuleName: dataCollectionRuleProperties.kind == 'All' + ? dataCollectionRuleAll.name + : dataCollectionRule.name + builtInRoleNames: builtInRoleNames + lock: lock + roleAssignments: roleAssignments + } +} + +// =========== // +// Outputs // +// =========== // + +@description('The name of the dataCollectionRule.') +output name string = dataCollectionRuleProperties.kind == 'All' ? dataCollectionRuleAll.name : dataCollectionRule.name + +@description('The resource ID of the dataCollectionRule.') +output resourceId string = dataCollectionRuleProperties.kind == 'All' ? dataCollectionRuleAll.id : dataCollectionRule.id + +@description('The name of the resource group the dataCollectionRule was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = dataCollectionRuleProperties.kind == 'All' + ? dataCollectionRuleAll.location + : dataCollectionRule.location + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string? = dataCollectionRuleProperties.kind == 'All' + ? dataCollectionRuleAll.?identity.?principalId + : dataCollectionRule.?identity.?principalId + +// =============== // +// Definitions // +// =============== // + +@export() +@discriminator('kind') +type dataCollectionRulePropertiesType = + | linuxDcrPropertiesType + | windowsDcrPropertiesType + | allPlatformsDcrPropertiesType + | agentSettingsDcrPropertiesType + +type linuxDcrPropertiesType = { + @description('Required. The platform type specifies the type of resources this rule can apply to.') + kind: 'Linux' + + @description('Required. Specification of data sources that will be collected.') + dataSources: object + + @description('Required. The specification of data flows.') + dataFlows: array + + @description('Required. Specification of destinations that can be used in data flows.') + destinations: object + + @description('Optional. The resource ID of the data collection endpoint that this rule can be used with.') + dataCollectionEndpointResourceId: string? + + @description('Optional. Declaration of custom streams used in this rule.') + streamDeclarations: object? + + @description('Optional. Description of the data collection rule.') + description: string? +} + +type windowsDcrPropertiesType = { + @description('Required. The platform type specifies the type of resources this rule can apply to.') + kind: 'Windows' + + @description('Required. Specification of data sources that will be collected.') + dataSources: object + + @description('Required. The specification of data flows.') + dataFlows: array + + @description('Required. Specification of destinations that can be used in data flows.') + destinations: object + + @description('Optional. The resource ID of the data collection endpoint that this rule can be used with.') + dataCollectionEndpointResourceId: string? + + @description('Optional. Declaration of custom streams used in this rule.') + streamDeclarations: object? + + @description('Optional. Description of the data collection rule.') + description: string? +} + +type allPlatformsDcrPropertiesType = { + @description('Required. The platform type specifies the type of resources this rule can apply to.') + kind: 'All' + + @description('Required. Specification of data sources that will be collected.') + dataSources: object + + @description('Required. The specification of data flows.') + dataFlows: array + + @description('Required. Specification of destinations that can be used in data flows.') + destinations: object + + @description('Optional. The resource ID of the data collection endpoint that this rule can be used with.') + dataCollectionEndpointResourceId: string? + + @description('Optional. Declaration of custom streams used in this rule.') + streamDeclarations: object? + + @description('Optional. Description of the data collection rule.') + description: string? +} + +type agentSettingsDcrPropertiesType = { + @description('Required. The platform type specifies the type of resources this rule can apply to.') + kind: 'AgentSettings' + + @description('Optional. Description of the data collection rule.') + description: string? + + @description('Required. Agent settings used to modify agent behavior on a given host.') + agentSettings: agentSettingsType +} + +type agentSettingsType = { + @description('Required. All the settings that are applicable to the logs agent (AMA).') + logs: agentSettingType[] +} + +type agentSettingType = { + @description('Required. The name of the agent setting.') + name: ('MaxDiskQuotaInMB' | 'UseTimeReceivedForForwardedEvents') + + @description('Required. The value of the agent setting.') + value: string +} diff --git a/avm/1.1.0/res/insights/data-collection-rule/main.json b/avm/1.1.0/res/insights/data-collection-rule/main.json new file mode 100644 index 000000000..f891571dd --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/main.json @@ -0,0 +1,771 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "18326948801281911152" + }, + "name": "Data Collection Rules", + "description": "This module deploys a Data Collection Rule." + }, + "definitions": { + "dataCollectionRulePropertiesType": { + "type": "object", + "discriminator": { + "propertyName": "kind", + "mapping": { + "Linux": { + "$ref": "#/definitions/linuxDcrPropertiesType" + }, + "Windows": { + "$ref": "#/definitions/windowsDcrPropertiesType" + }, + "All": { + "$ref": "#/definitions/allPlatformsDcrPropertiesType" + }, + "AgentSettings": { + "$ref": "#/definitions/agentSettingsDcrPropertiesType" + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "linuxDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Linux" + ], + "metadata": { + "description": "Required. The platform type specifies the type of resources this rule can apply to." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Declaration of custom streams used in this rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + } + }, + "windowsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Windows" + ], + "metadata": { + "description": "Required. The platform type specifies the type of resources this rule can apply to." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Declaration of custom streams used in this rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + } + }, + "allPlatformsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "All" + ], + "metadata": { + "description": "Required. The platform type specifies the type of resources this rule can apply to." + } + }, + "dataSources": { + "type": "object", + "metadata": { + "description": "Required. Specification of data sources that will be collected." + } + }, + "dataFlows": { + "type": "array", + "metadata": { + "description": "Required. The specification of data flows." + } + }, + "destinations": { + "type": "object", + "metadata": { + "description": "Required. Specification of destinations that can be used in data flows." + } + }, + "dataCollectionEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the data collection endpoint that this rule can be used with." + } + }, + "streamDeclarations": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Declaration of custom streams used in this rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + } + } + }, + "agentSettingsDcrPropertiesType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "AgentSettings" + ], + "metadata": { + "description": "Required. The platform type specifies the type of resources this rule can apply to." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the data collection rule." + } + }, + "agentSettings": { + "$ref": "#/definitions/agentSettingsType", + "metadata": { + "description": "Required. Agent settings used to modify agent behavior on a given host." + } + } + } + }, + "agentSettingsType": { + "type": "object", + "properties": { + "logs": { + "type": "array", + "items": { + "$ref": "#/definitions/agentSettingType" + }, + "metadata": { + "description": "Required. All the settings that are applicable to the logs agent (AMA)." + } + } + } + }, + "agentSettingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "MaxDiskQuotaInMB", + "UseTimeReceivedForForwardedEvents" + ], + "metadata": { + "description": "Required. The name of the agent setting." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value of the agent setting." + } + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the data collection rule. The name is case insensitive." + } + }, + "dataCollectionRuleProperties": { + "$ref": "#/definitions/dataCollectionRulePropertiesType", + "metadata": { + "description": "Required. The kind of data collection rule." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "dataCollectionRulePropertiesUnion": "[union(createObject('description', tryGet(parameters('dataCollectionRuleProperties'), 'description')), if(or(or(equals(parameters('dataCollectionRuleProperties').kind, 'Linux'), equals(parameters('dataCollectionRuleProperties').kind, 'Windows')), equals(parameters('dataCollectionRuleProperties').kind, 'All')), createObject('dataSources', parameters('dataCollectionRuleProperties').dataSources, 'dataFlows', parameters('dataCollectionRuleProperties').dataFlows, 'destinations', parameters('dataCollectionRuleProperties').destinations, 'dataCollectionEndpointId', tryGet(parameters('dataCollectionRuleProperties'), 'dataCollectionEndpointResourceId'), 'streamDeclarations', tryGet(parameters('dataCollectionRuleProperties'), 'streamDeclarations')), createObject()), if(equals(parameters('dataCollectionRuleProperties').kind, 'AgentSettings'), createObject('agentSettings', parameters('dataCollectionRuleProperties').agentSettings), createObject()))]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-datacollectionrule.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "dataCollectionRule": { + "condition": "[not(equals(parameters('dataCollectionRuleProperties').kind, 'All'))]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2023-03-11", + "name": "[parameters('name')]", + "kind": "[parameters('dataCollectionRuleProperties').kind]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" + }, + "dataCollectionRuleAll": { + "condition": "[equals(parameters('dataCollectionRuleProperties').kind, 'All')]", + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2023-03-11", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[variables('dataCollectionRulePropertiesUnion')]" + }, + "dataCollectionRule_conditionalScopeResources": { + "condition": "[or(and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None'))), not(empty(coalesce(parameters('roleAssignments'), createArray()))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-DCR-ConditionalScope', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dataCollectionRuleName": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), createObject('value', parameters('name')), createObject('value', parameters('name')))]", + "builtInRoleNames": { + "value": "[variables('builtInRoleNames')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "179607600205357551" + } + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.0" + } + } + } + }, + "parameters": { + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "builtInRoleNames": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Built-in role names." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "dataCollectionRuleName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Data Collection Rule to assign the role(s) to." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(parameters('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ] + }, + "resources": { + "dataCollectionRule": { + "existing": true, + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2023-03-11", + "name": "[parameters('dataCollectionRuleName')]" + }, + "dataCollectionRule_roleAssignments": { + "copy": { + "name": "dataCollectionRule_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/dataCollectionRules/{0}', parameters('dataCollectionRuleName'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceGroup().id, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + }, + "dataCollectionRule_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Insights/dataCollectionRules/{0}', parameters('dataCollectionRuleName'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('dataCollectionRuleName')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + } + } + } + }, + "dependsOn": [ + "dataCollectionRule", + "dataCollectionRuleAll" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), parameters('name'), parameters('name'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dataCollectionRule." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')), resourceId('Microsoft.Insights/dataCollectionRules', parameters('name')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the dataCollectionRule was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), reference('dataCollectionRuleAll', '2023-03-11', 'full').location, reference('dataCollectionRule', '2023-03-11', 'full').location)]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(equals(parameters('dataCollectionRuleProperties').kind, 'All'), tryGet(tryGet(reference('dataCollectionRuleAll', '2023-03-11', 'full'), 'identity'), 'principalId'), tryGet(tryGet(reference('dataCollectionRule', '2023-03-11', 'full'), 'identity'), 'principalId'))]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/data-collection-rule/modules/nested_conditionalScope.bicep b/avm/1.1.0/res/insights/data-collection-rule/modules/nested_conditionalScope.bicep new file mode 100644 index 000000000..bff1dd7cb --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/modules/nested_conditionalScope.bicep @@ -0,0 +1,55 @@ +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.3.0' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Built-in role names.') +param builtInRoleNames object = {} + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.3.0' +@description('Optional. The lock settings of the service.') +param lock lockType? + +@description('Required. Name of the Data Collection Rule to assign the role(s) to.') +param dataCollectionRuleName string + +resource dataCollectionRule 'Microsoft.Insights/dataCollectionRules@2023-03-11' existing = { + name: dataCollectionRuleName +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource dataCollectionRule_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(resourceGroup().id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + scope: dataCollectionRule + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + } +] + +resource dataCollectionRule_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${dataCollectionRuleName}' + scope: dataCollectionRule + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } +} diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/agent-settings/main.test.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/agent-settings/main.test.bicep new file mode 100644 index 000000000..28364a28f --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/agent-settings/main.test.bicep @@ -0,0 +1,59 @@ +targetScope = 'subscription' + +metadata name = 'Agent Settings' +metadata description = 'This instance deploys the module AMA (Azure Monitor Agent) Settings DCR.' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.dataCollectionRules-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idcrags' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dataCollectionRuleProperties: { + kind: 'AgentSettings' + description: 'Agent Settings' + agentSettings: { + logs: [ + { + name: 'MaxDiskQuotaInMB' + value: '5000' + } + ] + } + } + } + } +] diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customadv/dependencies.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customadv/dependencies.bicep new file mode 100644 index 000000000..83a92b025 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customadv/dependencies.bicep @@ -0,0 +1,68 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the data collection endpoint to create.') +param dataCollectionEndpointName string + +@description('Required. The name of the log analytics workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: logAnalyticsWorkspaceName + location: location + + resource customTableAdvanced 'tables@2022-10-01' = { + name: 'CustomTableAdvanced_CL' + properties: { + schema: { + name: 'CustomTableAdvanced_CL' + columns: [ + { + name: 'TimeGenerated' + type: 'DateTime' + } + { + name: 'EventTime' + type: 'DateTime' + } + { + name: 'EventLevel' + type: 'String' + } + { + name: 'EventCode' + type: 'Int' + } + { + name: 'Message' + type: 'String' + } + { + name: 'RawData' + type: 'String' + } + ] + } + } + } +} + +resource dataCollectionEndpoint 'Microsoft.Insights/dataCollectionEndpoints@2023-03-11' = { + kind: 'Windows' + location: location + name: dataCollectionEndpointName + properties: { + networkAcls: { + publicNetworkAccess: 'Enabled' + } + } +} + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id + +@description('The name of the deployed log analytics workspace.') +output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name + +@description('The resource ID of the created Data Collection Endpoint.') +output dataCollectionEndpointResourceId string = dataCollectionEndpoint.id diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customadv/main.test.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customadv/main.test.bicep new file mode 100644 index 000000000..23b27402b --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customadv/main.test.bicep @@ -0,0 +1,140 @@ +targetScope = 'subscription' + +metadata name = 'Collecting custom text logs with ingestion-time transformation' +metadata description = 'This instance deploys the module to setup collection of custom logs and ingestion-time transformation.' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.dataCollectionRules-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idcrcusadv' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + dataCollectionEndpointName: 'dep-${namePrefix}-dce-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dataCollectionRuleProperties: { + kind: 'Windows' + dataCollectionEndpointResourceId: nestedDependencies.outputs.dataCollectionEndpointResourceId + description: 'Collecting custom text logs with ingestion-time transformation to columns. Expected format of a log line (comma separated values): ",,,", for example: "2023-01-25T20:15:05Z,ERROR,404,Page not found"' + dataFlows: [ + { + streams: [ + 'Custom-CustomTableAdvanced_CL' + ] + destinations: [ + nestedDependencies.outputs.logAnalyticsWorkspaceName + ] + transformKql: 'source | extend LogFields = split(RawData, ",") | extend EventTime = todatetime(LogFields[0]) | extend EventLevel = tostring(LogFields[1]) | extend EventCode = toint(LogFields[2]) | extend Message = tostring(LogFields[3]) | project TimeGenerated, EventTime, EventLevel, EventCode, Message' + outputStream: 'Custom-CustomTableAdvanced_CL' + } + ] + dataSources: { + logFiles: [ + { + name: 'CustomTableAdvanced_CL' + samplingFrequencyInSeconds: 60 + streams: [ + 'Custom-CustomTableAdvanced_CL' + ] + filePatterns: [ + 'C:\\TestLogsAdvanced\\TestLog*.log' + ] + format: 'text' + settings: { + text: { + recordStartTimestampFormat: 'ISO 8601' + } + } + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + name: nestedDependencies.outputs.logAnalyticsWorkspaceName + } + ] + } + streamDeclarations: { + 'Custom-CustomTableAdvanced_CL': { + columns: [ + { + name: 'TimeGenerated' + type: 'datetime' + } + { + name: 'EventTime' + type: 'datetime' + } + { + name: 'EventLevel' + type: 'string' + } + { + name: 'EventCode' + type: 'int' + } + { + name: 'Message' + type: 'string' + } + { + name: 'RawData' + type: 'string' + } + ] + } + } + } + managedIdentities: { + systemAssigned: true + } + tags: { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Data Collection Rules' + kind: 'Windows' + } + } + } +] diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/custombasic/dependencies.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/custombasic/dependencies.bicep new file mode 100644 index 000000000..b474947ee --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/custombasic/dependencies.bicep @@ -0,0 +1,52 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the data collection endpoint to create.') +param dataCollectionEndpointName string + +@description('Required. The name of the log analytics workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: logAnalyticsWorkspaceName + location: location + + resource customTableBasic 'tables@2022-10-01' = { + name: 'CustomTableBasic_CL' + properties: { + schema: { + name: 'CustomTableBasic_CL' + columns: [ + { + name: 'TimeGenerated' + type: 'DateTime' + } + { + name: 'RawData' + type: 'String' + } + ] + } + } + } +} + +resource dataCollectionEndpoint 'Microsoft.Insights/dataCollectionEndpoints@2023-03-11' = { + kind: 'Windows' + location: location + name: dataCollectionEndpointName + properties: { + networkAcls: { + publicNetworkAccess: 'Enabled' + } + } +} + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id + +@description('The name of the deployed log analytics workspace.') +output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name + +@description('The resource ID of the created Data Collection Endpoint.') +output dataCollectionEndpointResourceId string = dataCollectionEndpoint.id diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/custombasic/main.test.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/custombasic/main.test.bicep new file mode 100644 index 000000000..7c660c4be --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/custombasic/main.test.bicep @@ -0,0 +1,121 @@ +targetScope = 'subscription' + +metadata name = 'Collecting custom text logs' +metadata description = 'This instance deploys the module to setup collection of custom logs.' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.dataCollectionRules-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idcrcusbas' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + dataCollectionEndpointName: 'dep-${namePrefix}-dce-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dataCollectionRuleProperties: { + kind: 'All' + dataCollectionEndpointResourceId: nestedDependencies.outputs.dataCollectionEndpointResourceId + description: 'Collecting custom text logs without ingestion-time transformation.' + dataFlows: [ + { + streams: [ + 'Custom-CustomTableBasic_CL' + ] + destinations: [ + nestedDependencies.outputs.logAnalyticsWorkspaceName + ] + transformKql: 'source' + outputStream: 'Custom-CustomTableBasic_CL' + } + ] + dataSources: { + logFiles: [ + { + name: 'CustomTableBasic_CL' + samplingFrequencyInSeconds: 60 + streams: [ + 'Custom-CustomTableBasic_CL' + ] + filePatterns: [ + 'C:\\TestLogsBasic\\TestLog*.log' + ] + format: 'text' + settings: { + text: { + recordStartTimestampFormat: 'ISO 8601' + } + } + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + name: nestedDependencies.outputs.logAnalyticsWorkspaceName + } + ] + } + streamDeclarations: { + 'Custom-CustomTableBasic_CL': { + columns: [ + { + name: 'TimeGenerated' + type: 'datetime' + } + { + name: 'RawData' + type: 'string' + } + ] + } + } + } + tags: { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Data Collection Rules' + kind: 'Windows' + } + } + } +] diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customiis/dependencies.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customiis/dependencies.bicep new file mode 100644 index 000000000..a4a121e56 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customiis/dependencies.bicep @@ -0,0 +1,33 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the data collection endpoint to create.') +param dataCollectionEndpointName string + +@description('Required. The name of the log analytics workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +resource dataCollectionEndpoint 'Microsoft.Insights/dataCollectionEndpoints@2023-03-11' = { + kind: 'Windows' + location: location + name: dataCollectionEndpointName + properties: { + networkAcls: { + publicNetworkAccess: 'Enabled' + } + } +} + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id + +@description('The name of the deployed log analytics workspace.') +output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name + +@description('The resource ID of the created Data Collection Endpoint.') +output dataCollectionEndpointResourceId string = dataCollectionEndpoint.id diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customiis/main.test.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customiis/main.test.bicep new file mode 100644 index 000000000..21221f6e6 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/customiis/main.test.bicep @@ -0,0 +1,100 @@ +targetScope = 'subscription' + +metadata name = 'Collecting IIS logs' +metadata description = 'This instance deploys the module to setup the collection of IIS logs.' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.dataCollectionRules-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idcrcusiis' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + dataCollectionEndpointName: 'dep-${namePrefix}-dce-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dataCollectionRuleProperties: { + kind: 'Windows' + dataCollectionEndpointResourceId: nestedDependencies.outputs.dataCollectionEndpointResourceId + description: 'Collecting IIS logs.' + dataFlows: [ + { + streams: [ + 'Microsoft-W3CIISLog' + ] + destinations: [ + nestedDependencies.outputs.logAnalyticsWorkspaceName + ] + transformKql: 'source' + outputStream: 'Microsoft-W3CIISLog' + } + ] + dataSources: { + iisLogs: [ + { + name: 'iisLogsDataSource' + streams: [ + 'Microsoft-W3CIISLog' + ] + logDirectories: [ + 'C:\\inetpub\\logs\\LogFiles\\W3SVC1' + ] + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + name: nestedDependencies.outputs.logAnalyticsWorkspaceName + } + ] + } + } + tags: { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Data Collection Rules' + kind: 'Windows' + } + } + } +] diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..50102a692 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,88 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.dataCollectionRules-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idcrmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dataCollectionRuleProperties: { + kind: 'Windows' + dataSources: { + performanceCounters: [ + { + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + counterSpecifiers: [ + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Processes' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Handle Count' + '\\System\\System Up Time' + '\\System\\Context Switches/sec' + '\\System\\Processor Queue Length' + ] + } + ] + } + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + } + dataFlows: [ + { + streams: [ + 'Microsoft-InsightsMetrics' + ] + destinations: [ + 'azureMonitorMetrics-default' + ] + } + ] + } + } + } +] diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/linux/dependencies.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/linux/dependencies.bicep new file mode 100644 index 000000000..62da14da4 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/linux/dependencies.bicep @@ -0,0 +1,16 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the log analytics workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id + +@description('The name of the deployed log analytics workspace.') +output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/linux/main.test.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/linux/main.test.bicep new file mode 100644 index 000000000..4a7759ac3 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/linux/main.test.bicep @@ -0,0 +1,212 @@ +targetScope = 'subscription' + +metadata name = 'Collecting Linux-specific information' +metadata description = 'This instance deploys the module to setup the collection of Linux-specific performance counters and Linux Syslog.' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.dataCollectionRules-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idcrlin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dataCollectionRuleProperties: { + kind: 'Linux' + description: 'Collecting Linux-specific performance counters and Linux Syslog' + dataSources: { + performanceCounters: [ + { + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + counterSpecifiers: [ + 'Processor(*)\\% Processor Time' + 'Processor(*)\\% Idle Time' + 'Processor(*)\\% User Time' + 'Processor(*)\\% Nice Time' + 'Processor(*)\\% Privileged Time' + 'Processor(*)\\% IO Wait Time' + 'Processor(*)\\% Interrupt Time' + 'Processor(*)\\% DPC Time' + 'Memory(*)\\Available MBytes Memory' + 'Memory(*)\\% Available Memory' + 'Memory(*)\\Used Memory MBytes' + 'Memory(*)\\% Used Memory' + 'Memory(*)\\Pages/sec' + 'Memory(*)\\Page Reads/sec' + 'Memory(*)\\Page Writes/sec' + 'Memory(*)\\Available MBytes Swap' + 'Memory(*)\\% Available Swap Space' + 'Memory(*)\\Used MBytes Swap Space' + 'Memory(*)\\% Used Swap Space' + 'Logical Disk(*)\\% Free Inodes' + 'Logical Disk(*)\\% Used Inodes' + 'Logical Disk(*)\\Free Megabytes' + 'Logical Disk(*)\\% Free Space' + 'Logical Disk(*)\\% Used Space' + 'Logical Disk(*)\\Logical Disk Bytes/sec' + 'Logical Disk(*)\\Disk Read Bytes/sec' + 'Logical Disk(*)\\Disk Write Bytes/sec' + 'Logical Disk(*)\\Disk Transfers/sec' + 'Logical Disk(*)\\Disk Reads/sec' + 'Logical Disk(*)\\Disk Writes/sec' + 'Network(*)\\Total Bytes Transmitted' + 'Network(*)\\Total Bytes Received' + 'Network(*)\\Total Bytes' + 'Network(*)\\Total Packets Transmitted' + 'Network(*)\\Total Packets Received' + 'Network(*)\\Total Rx Errors' + 'Network(*)\\Total Tx Errors' + 'Network(*)\\Total Collisions' + ] + } + ] + syslog: [ + { + name: 'sysLogsDataSource-debugLevel' + streams: [ + 'Microsoft-Syslog' + ] + facilityNames: [ + 'auth' + 'authpriv' + ] + logLevels: [ + 'Debug' + 'Info' + 'Notice' + 'Warning' + 'Error' + 'Critical' + 'Alert' + 'Emergency' + ] + } + { + name: 'sysLogsDataSource-warningLevel' + streams: [ + 'Microsoft-Syslog' + ] + facilityNames: [ + 'cron' + 'daemon' + 'mark' + 'kern' + 'local0' + ] + logLevels: [ + 'Warning' + 'Error' + 'Critical' + 'Alert' + 'Emergency' + ] + } + { + name: 'sysLogsDataSource-errLevel' + streams: [ + 'Microsoft-Syslog' + ] + facilityNames: [ + 'local1' + 'local2' + 'local3' + 'local4' + 'local5' + 'local6' + 'local7' + 'lpr' + 'mail' + 'news' + 'syslog' + ] + logLevels: [ + 'Error' + 'Critical' + 'Alert' + 'Emergency' + ] + } + ] + } + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + logAnalytics: [ + { + workspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + name: nestedDependencies.outputs.logAnalyticsWorkspaceName + } + ] + } + dataFlows: [ + { + streams: [ + 'Microsoft-InsightsMetrics' + ] + destinations: [ + 'azureMonitorMetrics-default' + ] + } + { + streams: [ + 'Microsoft-Syslog' + ] + destinations: [ + nestedDependencies.outputs.logAnalyticsWorkspaceName + ] + } + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Data Collection Rules' + kind: 'Linux' + } + } + } +] diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..e2e3291fd --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/max/dependencies.bicep @@ -0,0 +1,66 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the data collection endpoint to create.') +param dataCollectionEndpointName string + +@description('Required. The name of the log analytics workspace to create.') +param logAnalyticsWorkspaceName string + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: logAnalyticsWorkspaceName + location: location + + resource customTableBasic 'tables@2022-10-01' = { + name: 'CustomTableBasic_CL' + properties: { + schema: { + name: 'CustomTableBasic_CL' + columns: [ + { + name: 'TimeGenerated' + type: 'DateTime' + } + { + name: 'RawData' + type: 'String' + } + ] + } + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +resource dataCollectionEndpoint 'Microsoft.Insights/dataCollectionEndpoints@2023-03-11' = { + kind: 'Windows' + location: location + name: dataCollectionEndpointName + properties: { + networkAcls: { + publicNetworkAccess: 'Enabled' + } + } +} + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id + +@description('The name of the deployed log analytics workspace.') +output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name + +@description('The principal ID of the created managed identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Data Collection Endpoint.') +output dataCollectionEndpointResourceId string = dataCollectionEndpoint.id diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..41c799217 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/max/main.test.bicep @@ -0,0 +1,154 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.dataCollectionRules-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idcrmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + dataCollectionEndpointName: 'dep-${namePrefix}-dce-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dataCollectionRuleProperties: { + kind: 'Windows' + dataCollectionEndpointResourceId: nestedDependencies.outputs.dataCollectionEndpointResourceId + description: 'Collecting custom text logs without ingestion-time transformation.' + dataFlows: [ + { + streams: [ + 'Custom-CustomTableBasic_CL' + ] + destinations: [ + nestedDependencies.outputs.logAnalyticsWorkspaceName + ] + transformKql: 'source' + outputStream: 'Custom-CustomTableBasic_CL' + } + ] + dataSources: { + logFiles: [ + { + name: 'CustomTableBasic_CL' + samplingFrequencyInSeconds: 60 + streams: [ + 'Custom-CustomTableBasic_CL' + ] + filePatterns: [ + 'C:\\TestLogsBasic\\TestLog*.log' + ] + format: 'text' + settings: { + text: { + recordStartTimestampFormat: 'ISO 8601' + } + } + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + name: nestedDependencies.outputs.logAnalyticsWorkspaceName + } + ] + } + streamDeclarations: { + 'Custom-CustomTableBasic_CL': { + columns: [ + { + name: 'TimeGenerated' + type: 'datetime' + } + { + name: 'RawData' + type: 'string' + } + ] + } + } + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + roleAssignments: [ + { + name: '89a4d6fa-defb-4099-9196-173d94b91d67' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Data Collection Rules' + kind: 'Windows' + } + } + } +] diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..62da14da4 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,16 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the log analytics workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id + +@description('The name of the deployed log analytics workspace.') +output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..d4cec148c --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,167 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.dataCollectionRules-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idcrwaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dataCollectionRuleProperties: { + kind: 'Windows' + description: 'Collecting Windows-specific performance counters and Windows Event Logs' + dataSources: { + performanceCounters: [ + { + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + counterSpecifiers: [ + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Processes' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Handle Count' + '\\System\\System Up Time' + '\\System\\Context Switches/sec' + '\\System\\Processor Queue Length' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pages/sec' + '\\Memory\\Page Faults/sec' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + ] + } + ] + windowsEventLogs: [ + { + name: 'eventLogsDataSource' + streams: [ + 'Microsoft-Event' + ] + xPathQueries: [ + 'Application!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + 'Security!*[System[(band(Keywords,13510798882111488))]]' + 'System!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + ] + } + ] + } + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + logAnalytics: [ + { + workspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + name: nestedDependencies.outputs.logAnalyticsWorkspaceName + } + ] + } + dataFlows: [ + { + streams: [ + 'Microsoft-InsightsMetrics' + ] + destinations: [ + 'azureMonitorMetrics-default' + ] + } + { + streams: [ + 'Microsoft-Event' + ] + destinations: [ + nestedDependencies.outputs.logAnalyticsWorkspaceName + ] + } + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Data Collection Rules' + kind: 'Windows' + } + } + } +] diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/windows/dependencies.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/windows/dependencies.bicep new file mode 100644 index 000000000..62da14da4 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/windows/dependencies.bicep @@ -0,0 +1,16 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the log analytics workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id + +@description('The name of the deployed log analytics workspace.') +output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name diff --git a/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/windows/main.test.bicep b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/windows/main.test.bicep new file mode 100644 index 000000000..0655a2c2f --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/tests/e2e/windows/main.test.bicep @@ -0,0 +1,166 @@ +targetScope = 'subscription' + +metadata name = 'Collecting Windows-specific information' +metadata description = 'This instance deploys the module to setup the connection of Windows-specific performance counters and Windows Event Logs.' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.dataCollectionRules-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idcrwin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// =========== // +// Deployments // +// =========== // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dataCollectionRuleProperties: { + kind: 'Windows' + description: 'Collecting Windows-specific performance counters and Windows Event Logs' + dataSources: { + performanceCounters: [ + { + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + counterSpecifiers: [ + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Processes' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Handle Count' + '\\System\\System Up Time' + '\\System\\Context Switches/sec' + '\\System\\Processor Queue Length' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pages/sec' + '\\Memory\\Page Faults/sec' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + ] + } + ] + windowsEventLogs: [ + { + name: 'eventLogsDataSource' + streams: [ + 'Microsoft-Event' + ] + xPathQueries: [ + 'Application!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + 'Security!*[System[(band(Keywords,13510798882111488))]]' + 'System!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + ] + } + ] + } + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + logAnalytics: [ + { + workspaceResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + name: nestedDependencies.outputs.logAnalyticsWorkspaceName + } + ] + } + dataFlows: [ + { + streams: [ + 'Microsoft-InsightsMetrics' + ] + destinations: [ + 'azureMonitorMetrics-default' + ] + } + { + streams: [ + 'Microsoft-Event' + ] + destinations: [ + nestedDependencies.outputs.logAnalyticsWorkspaceName + ] + } + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Data Collection Rules' + kind: 'Windows' + } + } + } +] diff --git a/avm/1.1.0/res/insights/data-collection-rule/version.json b/avm/1.1.0/res/insights/data-collection-rule/version.json new file mode 100644 index 000000000..a8eda3102 --- /dev/null +++ b/avm/1.1.0/res/insights/data-collection-rule/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/diagnostic-setting/README.md b/avm/1.1.0/res/insights/diagnostic-setting/README.md new file mode 100644 index 000000000..17ab873d6 --- /dev/null +++ b/avm/1.1.0/res/insights/diagnostic-setting/README.md @@ -0,0 +1,456 @@ +# Diagnostic Settings (Activity Logs) for Azure Subscriptions `[Microsoft.Insights/diagnosticSettings]` + +This module deploys a Subscription wide export of the Activity Log. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/insights/diagnostic-setting:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting:' = { + name: 'diagnosticSettingDeployment' + params: { + location: '' + name: 'idsmin001' + workspaceResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "location": { + "value": "" + }, + "name": { + "value": "idsmin001" + }, + "workspaceResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/diagnostic-setting:' + +param location = '' +param name = 'idsmin001' +param workspaceResourceId = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting:' = { + name: 'diagnosticSettingDeployment' + params: { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + location: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'idsmax001' + storageAccountResourceId: '' + workspaceResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "eventHubAuthorizationRuleResourceId": { + "value": "" + }, + "eventHubName": { + "value": "" + }, + "location": { + "value": "" + }, + "metricCategories": { + "value": [ + { + "category": "AllMetrics" + } + ] + }, + "name": { + "value": "idsmax001" + }, + "storageAccountResourceId": { + "value": "" + }, + "workspaceResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/diagnostic-setting:' + +param eventHubAuthorizationRuleResourceId = '' +param eventHubName = '' +param location = '' +param metricCategories = [ + { + category: 'AllMetrics' + } +] +param name = 'idsmax001' +param storageAccountResourceId = '' +param workspaceResourceId = '' +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting:' = { + name: 'diagnosticSettingDeployment' + params: { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + location: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'idswaf001' + storageAccountResourceId: '' + workspaceResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "eventHubAuthorizationRuleResourceId": { + "value": "" + }, + "eventHubName": { + "value": "" + }, + "location": { + "value": "" + }, + "metricCategories": { + "value": [ + { + "category": "AllMetrics" + } + ] + }, + "name": { + "value": "idswaf001" + }, + "storageAccountResourceId": { + "value": "" + }, + "workspaceResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/diagnostic-setting:' + +param eventHubAuthorizationRuleResourceId = '' +param eventHubName = '' +param location = '' +param metricCategories = [ + { + category: 'AllMetrics' + } +] +param name = 'idswaf001' +param storageAccountResourceId = '' +param workspaceResourceId = '' +``` + +
+

+ +## Parameters + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`eventHubAuthorizationRuleResourceId`](#parameter-eventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-eventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. | +| [`location`](#parameter-location) | string | Location deployment metadata. | +| [`logAnalyticsDestinationType`](#parameter-loganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-logcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-marketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-metriccategories) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`name`](#parameter-name) | string | Name of the Diagnostic settings. | +| [`storageAccountResourceId`](#parameter-storageaccountresourceid) | string | Resource ID of the diagnostic storage account. | +| [`workspaceResourceId`](#parameter-workspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. | + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. + +- Required: No +- Type: string + +### Parameter: `location` + +Location deployment metadata. + +- Required: No +- Type: string +- Default: `[deployment().location]` + +### Parameter: `logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-logcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-logcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs. | +| [`enabled`](#parameter-logcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `metricCategories` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-metriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-metriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `name` + +Name of the Diagnostic settings. + +- Required: No +- Type: string +- Default: `[format('{0}-diagnosticSettings', uniqueString(subscription().id))]` + +### Parameter: `storageAccountResourceId` + +Resource ID of the diagnostic storage account. + +- Required: No +- Type: string + +### Parameter: `workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the diagnostic settings. | +| `resourceId` | string | The resource ID of the diagnostic settings. | +| `subscriptionName` | string | The name of the subscription to deploy into. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/insights/diagnostic-setting/main.bicep b/avm/1.1.0/res/insights/diagnostic-setting/main.bicep new file mode 100644 index 000000000..2bcff0d23 --- /dev/null +++ b/avm/1.1.0/res/insights/diagnostic-setting/main.bicep @@ -0,0 +1,124 @@ +metadata name = 'Diagnostic Settings (Activity Logs) for Azure Subscriptions' +metadata description = 'This module deploys a Subscription wide export of the Activity Log.' + +targetScope = 'subscription' + +@description('Optional. Name of the Diagnostic settings.') +@minLength(1) +@maxLength(260) +param name string = '${uniqueString(subscription().id)}-diagnosticSettings' + +@description('Optional. Resource ID of the diagnostic storage account.') +param storageAccountResourceId string? + +@description('Optional. Resource ID of the diagnostic log analytics workspace.') +param workspaceResourceId string? + +@description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') +param eventHubAuthorizationRuleResourceId string? + +@description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category.') +param eventHubName string? + +@description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') +param logCategoriesAndGroups logCategoriesAndGroupsType[]? + +@description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') +param metricCategories metricCategoriesType[]? + +@description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') +@allowed([ + '' + 'Dedicated' + 'AzureDiagnostics' +]) +param logAnalyticsDestinationType string = '' + +@description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') +param marketplacePartnerResourceId string? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Location deployment metadata.') +param location string = deployment().location + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.insights-diagnosticsetting.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + location: location + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource diagnosticSetting 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = { + name: name + properties: { + storageAccountId: storageAccountResourceId + workspaceId: workspaceResourceId + eventHubAuthorizationRuleId: eventHubAuthorizationRuleResourceId + eventHubName: eventHubName + logAnalyticsDestinationType: !empty(logAnalyticsDestinationType) ? logAnalyticsDestinationType : null + marketplacePartnerId: marketplacePartnerResourceId + logs: [ + for group in (logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + metrics: [ + for group in (metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + } +} + +@description('The name of the diagnostic settings.') +output name string = diagnosticSetting.name + +@description('The resource ID of the diagnostic settings.') +output resourceId string = diagnosticSetting.id + +@description('The name of the subscription to deploy into.') +output subscriptionName string = subscription().displayName + +// =============== // +// Definitions // +// =============== // + +@description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') +type logCategoriesAndGroupsType = { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? +} + +@description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') +type metricCategoriesType = { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? +} diff --git a/avm/1.1.0/res/insights/diagnostic-setting/main.json b/avm/1.1.0/res/insights/diagnostic-setting/main.json new file mode 100644 index 000000000..3363cf662 --- /dev/null +++ b/avm/1.1.0/res/insights/diagnostic-setting/main.json @@ -0,0 +1,237 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "4069661147816092581" + }, + "name": "Diagnostic Settings (Activity Logs) for Azure Subscriptions", + "description": "This module deploys a Subscription wide export of the Activity Log." + }, + "definitions": { + "logCategoriesAndGroupsType": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + }, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategoriesType": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + }, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + } + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}-diagnosticSettings', uniqueString(subscription().id))]", + "minLength": 1, + "maxLength": 260, + "metadata": { + "description": "Optional. Name of the Diagnostic settings." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/logCategoriesAndGroupsType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "$ref": "#/definitions/metricCategoriesType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Dedicated", + "AzureDiagnostics" + ], + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location deployment metadata." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-diagnosticsetting.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "location": "[parameters('location')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "diagnosticSetting": { + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "name": "[parameters('name')]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(parameters('logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(parameters('logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(parameters('logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(parameters('logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + }, + { + "name": "metrics", + "count": "[length(coalesce(parameters('metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(parameters('metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(parameters('metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[parameters('storageAccountResourceId')]", + "workspaceId": "[parameters('workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[parameters('eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[parameters('eventHubName')]", + "logAnalyticsDestinationType": "[if(not(empty(parameters('logAnalyticsDestinationType'))), parameters('logAnalyticsDestinationType'), null())]", + "marketplacePartnerId": "[parameters('marketplacePartnerResourceId')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the diagnostic settings." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the diagnostic settings." + }, + "value": "[subscriptionResourceId('Microsoft.Insights/diagnosticSettings', parameters('name'))]" + }, + "subscriptionName": { + "type": "string", + "metadata": { + "description": "The name of the subscription to deploy into." + }, + "value": "[subscription().displayName]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/diagnostic-setting/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/insights/diagnostic-setting/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..f1860d657 --- /dev/null +++ b/avm/1.1.0/res/insights/diagnostic-setting/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,62 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.diagnosticsettings-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idsmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + } +] diff --git a/avm/1.1.0/res/insights/diagnostic-setting/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/insights/diagnostic-setting/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..1a489c230 --- /dev/null +++ b/avm/1.1.0/res/insights/diagnostic-setting/tests/e2e/max/main.test.bicep @@ -0,0 +1,70 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.diagnosticsettings-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idsmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + } +] diff --git a/avm/1.1.0/res/insights/diagnostic-setting/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/insights/diagnostic-setting/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..c9cb4fe71 --- /dev/null +++ b/avm/1.1.0/res/insights/diagnostic-setting/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,70 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.diagnosticsettings-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'idswaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + } +] diff --git a/avm/1.1.0/res/insights/diagnostic-setting/version.json b/avm/1.1.0/res/insights/diagnostic-setting/version.json new file mode 100644 index 000000000..83083db69 --- /dev/null +++ b/avm/1.1.0/res/insights/diagnostic-setting/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/metric-alert/README.md b/avm/1.1.0/res/insights/metric-alert/README.md new file mode 100644 index 000000000..7c91321ff --- /dev/null +++ b/avm/1.1.0/res/insights/metric-alert/README.md @@ -0,0 +1,806 @@ +# Metric Alerts `[Microsoft.Insights/metricAlerts]` + +This module deploys a Metric Alert. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/metricAlerts` | [2018-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2018-03-01/metricAlerts) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/insights/metric-alert:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module metricAlert 'br/public:avm/res/insights/metric-alert:' = { + name: 'metricAlertDeployment' + params: { + // Required parameters + criteria: { + allof: [ + { + criterionType: 'StaticThresholdCriterion' + dimensions: [] + metricName: 'Percentage CPU' + name: '1st criterion' + operator: 'GreaterThan' + threshold: 80 + timeAggregation: 'Average' + } + ] + 'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria' + } + name: 'imamin001' + // Non-required parameters + location: 'Global' + scopes: [ + '' + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "criteria": { + "value": { + "allof": [ + { + "criterionType": "StaticThresholdCriterion", + "dimensions": [], + "metricName": "Percentage CPU", + "name": "1st criterion", + "operator": "GreaterThan", + "threshold": 80, + "timeAggregation": "Average" + } + ], + "odata.type": "Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria" + } + }, + "name": { + "value": "imamin001" + }, + // Non-required parameters + "location": { + "value": "Global" + }, + "scopes": { + "value": [ + "" + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/metric-alert:' + +// Required parameters +param criteria = { + allof: [ + { + criterionType: 'StaticThresholdCriterion' + dimensions: [] + metricName: 'Percentage CPU' + name: '1st criterion' + operator: 'GreaterThan' + threshold: 80 + timeAggregation: 'Average' + } + ] + 'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria' +} +param name = 'imamin001' +// Non-required parameters +param location = 'Global' +param scopes = [ + '' +] +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module metricAlert 'br/public:avm/res/insights/metric-alert:' = { + name: 'metricAlertDeployment' + params: { + // Required parameters + criteria: { + allof: [ + { + criterionType: 'StaticThresholdCriterion' + metricName: 'Percentage CPU' + metricNamespace: 'microsoft.compute/virtualmachines' + name: 'HighCPU' + operator: 'GreaterThan' + threshold: '90' + timeAggregation: 'Average' + } + ] + 'odata.type': 'Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria' + } + name: 'imamax001' + // Non-required parameters + actions: [ + '' + ] + location: 'Global' + roleAssignments: [ + { + name: '3ab52119-85d9-4374-a454-2410b84f19f9' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + targetResourceRegion: 'westeurope' + targetResourceType: 'microsoft.compute/virtualmachines' + windowSize: 'PT15M' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "criteria": { + "value": { + "allof": [ + { + "criterionType": "StaticThresholdCriterion", + "metricName": "Percentage CPU", + "metricNamespace": "microsoft.compute/virtualmachines", + "name": "HighCPU", + "operator": "GreaterThan", + "threshold": "90", + "timeAggregation": "Average" + } + ], + "odata.type": "Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria" + } + }, + "name": { + "value": "imamax001" + }, + // Non-required parameters + "actions": { + "value": [ + "" + ] + }, + "location": { + "value": "Global" + }, + "roleAssignments": { + "value": [ + { + "name": "3ab52119-85d9-4374-a454-2410b84f19f9", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "targetResourceRegion": { + "value": "westeurope" + }, + "targetResourceType": { + "value": "microsoft.compute/virtualmachines" + }, + "windowSize": { + "value": "PT15M" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/metric-alert:' + +// Required parameters +param criteria = { + allof: [ + { + criterionType: 'StaticThresholdCriterion' + metricName: 'Percentage CPU' + metricNamespace: 'microsoft.compute/virtualmachines' + name: 'HighCPU' + operator: 'GreaterThan' + threshold: '90' + timeAggregation: 'Average' + } + ] + 'odata.type': 'Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria' +} +param name = 'imamax001' +// Non-required parameters +param actions = [ + '' +] +param location = 'Global' +param roleAssignments = [ + { + name: '3ab52119-85d9-4374-a454-2410b84f19f9' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param targetResourceRegion = 'westeurope' +param targetResourceType = 'microsoft.compute/virtualmachines' +param windowSize = 'PT15M' +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module metricAlert 'br/public:avm/res/insights/metric-alert:' = { + name: 'metricAlertDeployment' + params: { + // Required parameters + criteria: { + componentResourceId: '' + failedLocationCount: 3 + 'odata.type': 'Microsoft.Azure.Monitor.WebtestLocationAvailabilityCriteria' + webTestResourceId: '' + } + name: 'imawaf001' + // Non-required parameters + actions: [ + '' + ] + evaluationFrequency: 'PT5M' + location: 'global' + scopes: [ + '' + '' + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + windowSize: 'PT5M' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "criteria": { + "value": { + "componentResourceId": "", + "failedLocationCount": 3, + "odata.type": "Microsoft.Azure.Monitor.WebtestLocationAvailabilityCriteria", + "webTestResourceId": "" + } + }, + "name": { + "value": "imawaf001" + }, + // Non-required parameters + "actions": { + "value": [ + "" + ] + }, + "evaluationFrequency": { + "value": "PT5M" + }, + "location": { + "value": "global" + }, + "scopes": { + "value": [ + "", + "" + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "windowSize": { + "value": "PT5M" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/metric-alert:' + +// Required parameters +param criteria = { + componentResourceId: '' + failedLocationCount: 3 + 'odata.type': 'Microsoft.Azure.Monitor.WebtestLocationAvailabilityCriteria' + webTestResourceId: '' +} +param name = 'imawaf001' +// Non-required parameters +param actions = [ + '' +] +param evaluationFrequency = 'PT5M' +param location = 'global' +param scopes = [ + '' + '' +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param windowSize = 'PT5M' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`criteria`](#parameter-criteria) | object | Maps to the 'odata.type' field. Specifies the type of the alert criteria. | +| [`name`](#parameter-name) | string | The name of the alert. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`targetResourceRegion`](#parameter-targetresourceregion) | string | The region of the target resource(s) on which the alert is created/updated. Required if alertCriteriaType is MultipleResourceMultipleMetricCriteria. | +| [`targetResourceType`](#parameter-targetresourcetype) | string | The resource type of the target resource(s) on which the alert is created/updated. Required if alertCriteriaType is MultipleResourceMultipleMetricCriteria. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`actions`](#parameter-actions) | array | The list of actions to take when alert triggers. | +| [`alertDescription`](#parameter-alertdescription) | string | Description of the alert. | +| [`autoMitigate`](#parameter-automitigate) | bool | The flag that indicates whether the alert should be auto resolved or not. | +| [`enabled`](#parameter-enabled) | bool | Indicates whether this alert is enabled. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`evaluationFrequency`](#parameter-evaluationfrequency) | string | how often the metric alert is evaluated represented in ISO 8601 duration format. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`scopes`](#parameter-scopes) | array | the list of resource IDs that this metric alert is scoped to. | +| [`severity`](#parameter-severity) | int | The severity of the alert. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`windowSize`](#parameter-windowsize) | string | the period of time (in ISO 8601 duration format) that is used to monitor alert activity based on the threshold. | + +### Parameter: `criteria` + +Maps to the 'odata.type' field. Specifies the type of the alert criteria. + +- Required: Yes +- Type: object + +### Parameter: `name` + +The name of the alert. + +- Required: Yes +- Type: string + +### Parameter: `targetResourceRegion` + +The region of the target resource(s) on which the alert is created/updated. Required if alertCriteriaType is MultipleResourceMultipleMetricCriteria. + +- Required: No +- Type: string + +### Parameter: `targetResourceType` + +The resource type of the target resource(s) on which the alert is created/updated. Required if alertCriteriaType is MultipleResourceMultipleMetricCriteria. + +- Required: No +- Type: string + +### Parameter: `actions` + +The list of actions to take when alert triggers. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `alertDescription` + +Description of the alert. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `autoMitigate` + +The flag that indicates whether the alert should be auto resolved or not. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enabled` + +Indicates whether this alert is enabled. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `evaluationFrequency` + +how often the metric alert is evaluated represented in ISO 8601 duration format. + +- Required: No +- Type: string +- Default: `'PT5M'` +- Allowed: + ```Bicep + [ + 'PT15M' + 'PT1H' + 'PT1M' + 'PT30M' + 'PT5M' + ] + ``` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `'global'` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `scopes` + +the list of resource IDs that this metric alert is scoped to. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + '[subscription().id]' + ] + ``` + +### Parameter: `severity` + +The severity of the alert. + +- Required: No +- Type: int +- Default: `3` +- Allowed: + ```Bicep + [ + 0 + 1 + 2 + 3 + 4 + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `windowSize` + +the period of time (in ISO 8601 duration format) that is used to monitor alert activity based on the threshold. + +- Required: No +- Type: string +- Default: `'PT15M'` +- Allowed: + ```Bicep + [ + 'P1D' + 'PT12H' + 'PT15M' + 'PT1H' + 'PT1M' + 'PT30M' + 'PT5M' + 'PT6H' + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the metric alert. | +| `resourceGroupName` | string | The resource group the metric alert was deployed into. | +| `resourceId` | string | The resource ID of the metric alert. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/insights/metric-alert/main.bicep b/avm/1.1.0/res/insights/metric-alert/main.bicep new file mode 100644 index 000000000..700a26304 --- /dev/null +++ b/avm/1.1.0/res/insights/metric-alert/main.bicep @@ -0,0 +1,204 @@ +metadata name = 'Metric Alerts' +metadata description = 'This module deploys a Metric Alert.' + +@description('Required. The name of the alert.') +param name string + +@description('Optional. Description of the alert.') +param alertDescription string = '' + +@description('Optional. Location for all resources.') +param location string = 'global' + +@description('Optional. Indicates whether this alert is enabled.') +param enabled bool = true + +@description('Optional. The severity of the alert.') +@allowed([ + 0 + 1 + 2 + 3 + 4 +]) +param severity int = 3 + +@description('Optional. how often the metric alert is evaluated represented in ISO 8601 duration format.') +@allowed([ + 'PT1M' + 'PT5M' + 'PT15M' + 'PT30M' + 'PT1H' +]) +param evaluationFrequency string = 'PT5M' + +@description('Optional. the period of time (in ISO 8601 duration format) that is used to monitor alert activity based on the threshold.') +@allowed([ + 'PT1M' + 'PT5M' + 'PT15M' + 'PT30M' + 'PT1H' + 'PT6H' + 'PT12H' + 'P1D' +]) +param windowSize string = 'PT15M' + +@description('Optional. the list of resource IDs that this metric alert is scoped to.') +param scopes array = [ + subscription().id +] + +@description('Conditional. The resource type of the target resource(s) on which the alert is created/updated. Required if alertCriteriaType is MultipleResourceMultipleMetricCriteria.') +param targetResourceType string? + +@description('Conditional. The region of the target resource(s) on which the alert is created/updated. Required if alertCriteriaType is MultipleResourceMultipleMetricCriteria.') +param targetResourceRegion string? + +@description('Optional. The flag that indicates whether the alert should be auto resolved or not.') +param autoMitigate bool = true + +@description('Optional. The list of actions to take when alert triggers.') +param actions array = [] + +@description('Required. Maps to the \'odata.type\' field. Specifies the type of the alert criteria.') +param criteria alertType + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var actionGroups = [ + for action in actions: { + actionGroupId: action.?actionGroupId ?? action + webHookProperties: action.?webHookProperties + } +] + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.insights-metricalert.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource metricAlert 'Microsoft.Insights/metricAlerts@2018-03-01' = { + name: name + location: location + tags: tags + properties: { + description: alertDescription + severity: severity + enabled: enabled + scopes: scopes + evaluationFrequency: evaluationFrequency + windowSize: windowSize + targetResourceType: targetResourceType + targetResourceRegion: targetResourceRegion + criteria: union( + { + 'odata.type': criteria['odata.type'] + }, + (contains(criteria, 'allof') ? { allof: criteria.allof } : {}), + (contains(criteria, 'componentResourceId') ? { componentId: criteria.componentResourceId } : {}), + (contains(criteria, 'failedLocationCount') ? { failedLocationCount: criteria.failedLocationCount } : {}), + (contains(criteria, 'webTestResourceId') ? { webTestId: criteria.webTestResourceId } : {}) + ) + autoMitigate: autoMitigate + actions: actionGroups + } +} + +resource metricAlert_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(metricAlert.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: metricAlert + } +] + +@description('The resource group the metric alert was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the metric alert.') +output name string = metricAlert.name + +@description('The resource ID of the metric alert.') +output resourceId string = metricAlert.id + +@description('The location the resource was deployed into.') +output location string = metricAlert.location + +// =============== // +// Definitions // +// =============== // + +@discriminator('odata.type') +type alertType = alertWebtestType | alertResourceType | alertMultiResourceType +type alertResourceType = { + 'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria' + allof: array +} +type alertMultiResourceType = { + 'odata.type': 'Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria' + allof: array +} +type alertWebtestType = { + 'odata.type': 'Microsoft.Azure.Monitor.WebtestLocationAvailabilityCriteria' + componentResourceId: string + failedLocationCount: int + webTestResourceId: string +} diff --git a/avm/1.1.0/res/insights/metric-alert/main.json b/avm/1.1.0/res/insights/metric-alert/main.json new file mode 100644 index 000000000..22a05a447 --- /dev/null +++ b/avm/1.1.0/res/insights/metric-alert/main.json @@ -0,0 +1,415 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "5542299104437497073" + }, + "name": "Metric Alerts", + "description": "This module deploys a Metric Alert." + }, + "definitions": { + "alertType": { + "type": "object", + "discriminator": { + "propertyName": "odata.type", + "mapping": { + "Microsoft.Azure.Monitor.WebtestLocationAvailabilityCriteria": { + "$ref": "#/definitions/alertWebtestType" + }, + "Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria": { + "$ref": "#/definitions/alertResourceType" + }, + "Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria": { + "$ref": "#/definitions/alertMultiResourceType" + } + } + } + }, + "alertResourceType": { + "type": "object", + "properties": { + "odata.type": { + "type": "string", + "allowedValues": [ + "Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria" + ] + }, + "allof": { + "type": "array" + } + } + }, + "alertMultiResourceType": { + "type": "object", + "properties": { + "odata.type": { + "type": "string", + "allowedValues": [ + "Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria" + ] + }, + "allof": { + "type": "array" + } + } + }, + "alertWebtestType": { + "type": "object", + "properties": { + "odata.type": { + "type": "string", + "allowedValues": [ + "Microsoft.Azure.Monitor.WebtestLocationAvailabilityCriteria" + ] + }, + "componentResourceId": { + "type": "string" + }, + "failedLocationCount": { + "type": "int" + }, + "webTestResourceId": { + "type": "string" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the alert." + } + }, + "alertDescription": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Description of the alert." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether this alert is enabled." + } + }, + "severity": { + "type": "int", + "defaultValue": 3, + "allowedValues": [ + 0, + 1, + 2, + 3, + 4 + ], + "metadata": { + "description": "Optional. The severity of the alert." + } + }, + "evaluationFrequency": { + "type": "string", + "defaultValue": "PT5M", + "allowedValues": [ + "PT1M", + "PT5M", + "PT15M", + "PT30M", + "PT1H" + ], + "metadata": { + "description": "Optional. how often the metric alert is evaluated represented in ISO 8601 duration format." + } + }, + "windowSize": { + "type": "string", + "defaultValue": "PT15M", + "allowedValues": [ + "PT1M", + "PT5M", + "PT15M", + "PT30M", + "PT1H", + "PT6H", + "PT12H", + "P1D" + ], + "metadata": { + "description": "Optional. the period of time (in ISO 8601 duration format) that is used to monitor alert activity based on the threshold." + } + }, + "scopes": { + "type": "array", + "defaultValue": [ + "[subscription().id]" + ], + "metadata": { + "description": "Optional. the list of resource IDs that this metric alert is scoped to." + } + }, + "targetResourceType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource type of the target resource(s) on which the alert is created/updated. Required if alertCriteriaType is MultipleResourceMultipleMetricCriteria." + } + }, + "targetResourceRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The region of the target resource(s) on which the alert is created/updated. Required if alertCriteriaType is MultipleResourceMultipleMetricCriteria." + } + }, + "autoMitigate": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The flag that indicates whether the alert should be auto resolved or not." + } + }, + "actions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The list of actions to take when alert triggers." + } + }, + "criteria": { + "$ref": "#/definitions/alertType", + "metadata": { + "description": "Required. Maps to the 'odata.type' field. Specifies the type of the alert criteria." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "actionGroups", + "count": "[length(parameters('actions'))]", + "input": { + "actionGroupId": "[coalesce(tryGet(parameters('actions')[copyIndex('actionGroups')], 'actionGroupId'), parameters('actions')[copyIndex('actionGroups')])]", + "webHookProperties": "[tryGet(parameters('actions')[copyIndex('actionGroups')], 'webHookProperties')]" + } + }, + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-metricalert.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "metricAlert": { + "type": "Microsoft.Insights/metricAlerts", + "apiVersion": "2018-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "description": "[parameters('alertDescription')]", + "severity": "[parameters('severity')]", + "enabled": "[parameters('enabled')]", + "scopes": "[parameters('scopes')]", + "evaluationFrequency": "[parameters('evaluationFrequency')]", + "windowSize": "[parameters('windowSize')]", + "targetResourceType": "[parameters('targetResourceType')]", + "targetResourceRegion": "[parameters('targetResourceRegion')]", + "criteria": "[union(createObject('odata.type', parameters('criteria')['odata.type']), if(contains(parameters('criteria'), 'allof'), createObject('allof', parameters('criteria').allof), createObject()), if(contains(parameters('criteria'), 'componentResourceId'), createObject('componentId', parameters('criteria').componentResourceId), createObject()), if(contains(parameters('criteria'), 'failedLocationCount'), createObject('failedLocationCount', parameters('criteria').failedLocationCount), createObject()), if(contains(parameters('criteria'), 'webTestResourceId'), createObject('webTestId', parameters('criteria').webTestResourceId), createObject()))]", + "autoMitigate": "[parameters('autoMitigate')]", + "actions": "[variables('actionGroups')]" + } + }, + "metricAlert_roleAssignments": { + "copy": { + "name": "metricAlert_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/metricAlerts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/metricAlerts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "metricAlert" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the metric alert was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the metric alert." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the metric alert." + }, + "value": "[resourceId('Microsoft.Insights/metricAlerts', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('metricAlert', '2018-03-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/metric-alert/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/insights/metric-alert/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..27a18a8ec --- /dev/null +++ b/avm/1.1.0/res/insights/metric-alert/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,78 @@ +@description('Required. Location to deploy resources to.') +param resourceLocation string + +@description('Required. The name of the Virtual Machine to create.') +param virtualMachineName string + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +module vm 'br/public:avm/res/compute/virtual-machine:0.5.3' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${virtualMachineName}' + params: { + location: resourceLocation + name: virtualMachineName + adminUsername: 'localAdminUser' + encryptionAtHost: false + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + zone: 0 + nicConfigurations: [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: virtualNetwork.properties.subnets[0].id + } + ] + nicSuffix: '-nic-01' + } + ] + osDisk: { + diskSizeGB: 128 + caching: 'ReadWrite' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + osType: 'Windows' + vmSize: 'Standard_DS2_v2' + adminPassword: password + } +} + +@description('The resource ID of the created Virtual Machine.') +output virtualMachineResourceId string = vm.outputs.resourceId diff --git a/avm/1.1.0/res/insights/metric-alert/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/insights/metric-alert/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..d3ed8b3f3 --- /dev/null +++ b/avm/1.1.0/res/insights/metric-alert/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,75 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.metricalerts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'imamin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + resourceLocation: resourceLocation + virtualMachineName: '${namePrefix}${serviceShort}001' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'Global' + criteria: { + allof: [ + { + name: '1st criterion' + metricName: 'Percentage CPU' + dimensions: [] + operator: 'GreaterThan' + threshold: 80 + timeAggregation: 'Average' + criterionType: 'StaticThresholdCriterion' + } + ] + 'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria' + } + scopes: [ + nestedDependencies.outputs.virtualMachineResourceId + ] + } + } +] diff --git a/avm/1.1.0/res/insights/metric-alert/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/insights/metric-alert/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..38c9636e2 --- /dev/null +++ b/avm/1.1.0/res/insights/metric-alert/tests/e2e/max/dependencies.bicep @@ -0,0 +1,29 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Action Group to create.') +param actionGroupName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource actionGroup 'Microsoft.Insights/actionGroups@2022-06-01' = { + name: actionGroupName + location: 'global' + + properties: { + enabled: true + groupShortName: substring(actionGroupName, 0, 11) + } +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Action Group.') +output actionGroupResourceId string = actionGroup.id diff --git a/avm/1.1.0/res/insights/metric-alert/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/insights/metric-alert/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..0ace1f32f --- /dev/null +++ b/avm/1.1.0/res/insights/metric-alert/tests/e2e/max/main.test.bicep @@ -0,0 +1,105 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.metricalerts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'imamax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + actionGroupName: 'dep-${namePrefix}-ag-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'Global' + criteria: { + allof: [ + { + criterionType: 'StaticThresholdCriterion' + metricName: 'Percentage CPU' + metricNamespace: 'microsoft.compute/virtualmachines' + name: 'HighCPU' + operator: 'GreaterThan' + threshold: '90' + timeAggregation: 'Average' + } + ] + 'odata.type': 'Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria' + } + actions: [ + nestedDependencies.outputs.actionGroupResourceId + ] + roleAssignments: [ + { + name: '3ab52119-85d9-4374-a454-2410b84f19f9' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + targetResourceRegion: 'westeurope' + targetResourceType: 'microsoft.compute/virtualmachines' + windowSize: 'PT15M' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/insights/metric-alert/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/insights/metric-alert/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..3b74e9208 --- /dev/null +++ b/avm/1.1.0/res/insights/metric-alert/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,79 @@ +@description('Required. The name of the Action Group to create.') +param actionGroupName string + +@description('Required. The name of the Application Insights to create.') +param appInsightsName string + +@description('Required. Location to deploy resources to.') +param resourceLocation string + +resource actionGroup 'Microsoft.Insights/actionGroups@2022-06-01' = { + name: actionGroupName + location: 'global' + + properties: { + enabled: true + groupShortName: substring(actionGroupName, 0, 11) + } +} + +resource appInsights 'Microsoft.Insights/components@2020-02-02' = { + name: appInsightsName + location: resourceLocation + kind: 'web' + properties: { + Application_Type: 'web' + } +} + +resource pingTest 'Microsoft.Insights/webtests@2022-06-15' = { + name: 'PingTest-${toLower(appInsightsName)}' + location: resourceLocation + properties: { + Name: 'PingTest-${toLower(appInsightsName)}' + Description: 'Basic ping test' + Enabled: true + Frequency: 300 + Timeout: 120 + Kind: 'standard' + RetryEnabled: true + Locations: [ + { + Id: 'us-il-ch1-azr' + } + { + Id: 'latam-br-gru-edge' + } + { + Id: 'us-fl-mia-edge' + } + { + Id: 'apac-jp-kaw-edge' + } + { + Id: 'emea-fr-pra-edge' + } + ] + ValidationRules: { + ExpectedHttpStatusCode: 200 + IgnoreHttpStatusCode: false + SSLCheck: false + } + Request: { + RequestUrl: 'https://www.microsoft.com' + HttpVerb: 'GET' + ParseDependentRequests: false + } + SyntheticMonitorId: 'PingTest-${toLower(appInsightsName)}' + } + tags: { + 'hidden-link:${appInsights.id}': 'Resource' + } +} + +@description('The resource ID of the created Action Group.') +output actionGroupResourceId string = actionGroup.id +@description('The resource ID of the created Application Insights.') +output appInsightsResourceId string = appInsights.id +@description('The resource ID of the webtest.') +output pingTestResourceId string = pingTest.id diff --git a/avm/1.1.0/res/insights/metric-alert/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/insights/metric-alert/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..f656e6f10 --- /dev/null +++ b/avm/1.1.0/res/insights/metric-alert/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,78 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.metricalerts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'imawaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + actionGroupName: 'dep-${namePrefix}-ag-${serviceShort}' + appInsightsName: 'dep-${namePrefix}-app-${serviceShort}' + resourceLocation: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + scopes: [ + nestedDependencies.outputs.pingTestResourceId + nestedDependencies.outputs.appInsightsResourceId + ] + criteria: { + componentResourceId: nestedDependencies.outputs.appInsightsResourceId + failedLocationCount: 3 + 'odata.type': 'Microsoft.Azure.Monitor.WebtestLocationAvailabilityCriteria' + webTestResourceId: nestedDependencies.outputs.pingTestResourceId + } + actions: [ + nestedDependencies.outputs.actionGroupResourceId + ] + windowSize: 'PT5M' + evaluationFrequency: 'PT5M' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/insights/metric-alert/version.json b/avm/1.1.0/res/insights/metric-alert/version.json new file mode 100644 index 000000000..c177b1bb5 --- /dev/null +++ b/avm/1.1.0/res/insights/metric-alert/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/private-link-scope/README.md b/avm/1.1.0/res/insights/private-link-scope/README.md new file mode 100644 index 000000000..16fbdbbff --- /dev/null +++ b/avm/1.1.0/res/insights/private-link-scope/README.md @@ -0,0 +1,1842 @@ +# Azure Monitor Private Link Scopes `[microsoft.insights/privateLinkScopes]` + +This module deploys an Azure Monitor Private Link Scope. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `microsoft.insights/privateLinkScopes` | [2021-07-01-preview](https://learn.microsoft.com/en-us/azure/templates/microsoft.insights/2021-07-01-preview/privateLinkScopes) | +| `Microsoft.Insights/privateLinkScopes/scopedResources` | [2021-07-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-07-01-preview/privateLinkScopes/scopedResources) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/insights/private-link-scope:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module privateLinkScope 'br/public:avm/res/insights/private-link-scope:' = { + name: 'privateLinkScopeDeployment' + params: { + // Required parameters + name: 'iplsmin001' + // Non-required parameters + location: 'global' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "iplsmin001" + }, + // Non-required parameters + "location": { + "value": "global" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/private-link-scope:' + +// Required parameters +param name = 'iplsmin001' +// Non-required parameters +param location = 'global' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module privateLinkScope 'br/public:avm/res/insights/private-link-scope:' = { + name: 'privateLinkScopeDeployment' + params: { + // Required parameters + name: 'iplsmax001' + // Non-required parameters + accessModeSettings: { + exclusions: [ + { + ingestionAccessMode: 'PrivateOnly' + privateEndpointConnectionName: 'thisisatest' + queryAccessMode: 'PrivateOnly' + } + ] + ingestionAccessMode: 'Open' + queryAccessMode: 'Open' + } + location: 'global' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + privateEndpoints: [ + { + customNetworkInterfaceName: 'nic-pe-' + ipConfigurations: [ + { + name: 'api' + properties: { + groupId: 'azuremonitor' + memberName: 'api' + privateIPAddress: '10.0.0.11' + } + } + { + name: 'globalinai' + properties: { + groupId: 'azuremonitor' + memberName: 'global.in.ai' + privateIPAddress: '10.0.0.12' + } + } + { + name: 'profiler' + properties: { + groupId: 'azuremonitor' + memberName: 'profiler' + privateIPAddress: '10.0.0.13' + } + } + { + name: 'live' + properties: { + groupId: 'azuremonitor' + memberName: 'live' + privateIPAddress: '10.0.0.14' + } + } + { + name: 'diagservicesquery' + properties: { + groupId: 'azuremonitor' + memberName: 'diagservicesquery' + privateIPAddress: '10.0.0.15' + } + } + { + name: 'snapshot' + properties: { + groupId: 'azuremonitor' + memberName: 'snapshot' + privateIPAddress: '10.0.0.16' + } + } + { + name: 'agentsolutionpackstore' + properties: { + groupId: 'azuremonitor' + memberName: 'agentsolutionpackstore' + privateIPAddress: '10.0.0.17' + } + } + { + name: 'dce-global' + properties: { + groupId: 'azuremonitor' + memberName: 'dce-global' + privateIPAddress: '10.0.0.18' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.19' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.20' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.21' + } + } + ] + name: 'pe-' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + roleAssignments: [ + { + name: 'af62023f-9f34-4bc0-8f05-2374886daf28' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + scopedResources: [ + { + linkedResourceId: '' + name: 'scoped1' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "iplsmax001" + }, + // Non-required parameters + "accessModeSettings": { + "value": { + "exclusions": [ + { + "ingestionAccessMode": "PrivateOnly", + "privateEndpointConnectionName": "thisisatest", + "queryAccessMode": "PrivateOnly" + } + ], + "ingestionAccessMode": "Open", + "queryAccessMode": "Open" + } + }, + "location": { + "value": "global" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "privateEndpoints": { + "value": [ + { + "customNetworkInterfaceName": "nic-pe-", + "ipConfigurations": [ + { + "name": "api", + "properties": { + "groupId": "azuremonitor", + "memberName": "api", + "privateIPAddress": "10.0.0.11" + } + }, + { + "name": "globalinai", + "properties": { + "groupId": "azuremonitor", + "memberName": "global.in.ai", + "privateIPAddress": "10.0.0.12" + } + }, + { + "name": "profiler", + "properties": { + "groupId": "azuremonitor", + "memberName": "profiler", + "privateIPAddress": "10.0.0.13" + } + }, + { + "name": "live", + "properties": { + "groupId": "azuremonitor", + "memberName": "live", + "privateIPAddress": "10.0.0.14" + } + }, + { + "name": "diagservicesquery", + "properties": { + "groupId": "azuremonitor", + "memberName": "diagservicesquery", + "privateIPAddress": "10.0.0.15" + } + }, + { + "name": "snapshot", + "properties": { + "groupId": "azuremonitor", + "memberName": "snapshot", + "privateIPAddress": "10.0.0.16" + } + }, + { + "name": "agentsolutionpackstore", + "properties": { + "groupId": "azuremonitor", + "memberName": "agentsolutionpackstore", + "privateIPAddress": "10.0.0.17" + } + }, + { + "name": "dce-global", + "properties": { + "groupId": "azuremonitor", + "memberName": "dce-global", + "privateIPAddress": "10.0.0.18" + } + }, + { + "name": "", + "properties": { + "groupId": "azuremonitor", + "memberName": "", + "privateIPAddress": "10.0.0.19" + } + }, + { + "name": "", + "properties": { + "groupId": "azuremonitor", + "memberName": "", + "privateIPAddress": "10.0.0.20" + } + }, + { + "name": "", + "properties": { + "groupId": "azuremonitor", + "memberName": "", + "privateIPAddress": "10.0.0.21" + } + } + ], + "name": "pe-", + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "af62023f-9f34-4bc0-8f05-2374886daf28", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "scopedResources": { + "value": [ + { + "linkedResourceId": "", + "name": "scoped1" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/private-link-scope:' + +// Required parameters +param name = 'iplsmax001' +// Non-required parameters +param accessModeSettings = { + exclusions: [ + { + ingestionAccessMode: 'PrivateOnly' + privateEndpointConnectionName: 'thisisatest' + queryAccessMode: 'PrivateOnly' + } + ] + ingestionAccessMode: 'Open' + queryAccessMode: 'Open' +} +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + customNetworkInterfaceName: 'nic-pe-' + ipConfigurations: [ + { + name: 'api' + properties: { + groupId: 'azuremonitor' + memberName: 'api' + privateIPAddress: '10.0.0.11' + } + } + { + name: 'globalinai' + properties: { + groupId: 'azuremonitor' + memberName: 'global.in.ai' + privateIPAddress: '10.0.0.12' + } + } + { + name: 'profiler' + properties: { + groupId: 'azuremonitor' + memberName: 'profiler' + privateIPAddress: '10.0.0.13' + } + } + { + name: 'live' + properties: { + groupId: 'azuremonitor' + memberName: 'live' + privateIPAddress: '10.0.0.14' + } + } + { + name: 'diagservicesquery' + properties: { + groupId: 'azuremonitor' + memberName: 'diagservicesquery' + privateIPAddress: '10.0.0.15' + } + } + { + name: 'snapshot' + properties: { + groupId: 'azuremonitor' + memberName: 'snapshot' + privateIPAddress: '10.0.0.16' + } + } + { + name: 'agentsolutionpackstore' + properties: { + groupId: 'azuremonitor' + memberName: 'agentsolutionpackstore' + privateIPAddress: '10.0.0.17' + } + } + { + name: 'dce-global' + properties: { + groupId: 'azuremonitor' + memberName: 'dce-global' + privateIPAddress: '10.0.0.18' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.19' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.20' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.21' + } + } + ] + name: 'pe-' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param roleAssignments = [ + { + name: 'af62023f-9f34-4bc0-8f05-2374886daf28' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scopedResources = [ + { + linkedResourceId: '' + name: 'scoped1' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module privateLinkScope 'br/public:avm/res/insights/private-link-scope:' = { + name: 'privateLinkScopeDeployment' + params: { + // Required parameters + name: 'iplswaf001' + // Non-required parameters + location: 'global' + privateEndpoints: [ + { + customNetworkInterfaceName: 'nic-pe-' + ipConfigurations: [ + { + name: 'api' + properties: { + groupId: 'azuremonitor' + memberName: 'api' + privateIPAddress: '10.0.0.11' + } + } + { + name: 'globalinai' + properties: { + groupId: 'azuremonitor' + memberName: 'global.in.ai' + privateIPAddress: '10.0.0.12' + } + } + { + name: 'profiler' + properties: { + groupId: 'azuremonitor' + memberName: 'profiler' + privateIPAddress: '10.0.0.13' + } + } + { + name: 'live' + properties: { + groupId: 'azuremonitor' + memberName: 'live' + privateIPAddress: '10.0.0.14' + } + } + { + name: 'diagservicesquery' + properties: { + groupId: 'azuremonitor' + memberName: 'diagservicesquery' + privateIPAddress: '10.0.0.15' + } + } + { + name: 'snapshot' + properties: { + groupId: 'azuremonitor' + memberName: 'snapshot' + privateIPAddress: '10.0.0.16' + } + } + { + name: 'agentsolutionpackstore' + properties: { + groupId: 'azuremonitor' + memberName: 'agentsolutionpackstore' + privateIPAddress: '10.0.0.17' + } + } + { + name: 'dce-global' + properties: { + groupId: 'azuremonitor' + memberName: 'dce-global' + privateIPAddress: '10.0.0.18' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.19' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.20' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.21' + } + } + ] + name: 'pe-' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + scopedResources: [ + { + linkedResourceId: '' + name: 'scoped1' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "iplswaf001" + }, + // Non-required parameters + "location": { + "value": "global" + }, + "privateEndpoints": { + "value": [ + { + "customNetworkInterfaceName": "nic-pe-", + "ipConfigurations": [ + { + "name": "api", + "properties": { + "groupId": "azuremonitor", + "memberName": "api", + "privateIPAddress": "10.0.0.11" + } + }, + { + "name": "globalinai", + "properties": { + "groupId": "azuremonitor", + "memberName": "global.in.ai", + "privateIPAddress": "10.0.0.12" + } + }, + { + "name": "profiler", + "properties": { + "groupId": "azuremonitor", + "memberName": "profiler", + "privateIPAddress": "10.0.0.13" + } + }, + { + "name": "live", + "properties": { + "groupId": "azuremonitor", + "memberName": "live", + "privateIPAddress": "10.0.0.14" + } + }, + { + "name": "diagservicesquery", + "properties": { + "groupId": "azuremonitor", + "memberName": "diagservicesquery", + "privateIPAddress": "10.0.0.15" + } + }, + { + "name": "snapshot", + "properties": { + "groupId": "azuremonitor", + "memberName": "snapshot", + "privateIPAddress": "10.0.0.16" + } + }, + { + "name": "agentsolutionpackstore", + "properties": { + "groupId": "azuremonitor", + "memberName": "agentsolutionpackstore", + "privateIPAddress": "10.0.0.17" + } + }, + { + "name": "dce-global", + "properties": { + "groupId": "azuremonitor", + "memberName": "dce-global", + "privateIPAddress": "10.0.0.18" + } + }, + { + "name": "", + "properties": { + "groupId": "azuremonitor", + "memberName": "", + "privateIPAddress": "10.0.0.19" + } + }, + { + "name": "", + "properties": { + "groupId": "azuremonitor", + "memberName": "", + "privateIPAddress": "10.0.0.20" + } + }, + { + "name": "", + "properties": { + "groupId": "azuremonitor", + "memberName": "", + "privateIPAddress": "10.0.0.21" + } + } + ], + "name": "pe-", + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + ] + }, + "scopedResources": { + "value": [ + { + "linkedResourceId": "", + "name": "scoped1" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/private-link-scope:' + +// Required parameters +param name = 'iplswaf001' +// Non-required parameters +param location = 'global' +param privateEndpoints = [ + { + customNetworkInterfaceName: 'nic-pe-' + ipConfigurations: [ + { + name: 'api' + properties: { + groupId: 'azuremonitor' + memberName: 'api' + privateIPAddress: '10.0.0.11' + } + } + { + name: 'globalinai' + properties: { + groupId: 'azuremonitor' + memberName: 'global.in.ai' + privateIPAddress: '10.0.0.12' + } + } + { + name: 'profiler' + properties: { + groupId: 'azuremonitor' + memberName: 'profiler' + privateIPAddress: '10.0.0.13' + } + } + { + name: 'live' + properties: { + groupId: 'azuremonitor' + memberName: 'live' + privateIPAddress: '10.0.0.14' + } + } + { + name: 'diagservicesquery' + properties: { + groupId: 'azuremonitor' + memberName: 'diagservicesquery' + privateIPAddress: '10.0.0.15' + } + } + { + name: 'snapshot' + properties: { + groupId: 'azuremonitor' + memberName: 'snapshot' + privateIPAddress: '10.0.0.16' + } + } + { + name: 'agentsolutionpackstore' + properties: { + groupId: 'azuremonitor' + memberName: 'agentsolutionpackstore' + privateIPAddress: '10.0.0.17' + } + } + { + name: 'dce-global' + properties: { + groupId: 'azuremonitor' + memberName: 'dce-global' + privateIPAddress: '10.0.0.18' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.19' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.20' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.21' + } + } + ] + name: 'pe-' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param scopedResources = [ + { + linkedResourceId: '' + name: 'scoped1' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the private link scope. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`accessModeSettings`](#parameter-accessmodesettings) | object | Specifies the access mode of ingestion or queries through associated private endpoints in scope. For security reasons, it is recommended to use PrivateOnly whenever possible to avoid data exfiltration.

* Private Only - This mode allows the connected virtual network to reach only Private Link resources. It is the most secure mode and is set as the default when the `privateEndpoints` parameter is configured.

* Open - Allows the connected virtual network to reach both Private Link resources and the resources not in the AMPLS resource. Data exfiltration cannot be prevented in this mode. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | The location of the private link scope. Should be global. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`scopedResources`](#parameter-scopedresources) | array | Configuration details for Azure Monitor Resources. | +| [`tags`](#parameter-tags) | object | Resource tags. | + +### Parameter: `name` + +Name of the private link scope. + +- Required: Yes +- Type: string + +### Parameter: `accessModeSettings` + +Specifies the access mode of ingestion or queries through associated private endpoints in scope. For security reasons, it is recommended to use PrivateOnly whenever possible to avoid data exfiltration.

* Private Only - This mode allows the connected virtual network to reach only Private Link resources. It is the most secure mode and is set as the default when the `privateEndpoints` parameter is configured.

* Open - Allows the connected virtual network to reach both Private Link resources and the resources not in the AMPLS resource. Data exfiltration cannot be prevented in this mode. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`exclusions`](#parameter-accessmodesettingsexclusions) | array | List of exclusions that override the default access mode settings for specific private endpoint connections. Exclusions for the current created Private endpoints can only be applied post initial provisioning. | +| [`ingestionAccessMode`](#parameter-accessmodesettingsingestionaccessmode) | string | Specifies the default access mode of ingestion through associated private endpoints in scope. Default is "Open" if no private endpoints are configured and will be set to "PrivateOnly" if private endpoints are configured. Override default behaviour by explicitly providing a value. | +| [`queryAccessMode`](#parameter-accessmodesettingsqueryaccessmode) | string | Specifies the default access mode of queries through associated private endpoints in scope. Default is "Open" if no private endpoints are configured and will be set to "PrivateOnly" if private endpoints are configured. Override default behaviour by explicitly providing a value. | + +### Parameter: `accessModeSettings.exclusions` + +List of exclusions that override the default access mode settings for specific private endpoint connections. Exclusions for the current created Private endpoints can only be applied post initial provisioning. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ingestionAccessMode`](#parameter-accessmodesettingsexclusionsingestionaccessmode) | string | Specifies the access mode of ingestion through the specified private endpoint connection in the exclusion. | +| [`privateEndpointConnectionName`](#parameter-accessmodesettingsexclusionsprivateendpointconnectionname) | string | The private endpoint connection name associated to the private endpoint on which we want to apply the specific access mode settings. | +| [`queryAccessMode`](#parameter-accessmodesettingsexclusionsqueryaccessmode) | string | Specifies the access mode of queries through the specified private endpoint connection in the exclusion. | + +### Parameter: `accessModeSettings.exclusions.ingestionAccessMode` + +Specifies the access mode of ingestion through the specified private endpoint connection in the exclusion. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Open' + 'PrivateOnly' + ] + ``` + +### Parameter: `accessModeSettings.exclusions.privateEndpointConnectionName` + +The private endpoint connection name associated to the private endpoint on which we want to apply the specific access mode settings. + +- Required: Yes +- Type: string + +### Parameter: `accessModeSettings.exclusions.queryAccessMode` + +Specifies the access mode of queries through the specified private endpoint connection in the exclusion. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Open' + 'PrivateOnly' + ] + ``` + +### Parameter: `accessModeSettings.ingestionAccessMode` + +Specifies the default access mode of ingestion through associated private endpoints in scope. Default is "Open" if no private endpoints are configured and will be set to "PrivateOnly" if private endpoints are configured. Override default behaviour by explicitly providing a value. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Open' + 'PrivateOnly' + ] + ``` + +### Parameter: `accessModeSettings.queryAccessMode` + +Specifies the default access mode of queries through associated private endpoints in scope. Default is "Open" if no private endpoints are configured and will be set to "PrivateOnly" if private endpoints are configured. Override default behaviour by explicitly providing a value. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Open' + 'PrivateOnly' + ] + ``` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +The location of the private link scope. Should be global. + +- Required: No +- Type: string +- Default: `'global'` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints` + +Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationSecurityGroupResourceIds`](#parameter-privateendpointsapplicationsecuritygroupresourceids) | array | Application security groups in which the Private Endpoint IP configuration is included. | +| [`customDnsConfigs`](#parameter-privateendpointscustomdnsconfigs) | array | Custom DNS configurations. | +| [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the Private Endpoint. | +| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | +| [`location`](#parameter-privateendpointslocation) | string | The location to deploy the Private Endpoint to. | +| [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | +| [`name`](#parameter-privateendpointsname) | string | The name of the Private Endpoint. | +| [`privateDnsZoneGroup`](#parameter-privateendpointsprivatednszonegroup) | object | The private DNS Zone Group to configure for the Private Endpoint. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | +| [`resourceGroupResourceId`](#parameter-privateendpointsresourcegroupresourceid) | string | The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the Private Endpoint for. For example "vault" for a Key Vault Private Endpoint. | +| [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/Resource Groups in this deployment. | + +### Parameter: `privateEndpoints.subnetResourceId` + +Resource ID of the subnet where the endpoint needs to be created. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.applicationSecurityGroupResourceIds` + +Application security groups in which the Private Endpoint IP configuration is included. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs` + +Custom DNS configurations. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | FQDN that resolves to private endpoint IP address. | + +### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +A list of private IP addresses of the private endpoint. + +- Required: Yes +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +FQDN that resolves to private endpoint IP address. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.customNetworkInterfaceName` + +The custom name of the network interface attached to the Private Endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.ipConfigurations` + +A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsipconfigurationsname) | string | The name of the resource that is unique within a resource group. | +| [`properties`](#parameter-privateendpointsipconfigurationsproperties) | object | Properties of private endpoint IP configurations. | + +### Parameter: `privateEndpoints.ipConfigurations.name` + +The name of the resource that is unique within a resource group. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties` + +Properties of private endpoint IP configurations. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private IP address obtained from the private endpoint's subnet. | + +### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` + +The ID of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.memberName` + +The member name of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` + +A private IP address obtained from the private endpoint's subnet. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.location` + +The location to deploy the Private Endpoint to. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.lock` + +Specify the type of lock. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-privateendpointslockkind) | string | Specify the type of lock. | +| [`name`](#parameter-privateendpointslockname) | string | Specify the name of lock. | + +### Parameter: `privateEndpoints.lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `privateEndpoints.lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.manualConnectionRequestMessage` + +A message passed to the owner of the remote resource with the manual connection request. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.name` + +The name of the Private Endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup` + +The private DNS Zone Group to configure for the Private Endpoint. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneGroupConfigs`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigs) | array | The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the Private DNS Zone Group. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs` + +The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneResourceId`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsprivatednszoneresourceid) | string | The resource id of the private DNS zone. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsname) | string | The name of the private DNS Zone Group config. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.privateDnsZoneResourceId` + +The resource id of the private DNS zone. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.name` + +The name of the private DNS Zone Group config. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.name` + +The name of the Private DNS Zone Group. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.resourceGroupResourceId` + +The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-privateendpointsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-privateendpointsroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-privateendpointsroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-privateendpointsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-privateendpointsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-privateendpointsroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-privateendpointsroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-privateendpointsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `privateEndpoints.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `privateEndpoints.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `privateEndpoints.service` + +The subresource to deploy the Private Endpoint for. For example "vault" for a Key Vault Private Endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.tags` + +Tags to be applied on all resources/Resource Groups in this deployment. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Log Analytics Contributor'` + - `'Log Analytics Reader'` + - `'Logic App Contributor'` + - `'Monitoring Contributor'` + - `'Monitoring Metrics Publisher'` + - `'Monitoring Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'Tag Contributor'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `scopedResources` + +Configuration details for Azure Monitor Resources. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`linkedResourceId`](#parameter-scopedresourceslinkedresourceid) | string | The resource ID of the scoped Azure monitor resource. | +| [`name`](#parameter-scopedresourcesname) | string | Name of the private link scoped resource. | + +### Parameter: `scopedResources.linkedResourceId` + +The resource ID of the scoped Azure monitor resource. + +- Required: Yes +- Type: string + +### Parameter: `scopedResources.name` + +Name of the private link scoped resource. + +- Required: Yes +- Type: string + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the private link scope. | +| `privateEndpoints` | array | The private endpoints of the private link scope. | +| `resourceGroupName` | string | The resource group the private link scope was deployed into. | +| `resourceId` | string | The resource ID of the private link scope. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/private-endpoint:0.10.1` | Remote reference | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/insights/private-link-scope/main.bicep b/avm/1.1.0/res/insights/private-link-scope/main.bicep new file mode 100644 index 000000000..c06154129 --- /dev/null +++ b/avm/1.1.0/res/insights/private-link-scope/main.bicep @@ -0,0 +1,313 @@ +metadata name = 'Azure Monitor Private Link Scopes' +metadata description = 'This module deploys an Azure Monitor Private Link Scope.' + +@description('Required. Name of the private link scope.') +@minLength(1) +param name string + +@description('''Optional. Specifies the access mode of ingestion or queries through associated private endpoints in scope. For security reasons, it is recommended to use PrivateOnly whenever possible to avoid data exfiltration. + + * Private Only - This mode allows the connected virtual network to reach only Private Link resources. It is the most secure mode and is set as the default when the `privateEndpoints` parameter is configured. + * Open - Allows the connected virtual network to reach both Private Link resources and the resources not in the AMPLS resource. Data exfiltration cannot be prevented in this mode.''') +param accessModeSettings accessModeType? + +@description('Optional. The location of the private link scope. Should be global.') +param location string = 'global' + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Configuration details for Azure Monitor Resources.') +param scopedResources scopedResourceType[]? + +import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointSingleServiceType[]? + +@description('Optional. Resource tags.') +param tags object? + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +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' + ) + 'Logic App Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '87a39d53-fc1b-424a-814c-f7e04687dc9e' + ) + 'Monitoring Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '749f88d5-cbae-40b8-bcfc-e573ddc772fa' + ) + 'Monitoring Metrics Publisher': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '3913510d-42f4-4e42-8a64-420c390055eb' + ) + 'Monitoring Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '43d0d8ad-25c7-4714-9337-8ba259a9fe05' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'Tag Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4a9ae827-6dc8-4573-8ac7-8239d42aa03f' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.insights-privatelinkscope.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource privateLinkScope 'microsoft.insights/privateLinkScopes@2021-07-01-preview' = { + name: name + location: location + tags: tags + properties: { + accessModeSettings: accessModeSettings ?? (!empty(privateEndpoints) + ? { + ingestionAccessMode: 'PrivateOnly' + queryAccessMode: 'PrivateOnly' + } + : { + ingestionAccessMode: 'Open' + queryAccessMode: 'Open' + }) + } +} + +module privateLinkScope_scopedResource 'scoped-resource/main.bicep' = [ + for (scopedResource, index) in (scopedResources ?? []): { + name: '${uniqueString(deployment().name, location)}-PrivateLinkScope-ScopedResource-${index}' + params: { + name: scopedResource.name + privateLinkScopeName: privateLinkScope.name + linkedResourceId: scopedResource.linkedResourceId + } + } +] + +resource privateLinkScope_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: privateLinkScope +} + +module privateLinkScope_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.10.1' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-privateLinkScope-PrivateEndpoint-${index}' + // use the subnet resource group if the resource group is not explicitly provided + scope: resourceGroup( + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[2], + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[4] + ) + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(privateLinkScope.id, '/'))}-${privateEndpoint.?service ?? 'azuremonitor'}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(privateLinkScope.id, '/'))}-${privateEndpoint.?service ?? 'azuremonitor'}-${index}' + properties: { + privateLinkServiceId: privateLinkScope.id + groupIds: [ + privateEndpoint.?service ?? 'azuremonitor' + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(privateLinkScope.id, '/'))}-${privateEndpoint.?service ?? 'azuremonitor'}-${index}' + properties: { + privateLinkServiceId: privateLinkScope.id + groupIds: [ + privateEndpoint.?service ?? 'azuremonitor' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] + : null + subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry + location: privateEndpoint.?location ?? reference( + split(privateEndpoint.subnetResourceId, '/subnets/')[0], + '2020-06-01', + 'Full' + ).location + lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } + dependsOn: [ + privateLinkScope_scopedResource + ] + } +] + +resource privateLinkScope_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(privateLinkScope.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: privateLinkScope + } +] + +@description('The name of the private link scope.') +output name string = privateLinkScope.name + +@description('The resource ID of the private link scope.') +output resourceId string = privateLinkScope.id + +@description('The resource group the private link scope was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = privateLinkScope.location + +@description('The private endpoints of the private link scope.') +output privateEndpoints privateEndpointOutputType[] = [ + for (item, index) in (privateEndpoints ?? []): { + name: privateLinkScope_privateEndpoints[index].outputs.name + resourceId: privateLinkScope_privateEndpoints[index].outputs.resourceId + groupId: privateLinkScope_privateEndpoints[index].outputs.?groupId! + customDnsConfigs: privateLinkScope_privateEndpoints[index].outputs.customDnsConfigs + networkInterfaceResourceIds: privateLinkScope_privateEndpoints[index].outputs.networkInterfaceResourceIds + } +] + +// =============== // +// Definitions // +// =============== // + +@export() +type privateEndpointOutputType = { + @description('The name of the private endpoint.') + name: string + + @description('The resource ID of the private endpoint.') + resourceId: string + + @description('The group Id for the private endpoint Group.') + groupId: string? + + @description('The custom DNS configurations of the private endpoint.') + customDnsConfigs: { + @description('FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @description('A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[] + + @description('The IDs of the network interfaces associated with the private endpoint.') + networkInterfaceResourceIds: string[] +} + +@export() +@description('The scoped resource type.') +type scopedResourceType = { + @description('Required. Name of the private link scoped resource.') + name: string + + @description('Required. The resource ID of the scoped Azure monitor resource.') + linkedResourceId: string +} + +@export() +@description('The access mode type.') +type accessModeType = { + @description('Optional. List of exclusions that override the default access mode settings for specific private endpoint connections. Exclusions for the current created Private endpoints can only be applied post initial provisioning.') + exclusions: { + @description('Required. The private endpoint connection name associated to the private endpoint on which we want to apply the specific access mode settings.') + privateEndpointConnectionName: string + + @description('Required. Specifies the access mode of ingestion through the specified private endpoint connection in the exclusion.') + ingestionAccessMode: 'Open' | 'PrivateOnly' + + @description('Required. Specifies the access mode of queries through the specified private endpoint connection in the exclusion.') + queryAccessMode: 'Open' | 'PrivateOnly' + }[]? + + @description('Optional. Specifies the default access mode of ingestion through associated private endpoints in scope. Default is "Open" if no private endpoints are configured and will be set to "PrivateOnly" if private endpoints are configured. Override default behaviour by explicitly providing a value.') + ingestionAccessMode: 'Open' | 'PrivateOnly'? + + @description('Optional. Specifies the default access mode of queries through associated private endpoints in scope. Default is "Open" if no private endpoints are configured and will be set to "PrivateOnly" if private endpoints are configured. Override default behaviour by explicitly providing a value.') + queryAccessMode: 'Open' | 'PrivateOnly'? +} diff --git a/avm/1.1.0/res/insights/private-link-scope/main.json b/avm/1.1.0/res/insights/private-link-scope/main.json new file mode 100644 index 000000000..589aebaee --- /dev/null +++ b/avm/1.1.0/res/insights/private-link-scope/main.json @@ -0,0 +1,1596 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "5613742865192153837" + }, + "name": "Azure Monitor Private Link Scopes", + "description": "This module deploys an Azure Monitor Private Link Scope." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "scopedResourceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private link scoped resource." + } + }, + "linkedResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scoped Azure monitor resource." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The scoped resource type." + } + }, + "accessModeType": { + "type": "object", + "properties": { + "exclusions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "privateEndpointConnectionName": { + "type": "string", + "metadata": { + "description": "Required. The private endpoint connection name associated to the private endpoint on which we want to apply the specific access mode settings." + } + }, + "ingestionAccessMode": { + "type": "string", + "allowedValues": [ + "Open", + "PrivateOnly" + ], + "metadata": { + "description": "Required. Specifies the access mode of ingestion through the specified private endpoint connection in the exclusion." + } + }, + "queryAccessMode": { + "type": "string", + "allowedValues": [ + "Open", + "PrivateOnly" + ], + "metadata": { + "description": "Required. Specifies the access mode of queries through the specified private endpoint connection in the exclusion." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. List of exclusions that override the default access mode settings for specific private endpoint connections. Exclusions for the current created Private endpoints can only be applied post initial provisioning." + } + }, + "ingestionAccessMode": { + "type": "string", + "allowedValues": [ + "Open", + "PrivateOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default access mode of ingestion through associated private endpoints in scope. Default is \"Open\" if no private endpoints are configured and will be set to \"PrivateOnly\" if private endpoints are configured. Override default behaviour by explicitly providing a value." + } + }, + "queryAccessMode": { + "type": "string", + "allowedValues": [ + "Open", + "PrivateOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default access mode of queries through associated private endpoints in scope. Default is \"Open\" if no private endpoints are configured and will be set to \"PrivateOnly\" if private endpoints are configured. Override default behaviour by explicitly providing a value." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The access mode type." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the private link scope." + } + }, + "accessModeSettings": { + "$ref": "#/definitions/accessModeType", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the access mode of ingestion or queries through associated private endpoints in scope. For security reasons, it is recommended to use PrivateOnly whenever possible to avoid data exfiltration.\n\n* Private Only - This mode allows the connected virtual network to reach only Private Link resources. It is the most secure mode and is set as the default when the `privateEndpoints` parameter is configured.\n* Open - Allows the connected virtual network to reach both Private Link resources and the resources not in the AMPLS resource. Data exfiltration cannot be prevented in this mode." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the private link scope. Should be global." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "scopedResources": { + "type": "array", + "items": { + "$ref": "#/definitions/scopedResourceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for Azure Monitor Resources." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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')]", + "Logic App Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '87a39d53-fc1b-424a-814c-f7e04687dc9e')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Tag Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4a9ae827-6dc8-4573-8ac7-8239d42aa03f')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-privatelinkscope.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateLinkScope": { + "type": "microsoft.insights/privateLinkScopes", + "apiVersion": "2021-07-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "accessModeSettings": "[coalesce(parameters('accessModeSettings'), if(not(empty(parameters('privateEndpoints'))), createObject('ingestionAccessMode', 'PrivateOnly', 'queryAccessMode', 'PrivateOnly'), createObject('ingestionAccessMode', 'Open', 'queryAccessMode', 'Open')))]" + } + }, + "privateLinkScope_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('microsoft.insights/privateLinkScopes/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateLinkScope" + ] + }, + "privateLinkScope_roleAssignments": { + "copy": { + "name": "privateLinkScope_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('microsoft.insights/privateLinkScopes/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('microsoft.insights/privateLinkScopes', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateLinkScope" + ] + }, + "privateLinkScope_scopedResource": { + "copy": { + "name": "privateLinkScope_scopedResource", + "count": "[length(coalesce(parameters('scopedResources'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateLinkScope-ScopedResource-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('scopedResources'), createArray())[copyIndex()].name]" + }, + "privateLinkScopeName": { + "value": "[parameters('name')]" + }, + "linkedResourceId": { + "value": "[coalesce(parameters('scopedResources'), createArray())[copyIndex()].linkedResourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "16373447809622934069" + }, + "name": "Private Link Scope Scoped Resources", + "description": "This module deploys a Private Link Scope Scoped Resource." + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the private link scoped resource." + } + }, + "privateLinkScopeName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Conditional. The name of the parent private link scope. Required if the template is used in a standalone deployment." + } + }, + "linkedResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scoped Azure monitor resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Insights/privateLinkScopes/scopedResources", + "apiVersion": "2021-07-01-preview", + "name": "[format('{0}/{1}', parameters('privateLinkScopeName'), parameters('name'))]", + "properties": { + "linkedResourceId": "[parameters('linkedResourceId')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group where the resource has been deployed." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed scopedResource." + }, + "value": "[resourceId('Microsoft.Insights/privateLinkScopes/scopedResources', parameters('privateLinkScopeName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The full name of the deployed Scoped Resource." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "privateLinkScope" + ] + }, + "privateLinkScope_privateEndpoints": { + "copy": { + "name": "privateLinkScope_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-privateLinkScope-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('microsoft.insights/privateLinkScopes', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'azuremonitor'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('microsoft.insights/privateLinkScopes', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'azuremonitor'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('microsoft.insights/privateLinkScopes', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'azuremonitor')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('microsoft.insights/privateLinkScopes', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'azuremonitor'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('microsoft.insights/privateLinkScopes', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'azuremonitor')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "15954548978129725136" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.10.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "5440815542537978381" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "privateLinkScope", + "privateLinkScope_scopedResource" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private link scope." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private link scope." + }, + "value": "[resourceId('microsoft.insights/privateLinkScopes', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private link scope was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateLinkScope', '2021-07-01-preview', 'full').location]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the private link scope." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('privateLinkScope_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('privateLinkScope_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('privateLinkScope_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('privateLinkScope_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('privateLinkScope_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/private-link-scope/scoped-resource/README.md b/avm/1.1.0/res/insights/private-link-scope/scoped-resource/README.md new file mode 100644 index 000000000..ff22976c9 --- /dev/null +++ b/avm/1.1.0/res/insights/private-link-scope/scoped-resource/README.md @@ -0,0 +1,59 @@ +# Private Link Scope Scoped Resources `[Microsoft.Insights/privateLinkScopes/scopedResources]` + +This module deploys a Private Link Scope Scoped Resource. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Insights/privateLinkScopes/scopedResources` | [2021-07-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-07-01-preview/privateLinkScopes/scopedResources) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`linkedResourceId`](#parameter-linkedresourceid) | string | The resource ID of the scoped Azure monitor resource. | +| [`name`](#parameter-name) | string | Name of the private link scoped resource. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateLinkScopeName`](#parameter-privatelinkscopename) | string | The name of the parent private link scope. Required if the template is used in a standalone deployment. | + +### Parameter: `linkedResourceId` + +The resource ID of the scoped Azure monitor resource. + +- Required: Yes +- Type: string + +### Parameter: `name` + +Name of the private link scoped resource. + +- Required: Yes +- Type: string + +### Parameter: `privateLinkScopeName` + +The name of the parent private link scope. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The full name of the deployed Scoped Resource. | +| `resourceGroupName` | string | The name of the resource group where the resource has been deployed. | +| `resourceId` | string | The resource ID of the deployed scopedResource. | diff --git a/avm/1.1.0/res/insights/private-link-scope/scoped-resource/main.bicep b/avm/1.1.0/res/insights/private-link-scope/scoped-resource/main.bicep new file mode 100644 index 000000000..13848c20d --- /dev/null +++ b/avm/1.1.0/res/insights/private-link-scope/scoped-resource/main.bicep @@ -0,0 +1,34 @@ +metadata name = 'Private Link Scope Scoped Resources' +metadata description = 'This module deploys a Private Link Scope Scoped Resource.' + +@description('Required. Name of the private link scoped resource.') +@minLength(1) +param name string + +@description('Conditional. The name of the parent private link scope. Required if the template is used in a standalone deployment.') +@minLength(1) +param privateLinkScopeName string + +@description('Required. The resource ID of the scoped Azure monitor resource.') +param linkedResourceId string + +resource privateLinkScope 'Microsoft.Insights/privateLinkScopes@2021-07-01-preview' existing = { + name: privateLinkScopeName +} + +resource scopedResource 'Microsoft.Insights/privateLinkScopes/scopedResources@2021-07-01-preview' = { + name: name + parent: privateLinkScope + properties: { + linkedResourceId: linkedResourceId + } +} + +@description('The name of the resource group where the resource has been deployed.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the deployed scopedResource.') +output resourceId string = scopedResource.id + +@description('The full name of the deployed Scoped Resource.') +output name string = scopedResource.name diff --git a/avm/1.1.0/res/insights/private-link-scope/scoped-resource/main.json b/avm/1.1.0/res/insights/private-link-scope/scoped-resource/main.json new file mode 100644 index 000000000..205d81563 --- /dev/null +++ b/avm/1.1.0/res/insights/private-link-scope/scoped-resource/main.json @@ -0,0 +1,68 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "18319290317274254807" + }, + "name": "Private Link Scope Scoped Resources", + "description": "This module deploys a Private Link Scope Scoped Resource." + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the private link scoped resource." + } + }, + "privateLinkScopeName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Conditional. The name of the parent private link scope. Required if the template is used in a standalone deployment." + } + }, + "linkedResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the scoped Azure monitor resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Insights/privateLinkScopes/scopedResources", + "apiVersion": "2021-07-01-preview", + "name": "[format('{0}/{1}', parameters('privateLinkScopeName'), parameters('name'))]", + "properties": { + "linkedResourceId": "[parameters('linkedResourceId')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group where the resource has been deployed." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed scopedResource." + }, + "value": "[resourceId('Microsoft.Insights/privateLinkScopes/scopedResources', parameters('privateLinkScopeName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The full name of the deployed Scoped Resource." + }, + "value": "[parameters('name')]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/private-link-scope/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/insights/private-link-scope/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..ce9ad59fd --- /dev/null +++ b/avm/1.1.0/res/insights/private-link-scope/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.privatelinkscopes-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'iplsmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-11-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + } + } +] diff --git a/avm/1.1.0/res/insights/private-link-scope/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/insights/private-link-scope/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..9777bf7f9 --- /dev/null +++ b/avm/1.1.0/res/insights/private-link-scope/tests/e2e/max/dependencies.bicep @@ -0,0 +1,71 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2024-06-01' = { + name: 'privatelink.monitor.azure.com' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2024-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id diff --git a/avm/1.1.0/res/insights/private-link-scope/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/insights/private-link-scope/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..1518706be --- /dev/null +++ b/avm/1.1.0/res/insights/private-link-scope/tests/e2e/max/main.test.bicep @@ -0,0 +1,225 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.privatelinkscopes-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'iplsmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-11-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-la-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +var locationUpdated = toLower(replace(resourceLocation, ' ', '')) + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + accessModeSettings: { + exclusions: [ + { + ingestionAccessMode: 'PrivateOnly' + queryAccessMode: 'PrivateOnly' + privateEndpointConnectionName: 'thisisatest' + } + ] + ingestionAccessMode: 'Open' + queryAccessMode: 'Open' + } + scopedResources: [ + { + name: 'scoped1' + linkedResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + privateEndpoints: [ + { + name: 'pe-${namePrefix}' + customNetworkInterfaceName: 'nic-pe-${namePrefix}' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + ipConfigurations: [ + { + name: 'api' + properties: { + groupId: 'azuremonitor' + memberName: 'api' + privateIPAddress: '10.0.0.11' + } + } + { + name: 'globalinai' + properties: { + groupId: 'azuremonitor' + memberName: 'global.in.ai' + privateIPAddress: '10.0.0.12' + } + } + { + name: 'profiler' + properties: { + groupId: 'azuremonitor' + memberName: 'profiler' + privateIPAddress: '10.0.0.13' + } + } + { + name: 'live' + properties: { + groupId: 'azuremonitor' + memberName: 'live' + privateIPAddress: '10.0.0.14' + } + } + { + name: 'diagservicesquery' + properties: { + groupId: 'azuremonitor' + memberName: 'diagservicesquery' + privateIPAddress: '10.0.0.15' + } + } + { + name: 'snapshot' + properties: { + groupId: 'azuremonitor' + memberName: 'snapshot' + privateIPAddress: '10.0.0.16' + } + } + { + name: 'agentsolutionpackstore' + properties: { + groupId: 'azuremonitor' + memberName: 'agentsolutionpackstore' + privateIPAddress: '10.0.0.17' + } + } + { + name: 'dce-global' + properties: { + groupId: 'azuremonitor' + memberName: 'dce-global' + privateIPAddress: '10.0.0.18' + } + } + { + name: 'oms-${locationUpdated}' + properties: { + groupId: 'azuremonitor' + memberName: 'oms-${locationUpdated}' + privateIPAddress: '10.0.0.19' + } + } + { + name: 'ods-${locationUpdated}' + properties: { + groupId: 'azuremonitor' + memberName: 'ods-${locationUpdated}' + privateIPAddress: '10.0.0.20' + } + } + { + name: 'agent-${locationUpdated}' + properties: { + groupId: 'azuremonitor' + memberName: 'agent-${locationUpdated}' + privateIPAddress: '10.0.0.21' + } + } + ] + } + ] + roleAssignments: [ + { + name: 'af62023f-9f34-4bc0-8f05-2374886daf28' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + } + } +] diff --git a/avm/1.1.0/res/insights/private-link-scope/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/insights/private-link-scope/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..98de113b8 --- /dev/null +++ b/avm/1.1.0/res/insights/private-link-scope/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,60 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2024-06-01' = { + name: 'privatelink.monitor.azure.com' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2024-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id diff --git a/avm/1.1.0/res/insights/private-link-scope/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/insights/private-link-scope/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..22f340ac2 --- /dev/null +++ b/avm/1.1.0/res/insights/private-link-scope/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,179 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.privatelinkscopes-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'iplswaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-11-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-la-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // +var locationUpdated = toLower(replace(resourceLocation, ' ', '')) + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + scopedResources: [ + { + name: 'scoped1' + linkedResourceId: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + privateEndpoints: [ + { + name: 'pe-${namePrefix}' + customNetworkInterfaceName: 'nic-pe-${namePrefix}' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + ipConfigurations: [ + { + name: 'api' + properties: { + groupId: 'azuremonitor' + memberName: 'api' + privateIPAddress: '10.0.0.11' + } + } + { + name: 'globalinai' + properties: { + groupId: 'azuremonitor' + memberName: 'global.in.ai' + privateIPAddress: '10.0.0.12' + } + } + { + name: 'profiler' + properties: { + groupId: 'azuremonitor' + memberName: 'profiler' + privateIPAddress: '10.0.0.13' + } + } + { + name: 'live' + properties: { + groupId: 'azuremonitor' + memberName: 'live' + privateIPAddress: '10.0.0.14' + } + } + { + name: 'diagservicesquery' + properties: { + groupId: 'azuremonitor' + memberName: 'diagservicesquery' + privateIPAddress: '10.0.0.15' + } + } + { + name: 'snapshot' + properties: { + groupId: 'azuremonitor' + memberName: 'snapshot' + privateIPAddress: '10.0.0.16' + } + } + { + name: 'agentsolutionpackstore' + properties: { + groupId: 'azuremonitor' + memberName: 'agentsolutionpackstore' + privateIPAddress: '10.0.0.17' + } + } + { + name: 'dce-global' + properties: { + groupId: 'azuremonitor' + memberName: 'dce-global' + privateIPAddress: '10.0.0.18' + } + } + { + name: 'oms-${locationUpdated}' + properties: { + groupId: 'azuremonitor' + memberName: 'oms-${locationUpdated}' + privateIPAddress: '10.0.0.19' + } + } + { + name: 'ods-${locationUpdated}' + properties: { + groupId: 'azuremonitor' + memberName: 'ods-${locationUpdated}' + privateIPAddress: '10.0.0.20' + } + } + { + name: 'agent-${locationUpdated}' + properties: { + groupId: 'azuremonitor' + memberName: 'agent-${locationUpdated}' + privateIPAddress: '10.0.0.21' + } + } + ] + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/insights/private-link-scope/version.json b/avm/1.1.0/res/insights/private-link-scope/version.json new file mode 100644 index 000000000..a89e5c9d3 --- /dev/null +++ b/avm/1.1.0/res/insights/private-link-scope/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.7", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/res/insights/scheduled-query-rule/README.md b/avm/1.1.0/res/insights/scheduled-query-rule/README.md new file mode 100644 index 000000000..617dc4cec --- /dev/null +++ b/avm/1.1.0/res/insights/scheduled-query-rule/README.md @@ -0,0 +1,1011 @@ +# Scheduled Query Rules `[Microsoft.Insights/scheduledQueryRules]` + +This module deploys a Scheduled Query Rule. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/scheduledQueryRules` | [2023-03-15-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2023-03-15-preview/scheduledQueryRules) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/insights/scheduled-query-rule:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule:' = { + name: 'scheduledQueryRuleDeployment' + params: { + // Required parameters + criterias: { + allOf: [ + { + dimensions: [ + { + name: 'Computer' + operator: 'Include' + values: [ + '*' + ] + } + { + name: 'InstanceName' + operator: 'Include' + values: [ + '*' + ] + } + ] + metricMeasureColumn: 'AggregatedValue' + operator: 'GreaterThan' + query: 'Perf | where ObjectName == \'LogicalDisk\' | where CounterName == \'% Free Space\' | where InstanceName <> \'HarddiskVolume1\' and InstanceName <> \'_Total\' | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)' + threshold: 0 + timeAggregation: 'Average' + } + ] + } + name: 'isqrmin001' + scopes: [ + '' + ] + // Non-required parameters + evaluationFrequency: 'PT5M' + location: '' + windowSize: 'PT5M' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "criterias": { + "value": { + "allOf": [ + { + "dimensions": [ + { + "name": "Computer", + "operator": "Include", + "values": [ + "*" + ] + }, + { + "name": "InstanceName", + "operator": "Include", + "values": [ + "*" + ] + } + ], + "metricMeasureColumn": "AggregatedValue", + "operator": "GreaterThan", + "query": "Perf | where ObjectName == \"LogicalDisk\" | where CounterName == \"% Free Space\" | where InstanceName <> \"HarddiskVolume1\" and InstanceName <> \"_Total\" | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)", + "threshold": 0, + "timeAggregation": "Average" + } + ] + } + }, + "name": { + "value": "isqrmin001" + }, + "scopes": { + "value": [ + "" + ] + }, + // Non-required parameters + "evaluationFrequency": { + "value": "PT5M" + }, + "location": { + "value": "" + }, + "windowSize": { + "value": "PT5M" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/scheduled-query-rule:' + +// Required parameters +param criterias = { + allOf: [ + { + dimensions: [ + { + name: 'Computer' + operator: 'Include' + values: [ + '*' + ] + } + { + name: 'InstanceName' + operator: 'Include' + values: [ + '*' + ] + } + ] + metricMeasureColumn: 'AggregatedValue' + operator: 'GreaterThan' + query: 'Perf | where ObjectName == \'LogicalDisk\' | where CounterName == \'% Free Space\' | where InstanceName <> \'HarddiskVolume1\' and InstanceName <> \'_Total\' | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)' + threshold: 0 + timeAggregation: 'Average' + } + ] +} +param name = 'isqrmin001' +param scopes = [ + '' +] +// Non-required parameters +param evaluationFrequency = 'PT5M' +param location = '' +param windowSize = 'PT5M' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule:' = { + name: 'scheduledQueryRuleDeployment' + params: { + // Required parameters + criterias: { + allOf: [ + { + dimensions: [ + { + name: 'Computer' + operator: 'Include' + values: [ + '*' + ] + } + { + name: 'InstanceName' + operator: 'Include' + values: [ + '*' + ] + } + ] + metricMeasureColumn: 'AggregatedValue' + operator: 'GreaterThan' + query: 'Perf | where ObjectName == \'LogicalDisk\' | where CounterName == \'% Free Space\' | where InstanceName <> \'HarddiskVolume1\' and InstanceName <> \'_Total\' | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)' + threshold: 0 + timeAggregation: 'Average' + } + ] + } + name: 'isqrmax001' + scopes: [ + '' + ] + // Non-required parameters + alertDescription: 'My sample Alert' + alertDisplayName: '' + autoMitigate: false + evaluationFrequency: 'PT5M' + location: '' + queryTimeRange: 'PT5M' + roleAssignments: [ + { + name: 'fa8868c7-33d3-4cd5-86a5-cbf76261035b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ruleResolveConfiguration: { + autoResolved: true + timeToResolve: 'PT5M' + } + suppressForMinutes: 'PT5M' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + windowSize: 'PT5M' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "criterias": { + "value": { + "allOf": [ + { + "dimensions": [ + { + "name": "Computer", + "operator": "Include", + "values": [ + "*" + ] + }, + { + "name": "InstanceName", + "operator": "Include", + "values": [ + "*" + ] + } + ], + "metricMeasureColumn": "AggregatedValue", + "operator": "GreaterThan", + "query": "Perf | where ObjectName == \"LogicalDisk\" | where CounterName == \"% Free Space\" | where InstanceName <> \"HarddiskVolume1\" and InstanceName <> \"_Total\" | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)", + "threshold": 0, + "timeAggregation": "Average" + } + ] + } + }, + "name": { + "value": "isqrmax001" + }, + "scopes": { + "value": [ + "" + ] + }, + // Non-required parameters + "alertDescription": { + "value": "My sample Alert" + }, + "alertDisplayName": { + "value": "" + }, + "autoMitigate": { + "value": false + }, + "evaluationFrequency": { + "value": "PT5M" + }, + "location": { + "value": "" + }, + "queryTimeRange": { + "value": "PT5M" + }, + "roleAssignments": { + "value": [ + { + "name": "fa8868c7-33d3-4cd5-86a5-cbf76261035b", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "ruleResolveConfiguration": { + "value": { + "autoResolved": true, + "timeToResolve": "PT5M" + } + }, + "suppressForMinutes": { + "value": "PT5M" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "windowSize": { + "value": "PT5M" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/scheduled-query-rule:' + +// Required parameters +param criterias = { + allOf: [ + { + dimensions: [ + { + name: 'Computer' + operator: 'Include' + values: [ + '*' + ] + } + { + name: 'InstanceName' + operator: 'Include' + values: [ + '*' + ] + } + ] + metricMeasureColumn: 'AggregatedValue' + operator: 'GreaterThan' + query: 'Perf | where ObjectName == \'LogicalDisk\' | where CounterName == \'% Free Space\' | where InstanceName <> \'HarddiskVolume1\' and InstanceName <> \'_Total\' | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)' + threshold: 0 + timeAggregation: 'Average' + } + ] +} +param name = 'isqrmax001' +param scopes = [ + '' +] +// Non-required parameters +param alertDescription = 'My sample Alert' +param alertDisplayName = '' +param autoMitigate = false +param evaluationFrequency = 'PT5M' +param location = '' +param queryTimeRange = 'PT5M' +param roleAssignments = [ + { + name: 'fa8868c7-33d3-4cd5-86a5-cbf76261035b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param ruleResolveConfiguration = { + autoResolved: true + timeToResolve: 'PT5M' +} +param suppressForMinutes = 'PT5M' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param windowSize = 'PT5M' +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule:' = { + name: 'scheduledQueryRuleDeployment' + params: { + // Required parameters + criterias: { + allOf: [ + { + dimensions: [ + { + name: 'Computer' + operator: 'Include' + values: [ + '*' + ] + } + { + name: 'InstanceName' + operator: 'Include' + values: [ + '*' + ] + } + ] + metricMeasureColumn: 'AggregatedValue' + operator: 'GreaterThan' + query: 'Perf | where ObjectName == \'LogicalDisk\' | where CounterName == \'% Free Space\' | where InstanceName <> \'HarddiskVolume1\' and InstanceName <> \'_Total\' | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)' + threshold: 0 + timeAggregation: 'Average' + } + ] + } + name: 'isqrwaf001' + scopes: [ + '' + ] + // Non-required parameters + alertDescription: 'My sample Alert' + autoMitigate: false + evaluationFrequency: 'PT5M' + location: '' + queryTimeRange: 'PT5M' + suppressForMinutes: 'PT5M' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + windowSize: 'PT5M' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "criterias": { + "value": { + "allOf": [ + { + "dimensions": [ + { + "name": "Computer", + "operator": "Include", + "values": [ + "*" + ] + }, + { + "name": "InstanceName", + "operator": "Include", + "values": [ + "*" + ] + } + ], + "metricMeasureColumn": "AggregatedValue", + "operator": "GreaterThan", + "query": "Perf | where ObjectName == \"LogicalDisk\" | where CounterName == \"% Free Space\" | where InstanceName <> \"HarddiskVolume1\" and InstanceName <> \"_Total\" | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)", + "threshold": 0, + "timeAggregation": "Average" + } + ] + } + }, + "name": { + "value": "isqrwaf001" + }, + "scopes": { + "value": [ + "" + ] + }, + // Non-required parameters + "alertDescription": { + "value": "My sample Alert" + }, + "autoMitigate": { + "value": false + }, + "evaluationFrequency": { + "value": "PT5M" + }, + "location": { + "value": "" + }, + "queryTimeRange": { + "value": "PT5M" + }, + "suppressForMinutes": { + "value": "PT5M" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "windowSize": { + "value": "PT5M" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/scheduled-query-rule:' + +// Required parameters +param criterias = { + allOf: [ + { + dimensions: [ + { + name: 'Computer' + operator: 'Include' + values: [ + '*' + ] + } + { + name: 'InstanceName' + operator: 'Include' + values: [ + '*' + ] + } + ] + metricMeasureColumn: 'AggregatedValue' + operator: 'GreaterThan' + query: 'Perf | where ObjectName == \'LogicalDisk\' | where CounterName == \'% Free Space\' | where InstanceName <> \'HarddiskVolume1\' and InstanceName <> \'_Total\' | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)' + threshold: 0 + timeAggregation: 'Average' + } + ] +} +param name = 'isqrwaf001' +param scopes = [ + '' +] +// Non-required parameters +param alertDescription = 'My sample Alert' +param autoMitigate = false +param evaluationFrequency = 'PT5M' +param location = '' +param queryTimeRange = 'PT5M' +param suppressForMinutes = 'PT5M' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param windowSize = 'PT5M' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`criterias`](#parameter-criterias) | object | The rule criteria that defines the conditions of the scheduled query rule. | +| [`name`](#parameter-name) | string | The name of the Alert. | +| [`scopes`](#parameter-scopes) | array | The list of resource IDs that this scheduled query rule is scoped to. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`windowSize`](#parameter-windowsize) | string | The period of time (in ISO 8601 duration format) on which the Alert query will be executed (bin size). Required if the kind is set to 'LogAlert', otherwise not relevant. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`actions`](#parameter-actions) | array | Actions to invoke when the alert fires. | +| [`alertDescription`](#parameter-alertdescription) | string | The description of the scheduled query rule. | +| [`alertDisplayName`](#parameter-alertdisplayname) | string | The display name of the scheduled query rule. | +| [`autoMitigate`](#parameter-automitigate) | bool | The flag that indicates whether the alert should be automatically resolved or not. Relevant only for rules of the kind LogAlert. | +| [`enabled`](#parameter-enabled) | bool | The flag which indicates whether this scheduled query rule is enabled. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`evaluationFrequency`](#parameter-evaluationfrequency) | string | How often the scheduled query rule is evaluated represented in ISO 8601 duration format. Relevant and required only for rules of the kind LogAlert. | +| [`kind`](#parameter-kind) | string | Indicates the type of scheduled query rule. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`queryTimeRange`](#parameter-querytimerange) | string | If specified (in ISO 8601 duration format) then overrides the query time range. Relevant only for rules of the kind LogAlert. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ruleResolveConfiguration`](#parameter-ruleresolveconfiguration) | object | Defines the configuration for resolving fired alerts. Relevant only for rules of the kind LogAlert. | +| [`severity`](#parameter-severity) | int | Severity of the alert. Should be an integer between [0-4]. Value of 0 is severest. Relevant and required only for rules of the kind LogAlert. | +| [`skipQueryValidation`](#parameter-skipqueryvalidation) | bool | The flag which indicates whether the provided query should be validated or not. Relevant only for rules of the kind LogAlert. | +| [`suppressForMinutes`](#parameter-suppressforminutes) | string | Mute actions for the chosen period of time (in ISO 8601 duration format) after the alert is fired. If set, autoMitigate must be disabled.Relevant only for rules of the kind LogAlert. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`targetResourceTypes`](#parameter-targetresourcetypes) | array | List of resource type of the target resource(s) on which the alert is created/updated. For example if the scope is a resource group and targetResourceTypes is Microsoft.Compute/virtualMachines, then a different alert will be fired for each virtual machine in the resource group which meet the alert criteria. Relevant only for rules of the kind LogAlert. | + +### Parameter: `criterias` + +The rule criteria that defines the conditions of the scheduled query rule. + +- Required: Yes +- Type: object + +### Parameter: `name` + +The name of the Alert. + +- Required: Yes +- Type: string + +### Parameter: `scopes` + +The list of resource IDs that this scheduled query rule is scoped to. + +- Required: Yes +- Type: array + +### Parameter: `windowSize` + +The period of time (in ISO 8601 duration format) on which the Alert query will be executed (bin size). Required if the kind is set to 'LogAlert', otherwise not relevant. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `actions` + +Actions to invoke when the alert fires. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `alertDescription` + +The description of the scheduled query rule. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `alertDisplayName` + +The display name of the scheduled query rule. + +- Required: No +- Type: string + +### Parameter: `autoMitigate` + +The flag that indicates whether the alert should be automatically resolved or not. Relevant only for rules of the kind LogAlert. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enabled` + +The flag which indicates whether this scheduled query rule is enabled. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `evaluationFrequency` + +How often the scheduled query rule is evaluated represented in ISO 8601 duration format. Relevant and required only for rules of the kind LogAlert. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `kind` + +Indicates the type of scheduled query rule. + +- Required: No +- Type: string +- Default: `'LogAlert'` +- Allowed: + ```Bicep + [ + 'LogAlert' + 'LogToMetric' + ] + ``` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `queryTimeRange` + +If specified (in ISO 8601 duration format) then overrides the query time range. Relevant only for rules of the kind LogAlert. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ruleResolveConfiguration` + +Defines the configuration for resolving fired alerts. Relevant only for rules of the kind LogAlert. + +- Required: No +- Type: object + +### Parameter: `severity` + +Severity of the alert. Should be an integer between [0-4]. Value of 0 is severest. Relevant and required only for rules of the kind LogAlert. + +- Required: No +- Type: int +- Default: `3` +- Allowed: + ```Bicep + [ + 0 + 1 + 2 + 3 + 4 + ] + ``` + +### Parameter: `skipQueryValidation` + +The flag which indicates whether the provided query should be validated or not. Relevant only for rules of the kind LogAlert. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `suppressForMinutes` + +Mute actions for the chosen period of time (in ISO 8601 duration format) after the alert is fired. If set, autoMitigate must be disabled.Relevant only for rules of the kind LogAlert. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `targetResourceTypes` + +List of resource type of the target resource(s) on which the alert is created/updated. For example if the scope is a resource group and targetResourceTypes is Microsoft.Compute/virtualMachines, then a different alert will be fired for each virtual machine in the resource group which meet the alert criteria. Relevant only for rules of the kind LogAlert. + +- Required: No +- Type: array +- Default: `[]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The Name of the created scheduled query rule. | +| `resourceGroupName` | string | The Resource Group of the created scheduled query rule. | +| `resourceId` | string | The resource ID of the created scheduled query rule. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/insights/scheduled-query-rule/main.bicep b/avm/1.1.0/res/insights/scheduled-query-rule/main.bicep new file mode 100644 index 000000000..9beaba4b5 --- /dev/null +++ b/avm/1.1.0/res/insights/scheduled-query-rule/main.bicep @@ -0,0 +1,205 @@ +metadata name = 'Scheduled Query Rules' +metadata description = 'This module deploys a Scheduled Query Rule.' + +@description('Required. The name of the Alert.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The description of the scheduled query rule.') +param alertDescription string = '' + +@description('Optional. The display name of the scheduled query rule.') +param alertDisplayName string? + +@description('Optional. The flag which indicates whether this scheduled query rule is enabled.') +param enabled bool = true + +@description('Optional. Indicates the type of scheduled query rule.') +@allowed([ + 'LogAlert' + 'LogToMetric' +]) +param kind string = 'LogAlert' + +@description('Optional. The flag that indicates whether the alert should be automatically resolved or not. Relevant only for rules of the kind LogAlert.') +param autoMitigate bool = true + +@description('Optional. If specified (in ISO 8601 duration format) then overrides the query time range. Relevant only for rules of the kind LogAlert.') +param queryTimeRange string = '' + +@description('Optional. The flag which indicates whether the provided query should be validated or not. Relevant only for rules of the kind LogAlert.') +param skipQueryValidation bool = false + +@description('Optional. List of resource type of the target resource(s) on which the alert is created/updated. For example if the scope is a resource group and targetResourceTypes is Microsoft.Compute/virtualMachines, then a different alert will be fired for each virtual machine in the resource group which meet the alert criteria. Relevant only for rules of the kind LogAlert.') +param targetResourceTypes array = [] + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Defines the configuration for resolving fired alerts. Relevant only for rules of the kind LogAlert.') +param ruleResolveConfiguration object? + +@description('Required. The list of resource IDs that this scheduled query rule is scoped to.') +param scopes array + +@description('Optional. Severity of the alert. Should be an integer between [0-4]. Value of 0 is severest. Relevant and required only for rules of the kind LogAlert.') +@allowed([ + 0 + 1 + 2 + 3 + 4 +]) +param severity int = 3 + +@description('Optional. How often the scheduled query rule is evaluated represented in ISO 8601 duration format. Relevant and required only for rules of the kind LogAlert.') +param evaluationFrequency string = '' + +@description('Conditional. The period of time (in ISO 8601 duration format) on which the Alert query will be executed (bin size). Required if the kind is set to \'LogAlert\', otherwise not relevant.') +param windowSize string = '' + +@description('Optional. Actions to invoke when the alert fires.') +param actions array = [] + +@description('Required. The rule criteria that defines the conditions of the scheduled query rule.') +param criterias object + +@description('Optional. Mute actions for the chosen period of time (in ISO 8601 duration format) after the alert is fired. If set, autoMitigate must be disabled.Relevant only for rules of the kind LogAlert.') +param suppressForMinutes string = '' + +@description('Optional. Tags of the resource.') +param tags object? + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.insights-scheduledqueryrule.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource queryRule 'Microsoft.Insights/scheduledQueryRules@2023-03-15-preview' = { + name: name + location: location + tags: tags + kind: kind + properties: { + actions: { + actionGroups: actions + customProperties: {} + } + autoMitigate: (kind == 'LogAlert') ? autoMitigate : null + criteria: criterias + description: alertDescription + displayName: alertDisplayName ?? name + enabled: enabled + evaluationFrequency: (kind == 'LogAlert' && !empty(evaluationFrequency)) ? evaluationFrequency : null + muteActionsDuration: (kind == 'LogAlert' && !empty(suppressForMinutes)) ? suppressForMinutes : null + overrideQueryTimeRange: (kind == 'LogAlert' && !empty(queryTimeRange)) ? queryTimeRange : null + ruleResolveConfiguration: (kind == 'LogAlert' && !empty(ruleResolveConfiguration)) ? ruleResolveConfiguration : null + scopes: scopes + severity: (kind == 'LogAlert') ? severity : null + skipQueryValidation: (kind == 'LogAlert') ? skipQueryValidation : null + targetResourceTypes: (kind == 'LogAlert') ? targetResourceTypes : null + windowSize: (kind == 'LogAlert' && !empty(windowSize)) ? windowSize : null + } +} + +resource queryRule_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(queryRule.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: queryRule + } +] + +@description('The Name of the created scheduled query rule.') +output name string = queryRule.name + +@description('The resource ID of the created scheduled query rule.') +output resourceId string = queryRule.id + +@description('The Resource Group of the created scheduled query rule.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = queryRule.location + +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/insights/scheduled-query-rule/main.json b/avm/1.1.0/res/insights/scheduled-query-rule/main.json new file mode 100644 index 000000000..5e5cd7748 --- /dev/null +++ b/avm/1.1.0/res/insights/scheduled-query-rule/main.json @@ -0,0 +1,363 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "8433672501117405052" + }, + "name": "Scheduled Query Rules", + "description": "This module deploys a Scheduled Query Rule." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Alert." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "alertDescription": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the scheduled query rule." + } + }, + "alertDisplayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The display name of the scheduled query rule." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The flag which indicates whether this scheduled query rule is enabled." + } + }, + "kind": { + "type": "string", + "defaultValue": "LogAlert", + "allowedValues": [ + "LogAlert", + "LogToMetric" + ], + "metadata": { + "description": "Optional. Indicates the type of scheduled query rule." + } + }, + "autoMitigate": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The flag that indicates whether the alert should be automatically resolved or not. Relevant only for rules of the kind LogAlert." + } + }, + "queryTimeRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. If specified (in ISO 8601 duration format) then overrides the query time range. Relevant only for rules of the kind LogAlert." + } + }, + "skipQueryValidation": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag which indicates whether the provided query should be validated or not. Relevant only for rules of the kind LogAlert." + } + }, + "targetResourceTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of resource type of the target resource(s) on which the alert is created/updated. For example if the scope is a resource group and targetResourceTypes is Microsoft.Compute/virtualMachines, then a different alert will be fired for each virtual machine in the resource group which meet the alert criteria. Relevant only for rules of the kind LogAlert." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "ruleResolveConfiguration": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Defines the configuration for resolving fired alerts. Relevant only for rules of the kind LogAlert." + } + }, + "scopes": { + "type": "array", + "metadata": { + "description": "Required. The list of resource IDs that this scheduled query rule is scoped to." + } + }, + "severity": { + "type": "int", + "defaultValue": 3, + "allowedValues": [ + 0, + 1, + 2, + 3, + 4 + ], + "metadata": { + "description": "Optional. Severity of the alert. Should be an integer between [0-4]. Value of 0 is severest. Relevant and required only for rules of the kind LogAlert." + } + }, + "evaluationFrequency": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How often the scheduled query rule is evaluated represented in ISO 8601 duration format. Relevant and required only for rules of the kind LogAlert." + } + }, + "windowSize": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. The period of time (in ISO 8601 duration format) on which the Alert query will be executed (bin size). Required if the kind is set to 'LogAlert', otherwise not relevant." + } + }, + "actions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Actions to invoke when the alert fires." + } + }, + "criterias": { + "type": "object", + "metadata": { + "description": "Required. The rule criteria that defines the conditions of the scheduled query rule." + } + }, + "suppressForMinutes": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Mute actions for the chosen period of time (in ISO 8601 duration format) after the alert is fired. If set, autoMitigate must be disabled.Relevant only for rules of the kind LogAlert." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-scheduledqueryrule.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "queryRule": { + "type": "Microsoft.Insights/scheduledQueryRules", + "apiVersion": "2023-03-15-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "properties": { + "actions": { + "actionGroups": "[parameters('actions')]", + "customProperties": {} + }, + "autoMitigate": "[if(equals(parameters('kind'), 'LogAlert'), parameters('autoMitigate'), null())]", + "criteria": "[parameters('criterias')]", + "description": "[parameters('alertDescription')]", + "displayName": "[coalesce(parameters('alertDisplayName'), parameters('name'))]", + "enabled": "[parameters('enabled')]", + "evaluationFrequency": "[if(and(equals(parameters('kind'), 'LogAlert'), not(empty(parameters('evaluationFrequency')))), parameters('evaluationFrequency'), null())]", + "muteActionsDuration": "[if(and(equals(parameters('kind'), 'LogAlert'), not(empty(parameters('suppressForMinutes')))), parameters('suppressForMinutes'), null())]", + "overrideQueryTimeRange": "[if(and(equals(parameters('kind'), 'LogAlert'), not(empty(parameters('queryTimeRange')))), parameters('queryTimeRange'), null())]", + "ruleResolveConfiguration": "[if(and(equals(parameters('kind'), 'LogAlert'), not(empty(parameters('ruleResolveConfiguration')))), parameters('ruleResolveConfiguration'), null())]", + "scopes": "[parameters('scopes')]", + "severity": "[if(equals(parameters('kind'), 'LogAlert'), parameters('severity'), null())]", + "skipQueryValidation": "[if(equals(parameters('kind'), 'LogAlert'), parameters('skipQueryValidation'), null())]", + "targetResourceTypes": "[if(equals(parameters('kind'), 'LogAlert'), parameters('targetResourceTypes'), null())]", + "windowSize": "[if(and(equals(parameters('kind'), 'LogAlert'), not(empty(parameters('windowSize')))), parameters('windowSize'), null())]" + } + }, + "queryRule_roleAssignments": { + "copy": { + "name": "queryRule_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/scheduledQueryRules/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/scheduledQueryRules', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "queryRule" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the created scheduled query rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the created scheduled query rule." + }, + "value": "[resourceId('Microsoft.Insights/scheduledQueryRules', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The Resource Group of the created scheduled query rule." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('queryRule', '2023-03-15-preview', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..63e7a207d --- /dev/null +++ b/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id diff --git a/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..90dbf0cbf --- /dev/null +++ b/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,89 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.scheduledqueryrules-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'isqrmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + criterias: { + allOf: [ + { + dimensions: [ + { + name: 'Computer' + operator: 'Include' + values: [ + '*' + ] + } + { + name: 'InstanceName' + operator: 'Include' + values: [ + '*' + ] + } + ] + metricMeasureColumn: 'AggregatedValue' + operator: 'GreaterThan' + query: 'Perf | where ObjectName == "LogicalDisk" | where CounterName == "% Free Space" | where InstanceName <> "HarddiskVolume1" and InstanceName <> "_Total" | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)' + threshold: 0 + timeAggregation: 'Average' + } + ] + } + evaluationFrequency: 'PT5M' + scopes: [ + nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + ] + windowSize: 'PT5M' + } + } +] diff --git a/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..c4b318881 --- /dev/null +++ b/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/max/dependencies.bicep @@ -0,0 +1,24 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id diff --git a/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..363126f2e --- /dev/null +++ b/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/max/main.test.bicep @@ -0,0 +1,126 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.scheduledqueryrules-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'isqrmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + alertDescription: 'My sample Alert' + autoMitigate: false + criterias: { + allOf: [ + { + dimensions: [ + { + name: 'Computer' + operator: 'Include' + values: [ + '*' + ] + } + { + name: 'InstanceName' + operator: 'Include' + values: [ + '*' + ] + } + ] + metricMeasureColumn: 'AggregatedValue' + operator: 'GreaterThan' + query: 'Perf | where ObjectName == "LogicalDisk" | where CounterName == "% Free Space" | where InstanceName <> "HarddiskVolume1" and InstanceName <> "_Total" | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)' + threshold: 0 + timeAggregation: 'Average' + } + ] + } + evaluationFrequency: 'PT5M' + queryTimeRange: 'PT5M' + roleAssignments: [ + { + name: 'fa8868c7-33d3-4cd5-86a5-cbf76261035b' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + alertDisplayName: '${uniqueString(deployment().name, resourceLocation)}-displayNameTest-${serviceShort}-${iteration}' + ruleResolveConfiguration: { + autoResolved: true + timeToResolve: 'PT5M' + } + scopes: [ + nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + ] + suppressForMinutes: 'PT5M' + windowSize: 'PT5M' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..63e7a207d --- /dev/null +++ b/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id diff --git a/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..911787cae --- /dev/null +++ b/avm/1.1.0/res/insights/scheduled-query-rule/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,98 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.scheduledqueryrules-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'isqrwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + alertDescription: 'My sample Alert' + autoMitigate: false + criterias: { + allOf: [ + { + dimensions: [ + { + name: 'Computer' + operator: 'Include' + values: [ + '*' + ] + } + { + name: 'InstanceName' + operator: 'Include' + values: [ + '*' + ] + } + ] + metricMeasureColumn: 'AggregatedValue' + operator: 'GreaterThan' + query: 'Perf | where ObjectName == "LogicalDisk" | where CounterName == "% Free Space" | where InstanceName <> "HarddiskVolume1" and InstanceName <> "_Total" | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)' + threshold: 0 + timeAggregation: 'Average' + } + ] + } + evaluationFrequency: 'PT5M' + queryTimeRange: 'PT5M' + scopes: [ + nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + ] + suppressForMinutes: 'PT5M' + windowSize: 'PT5M' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/insights/scheduled-query-rule/version.json b/avm/1.1.0/res/insights/scheduled-query-rule/version.json new file mode 100644 index 000000000..c177b1bb5 --- /dev/null +++ b/avm/1.1.0/res/insights/scheduled-query-rule/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/webtest/README.md b/avm/1.1.0/res/insights/webtest/README.md new file mode 100644 index 000000000..13f0ff3ee --- /dev/null +++ b/avm/1.1.0/res/insights/webtest/README.md @@ -0,0 +1,789 @@ +# Web Tests `[Microsoft.Insights/webtests]` + +This module deploys a Web Test. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/webtests` | [2022-06-15](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2022-06-15/webtests) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/insights/webtest:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module webtest 'br/public:avm/res/insights/webtest:' = { + name: 'webtestDeployment' + params: { + // Required parameters + appInsightResourceId: '' + name: 'iwtmin001' + request: { + HttpVerb: 'GET' + RequestUrl: 'https://learn.microsoft.com/en-us/' + } + webTestName: 'wt$iwtmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "appInsightResourceId": { + "value": "" + }, + "name": { + "value": "iwtmin001" + }, + "request": { + "value": { + "HttpVerb": "GET", + "RequestUrl": "https://learn.microsoft.com/en-us/" + } + }, + "webTestName": { + "value": "wt$iwtmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/webtest:' + +// Required parameters +param appInsightResourceId = '' +param name = 'iwtmin001' +param request = { + HttpVerb: 'GET' + RequestUrl: 'https://learn.microsoft.com/en-us/' +} +param webTestName = 'wt$iwtmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module webtest 'br/public:avm/res/insights/webtest:' = { + name: 'webtestDeployment' + params: { + // Required parameters + appInsightResourceId: '' + name: 'iwtmax001' + request: { + HttpVerb: 'GET' + RequestUrl: 'https://learn.microsoft.com/en-us/' + } + webTestName: 'wt$iwtmax001' + // Non-required parameters + location: '' + locations: [ + { + Id: 'emea-nl-ams-azr' + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '86bf66a0-940f-438d-977e-624c00ccb2d8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + syntheticMonitorId: 'iwtmax001' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "appInsightResourceId": { + "value": "" + }, + "name": { + "value": "iwtmax001" + }, + "request": { + "value": { + "HttpVerb": "GET", + "RequestUrl": "https://learn.microsoft.com/en-us/" + } + }, + "webTestName": { + "value": "wt$iwtmax001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "locations": { + "value": [ + { + "Id": "emea-nl-ams-azr" + } + ] + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "86bf66a0-940f-438d-977e-624c00ccb2d8", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "syntheticMonitorId": { + "value": "iwtmax001" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/webtest:' + +// Required parameters +param appInsightResourceId = '' +param name = 'iwtmax001' +param request = { + HttpVerb: 'GET' + RequestUrl: 'https://learn.microsoft.com/en-us/' +} +param webTestName = 'wt$iwtmax001' +// Non-required parameters +param location = '' +param locations = [ + { + Id: 'emea-nl-ams-azr' + } +] +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '86bf66a0-940f-438d-977e-624c00ccb2d8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param syntheticMonitorId = 'iwtmax001' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module webtest 'br/public:avm/res/insights/webtest:' = { + name: 'webtestDeployment' + params: { + // Required parameters + appInsightResourceId: '' + name: 'iwtwaf001' + request: { + HttpVerb: 'GET' + RequestUrl: 'https://learn.microsoft.com/en-us/' + } + webTestName: 'wt$iwtwaf001' + // Non-required parameters + location: '' + locations: [ + { + Id: 'emea-nl-ams-azr' + } + ] + syntheticMonitorId: 'iwtwaf001' + tags: { + 'hidden-title': 'This is visible in the resource name' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "appInsightResourceId": { + "value": "" + }, + "name": { + "value": "iwtwaf001" + }, + "request": { + "value": { + "HttpVerb": "GET", + "RequestUrl": "https://learn.microsoft.com/en-us/" + } + }, + "webTestName": { + "value": "wt$iwtwaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "locations": { + "value": [ + { + "Id": "emea-nl-ams-azr" + } + ] + }, + "syntheticMonitorId": { + "value": "iwtwaf001" + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/webtest:' + +// Required parameters +param appInsightResourceId = '' +param name = 'iwtwaf001' +param request = { + HttpVerb: 'GET' + RequestUrl: 'https://learn.microsoft.com/en-us/' +} +param webTestName = 'wt$iwtwaf001' +// Non-required parameters +param location = '' +param locations = [ + { + Id: 'emea-nl-ams-azr' + } +] +param syntheticMonitorId = 'iwtwaf001' +param tags = { + 'hidden-title': 'This is visible in the resource name' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appInsightResourceId`](#parameter-appinsightresourceid) | string | Resource ID of the App Insights resource to link with this webtest. | +| [`name`](#parameter-name) | string | Name of the webtest. | +| [`request`](#parameter-request) | object | The collection of request properties. | +| [`webTestName`](#parameter-webtestname) | string | User defined name if this WebTest. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`configuration`](#parameter-configuration) | object | An XML configuration specification for a WebTest. | +| [`description`](#parameter-description) | string | User defined description for this WebTest. | +| [`enabled`](#parameter-enabled) | bool | Is the test actively being monitored. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`frequency`](#parameter-frequency) | int | Interval in seconds between test runs for this WebTest. | +| [`kind`](#parameter-kind) | string | The kind of WebTest that this web test watches. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`locations`](#parameter-locations) | array | List of where to physically run the tests from to give global coverage for accessibility of your application. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`retryEnabled`](#parameter-retryenabled) | bool | Allow for retries should this WebTest fail. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`syntheticMonitorId`](#parameter-syntheticmonitorid) | string | Unique ID of this WebTest. | +| [`tags`](#parameter-tags) | object | Resource tags. Note: a mandatory tag 'hidden-link' based on the 'appInsightResourceId' parameter will be automatically added to the tags defined here. | +| [`timeout`](#parameter-timeout) | int | Seconds until this WebTest will timeout and fail. | +| [`validationRules`](#parameter-validationrules) | object | The collection of validation rule properties. | + +### Parameter: `appInsightResourceId` + +Resource ID of the App Insights resource to link with this webtest. + +- Required: Yes +- Type: string + +### Parameter: `name` + +Name of the webtest. + +- Required: Yes +- Type: string + +### Parameter: `request` + +The collection of request properties. + +- Required: Yes +- Type: object + +### Parameter: `webTestName` + +User defined name if this WebTest. + +- Required: Yes +- Type: string + +### Parameter: `configuration` + +An XML configuration specification for a WebTest. + +- Required: No +- Type: object + +### Parameter: `description` + +User defined description for this WebTest. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `enabled` + +Is the test actively being monitored. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `frequency` + +Interval in seconds between test runs for this WebTest. + +- Required: No +- Type: int +- Default: `300` + +### Parameter: `kind` + +The kind of WebTest that this web test watches. + +- Required: No +- Type: string +- Default: `'standard'` +- Allowed: + ```Bicep + [ + 'multistep' + 'ping' + 'standard' + ] + ``` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `locations` + +List of where to physically run the tests from to give global coverage for accessibility of your application. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + { + Id: 'us-il-ch1-azr' + } + { + Id: 'us-fl-mia-edge' + } + { + Id: 'latam-br-gru-edge' + } + { + Id: 'apac-sg-sin-azr' + } + { + Id: 'emea-nl-ams-azr' + } + ] + ``` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `retryEnabled` + +Allow for retries should this WebTest fail. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `syntheticMonitorId` + +Unique ID of this WebTest. + +- Required: No +- Type: string +- Default: `[parameters('name')]` + +### Parameter: `tags` + +Resource tags. Note: a mandatory tag 'hidden-link' based on the 'appInsightResourceId' parameter will be automatically added to the tags defined here. + +- Required: No +- Type: object + +### Parameter: `timeout` + +Seconds until this WebTest will timeout and fail. + +- Required: No +- Type: int +- Default: `30` + +### Parameter: `validationRules` + +The collection of validation rule properties. + +- Required: No +- Type: object +- Default: `{}` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the webtest. | +| `resourceGroupName` | string | The resource group the resource was deployed into. | +| `resourceId` | string | The resource ID of the webtest. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/insights/webtest/main.bicep b/avm/1.1.0/res/insights/webtest/main.bicep new file mode 100644 index 000000000..e6563da00 --- /dev/null +++ b/avm/1.1.0/res/insights/webtest/main.bicep @@ -0,0 +1,189 @@ +metadata name = 'Web Tests' +metadata description = 'This module deploys a Web Test.' + +@sys.description('Required. Name of the webtest.') +param name string + +@sys.description('Required. Resource ID of the App Insights resource to link with this webtest.') +param appInsightResourceId string + +@sys.description('Required. User defined name if this WebTest.') +param webTestName string + +@sys.description('Optional. Resource tags. Note: a mandatory tag \'hidden-link\' based on the \'appInsightResourceId\' parameter will be automatically added to the tags defined here.') +param tags object? + +@sys.description('Required. The collection of request properties.') +param request object + +@sys.description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@sys.description('Optional. User defined description for this WebTest.') +param description string = '' + +@sys.description('Optional. Unique ID of this WebTest.') +param syntheticMonitorId string = name + +@sys.description('Optional. The kind of WebTest that this web test watches.') +@allowed([ + 'multistep' + 'ping' + 'standard' +]) +param kind string = 'standard' + +@sys.description('Optional. List of where to physically run the tests from to give global coverage for accessibility of your application.') +param locations array = [ + { + Id: 'us-il-ch1-azr' + } + { + Id: 'us-fl-mia-edge' + } + { + Id: 'latam-br-gru-edge' + } + { + Id: 'apac-sg-sin-azr' + } + { + Id: 'emea-nl-ams-azr' + } +] + +@sys.description('Optional. Is the test actively being monitored.') +param enabled bool = true + +@sys.description('Optional. Interval in seconds between test runs for this WebTest.') +param frequency int = 300 + +@sys.description('Optional. Seconds until this WebTest will timeout and fail.') +param timeout int = 30 + +@sys.description('Optional. Allow for retries should this WebTest fail.') +param retryEnabled bool = true + +@sys.description('Optional. The collection of validation rule properties.') +param validationRules object = {} + +@sys.description('Optional. An XML configuration specification for a WebTest.') +param configuration object? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@sys.description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@sys.description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var hiddenLinkTag = { + 'hidden-link:${appInsightResourceId}': 'Resource' +} + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.insights-webtest.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource webtest 'Microsoft.Insights/webtests@2022-06-15' = { + name: name + location: location + tags: union(tags ?? {}, hiddenLinkTag) + properties: { + Kind: kind + Locations: locations + Name: webTestName + Description: description + SyntheticMonitorId: syntheticMonitorId + Enabled: enabled + Frequency: frequency + Timeout: timeout + RetryEnabled: retryEnabled + Request: request + ValidationRules: validationRules + Configuration: configuration + } +} + +resource webtest_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: webtest +} + +resource webtest_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(webtest.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: webtest + } +] + +@sys.description('The name of the webtest.') +output name string = webtest.name + +@sys.description('The resource ID of the webtest.') +output resourceId string = webtest.id + +@sys.description('The resource group the resource was deployed into.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The location the resource was deployed into.') +output location string = webtest.location diff --git a/avm/1.1.0/res/insights/webtest/main.json b/avm/1.1.0/res/insights/webtest/main.json new file mode 100644 index 000000000..b144dea6d --- /dev/null +++ b/avm/1.1.0/res/insights/webtest/main.json @@ -0,0 +1,404 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "13066561667388649172" + }, + "name": "Web Tests", + "description": "This module deploys a Web Test." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the webtest." + } + }, + "appInsightResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the App Insights resource to link with this webtest." + } + }, + "webTestName": { + "type": "string", + "metadata": { + "description": "Required. User defined name if this WebTest." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags. Note: a mandatory tag 'hidden-link' based on the 'appInsightResourceId' parameter will be automatically added to the tags defined here." + } + }, + "request": { + "type": "object", + "metadata": { + "description": "Required. The collection of request properties." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. User defined description for this WebTest." + } + }, + "syntheticMonitorId": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Unique ID of this WebTest." + } + }, + "kind": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "multistep", + "ping", + "standard" + ], + "metadata": { + "description": "Optional. The kind of WebTest that this web test watches." + } + }, + "locations": { + "type": "array", + "defaultValue": [ + { + "Id": "us-il-ch1-azr" + }, + { + "Id": "us-fl-mia-edge" + }, + { + "Id": "latam-br-gru-edge" + }, + { + "Id": "apac-sg-sin-azr" + }, + { + "Id": "emea-nl-ams-azr" + } + ], + "metadata": { + "description": "Optional. List of where to physically run the tests from to give global coverage for accessibility of your application." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Is the test actively being monitored." + } + }, + "frequency": { + "type": "int", + "defaultValue": 300, + "metadata": { + "description": "Optional. Interval in seconds between test runs for this WebTest." + } + }, + "timeout": { + "type": "int", + "defaultValue": 30, + "metadata": { + "description": "Optional. Seconds until this WebTest will timeout and fail." + } + }, + "retryEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow for retries should this WebTest fail." + } + }, + "validationRules": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The collection of validation rule properties." + } + }, + "configuration": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. An XML configuration specification for a WebTest." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "hiddenLinkTag": { + "[format('hidden-link:{0}', parameters('appInsightResourceId'))]": "Resource" + }, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-webtest.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "webtest": { + "type": "Microsoft.Insights/webtests", + "apiVersion": "2022-06-15", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[union(coalesce(parameters('tags'), createObject()), variables('hiddenLinkTag'))]", + "properties": { + "Kind": "[parameters('kind')]", + "Locations": "[parameters('locations')]", + "Name": "[parameters('webTestName')]", + "Description": "[parameters('description')]", + "SyntheticMonitorId": "[parameters('syntheticMonitorId')]", + "Enabled": "[parameters('enabled')]", + "Frequency": "[parameters('frequency')]", + "Timeout": "[parameters('timeout')]", + "RetryEnabled": "[parameters('retryEnabled')]", + "Request": "[parameters('request')]", + "ValidationRules": "[parameters('validationRules')]", + "Configuration": "[parameters('configuration')]" + } + }, + "webtest_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Insights/webtests/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "webtest" + ] + }, + "webtest_roleAssignments": { + "copy": { + "name": "webtest_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/webtests/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/webtests', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "webtest" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the webtest." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the webtest." + }, + "value": "[resourceId('Microsoft.Insights/webtests', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the resource was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('webtest', '2022-06-15', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/insights/webtest/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/insights/webtest/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..79e003515 --- /dev/null +++ b/avm/1.1.0/res/insights/webtest/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,26 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param appInsightName string + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +resource appInsight 'Microsoft.Insights/components@2020-02-02' = { + name: appInsightName + location: location + kind: 'web' + properties: { + Application_Type: 'web' + WorkspaceResourceId: logAnalyticsWorkspace.id + } +} + +@description('The resource ID of the created Log Analytics Workspace.') +output appInsightResourceId string = appInsight.id diff --git a/avm/1.1.0/res/insights/webtest/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/insights/webtest/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..dc52027e6 --- /dev/null +++ b/avm/1.1.0/res/insights/webtest/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,64 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.webtests-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'iwtmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + appInsightName: 'dep-${namePrefix}-appi-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + appInsightResourceId: nestedDependencies.outputs.appInsightResourceId + webTestName: 'wt${namePrefix}$${serviceShort}001' + request: { + RequestUrl: 'https://learn.microsoft.com/en-us/' + HttpVerb: 'GET' + } + } + } +] diff --git a/avm/1.1.0/res/insights/webtest/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/insights/webtest/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..51098662d --- /dev/null +++ b/avm/1.1.0/res/insights/webtest/tests/e2e/max/dependencies.bicep @@ -0,0 +1,37 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param appInsightName string + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource appInsight 'Microsoft.Insights/components@2020-02-02' = { + name: appInsightName + location: location + kind: 'web' + properties: { + Application_Type: 'web' + WorkspaceResourceId: logAnalyticsWorkspace.id + } +} + +@description('The resource ID of the created Log Analytics Workspace.') +output appInsightResourceId string = appInsight.id + +@description('The principal ID of the created managed identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/insights/webtest/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/insights/webtest/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..aaafa6341 --- /dev/null +++ b/avm/1.1.0/res/insights/webtest/tests/e2e/max/main.test.bicep @@ -0,0 +1,102 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.webtests-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'iwtmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + appInsightName: 'dep-${namePrefix}-appi-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + appInsightResourceId: nestedDependencies.outputs.appInsightResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + webTestName: 'wt${namePrefix}$${serviceShort}001' + syntheticMonitorId: '${namePrefix}${serviceShort}001' + locations: [ + { + Id: 'emea-nl-ams-azr' + } + ] + request: { + RequestUrl: 'https://learn.microsoft.com/en-us/' + HttpVerb: 'GET' + } + roleAssignments: [ + { + name: '86bf66a0-940f-438d-977e-624c00ccb2d8' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + } + } +] diff --git a/avm/1.1.0/res/insights/webtest/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/insights/webtest/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..79e003515 --- /dev/null +++ b/avm/1.1.0/res/insights/webtest/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,26 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param appInsightName string + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +resource appInsight 'Microsoft.Insights/components@2020-02-02' = { + name: appInsightName + location: location + kind: 'web' + properties: { + Application_Type: 'web' + WorkspaceResourceId: logAnalyticsWorkspace.id + } +} + +@description('The resource ID of the created Log Analytics Workspace.') +output appInsightResourceId string = appInsight.id diff --git a/avm/1.1.0/res/insights/webtest/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/insights/webtest/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..11a413e55 --- /dev/null +++ b/avm/1.1.0/res/insights/webtest/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,73 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.webtests-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'iwtwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + appInsightName: 'dep-${namePrefix}-appi-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + appInsightResourceId: nestedDependencies.outputs.appInsightResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + } + webTestName: 'wt${namePrefix}$${serviceShort}001' + syntheticMonitorId: '${namePrefix}${serviceShort}001' + locations: [ + { + Id: 'emea-nl-ams-azr' + } + ] + request: { + RequestUrl: 'https://learn.microsoft.com/en-us/' + HttpVerb: 'GET' + } + } + } +] diff --git a/avm/1.1.0/res/insights/webtest/version.json b/avm/1.1.0/res/insights/webtest/version.json new file mode 100644 index 000000000..c177b1bb5 --- /dev/null +++ b/avm/1.1.0/res/insights/webtest/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/key-vault/vault/README.md b/avm/1.1.0/res/key-vault/vault/README.md new file mode 100644 index 000000000..4fe0b7412 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/README.md @@ -0,0 +1,3179 @@ +# Key Vaults `[Microsoft.KeyVault/vaults]` + +This module deploys a Key Vault. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.KeyVault/vaults` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults) | +| `Microsoft.KeyVault/vaults/accessPolicies` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2023-07-01/vaults/accessPolicies) | +| `Microsoft.KeyVault/vaults/keys` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/keys) | +| `Microsoft.KeyVault/vaults/secrets` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/secrets) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/key-vault/vault:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using only defaults](#example-2-using-only-defaults) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [Using only defaults](#example-4-using-only-defaults) +- [WAF-aligned](#example-5-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module vault 'br/public:avm/res/key-vault/vault:' = { + name: 'vaultDeployment' + params: { + // Required parameters + name: 'kvvmin002' + // Non-required parameters + enablePurgeProtection: false + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "kvvmin002" + }, + // Non-required parameters + "enablePurgeProtection": { + "value": false + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/key-vault/vault:' + +// Required parameters +param name = 'kvvmin002' +// Non-required parameters +param enablePurgeProtection = false +``` + +
+

+ +### Example 2: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module vault 'br/public:avm/res/key-vault/vault:' = { + name: 'vaultDeployment' + params: { + // Required parameters + name: 'kvvec002' + // Non-required parameters + enablePurgeProtection: false + enableRbacAuthorization: true + keys: [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + kty: 'EC' + name: 'keyName' + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + action: { + type: 'Rotate' + } + trigger: { + timeBeforeExpiry: 'P2M' + } + } + { + action: { + type: 'Notify' + } + trigger: { + timeBeforeExpiry: 'P30D' + } + } + ] + } + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "kvvec002" + }, + "enablePurgeProtection": { + "value": false + }, + "enableRbacAuthorization": { + "value": true + }, + "keys": { + "value": [ + { + "attributes": { + "exp": 1725109032, + "nbf": 10000 + }, + "kty": "EC", + "name": "keyName", + "rotationPolicy": { + "attributes": { + "expiryTime": "P2Y" + }, + "lifetimeActions": [ + { + "action": { + "type": "Rotate" + }, + "trigger": { + "timeBeforeExpiry": "P2M" + } + }, + { + "action": { + "type": "Notify" + }, + "trigger": { + "timeBeforeExpiry": "P30D" + } + } + ] + } + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/key-vault/vault:' + +// Required parameters +param name = 'kvvec002' +// Non-required parameters +param enablePurgeProtection = false +param enableRbacAuthorization = true +param keys = [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + kty: 'EC' + name: 'keyName' + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + action: { + type: 'Rotate' + } + trigger: { + timeBeforeExpiry: 'P2M' + } + } + { + action: { + type: 'Notify' + } + trigger: { + timeBeforeExpiry: 'P30D' + } + } + ] + } + } +] +``` + +
+

+ +### Example 3: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module vault 'br/public:avm/res/key-vault/vault:' = { + name: 'vaultDeployment' + params: { + // Required parameters + name: 'kvvmax002' + // Non-required parameters + accessPolicies: [ + { + objectId: '' + permissions: { + keys: [ + 'get' + 'list' + 'update' + ] + secrets: [ + 'all' + ] + } + tenantId: '' + } + { + objectId: '' + permissions: { + certificates: [ + 'backup' + 'create' + 'delete' + ] + secrets: [ + 'all' + ] + } + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'AzurePolicyEvaluationDetails' + } + { + category: 'AuditEvent' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + enablePurgeProtection: false + enableRbacAuthorization: false + keys: [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + name: 'keyName' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + action: { + type: 'Rotate' + } + trigger: { + timeBeforeExpiry: 'P2M' + } + } + { + action: { + type: 'Notify' + } + trigger: { + timeBeforeExpiry: 'P30D' + } + } + ] + } + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + ipRules: [ + { + value: '40.74.28.0/23' + } + ] + virtualNetworkRules: [ + { + id: '' + ignoreMissingVnetServiceEndpoint: false + } + ] + } + privateEndpoints: [ + { + customDnsConfigs: [ + { + fqdn: 'abc.keyvault.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + resourceGroupResourceId: '' + subnetResourceId: '' + } + ] + roleAssignments: [ + { + name: 'b50cc72e-a2f2-4c4c-a3ad-86a43feb6ab8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + secrets: [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + contentType: 'Something' + name: 'secretName' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + value: 'secretValue' + } + ] + softDeleteRetentionInDays: 7 + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "kvvmax002" + }, + "accessPolicies": { + "value": [ + { + "objectId": "", + "permissions": { + "keys": [ + "get", + "list", + "update" + ], + "secrets": [ + "all" + ] + }, + "tenantId": "" + }, + { + "objectId": "", + "permissions": { + "certificates": [ + "backup", + "create", + "delete" + ], + "secrets": [ + "all" + ] + } + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "logCategoriesAndGroups": [ + { + "category": "AzurePolicyEvaluationDetails" + }, + { + "category": "AuditEvent" + } + ], + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "enablePurgeProtection": { + "value": false + }, + "enableRbacAuthorization": { + "value": false + }, + "keys": { + "value": [ + { + "attributes": { + "exp": 1725109032, + "nbf": 10000 + }, + "name": "keyName", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "rotationPolicy": { + "attributes": { + "expiryTime": "P2Y" + }, + "lifetimeActions": [ + { + "action": { + "type": "Rotate" + }, + "trigger": { + "timeBeforeExpiry": "P2M" + } + }, + { + "action": { + "type": "Notify" + }, + "trigger": { + "timeBeforeExpiry": "P30D" + } + } + ] + } + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "Deny", + "ipRules": [ + { + "value": "40.74.28.0/23" + } + ], + "virtualNetworkRules": [ + { + "id": "", + "ignoreMissingVnetServiceEndpoint": false + } + ] + } + }, + "privateEndpoints": { + "value": [ + { + "customDnsConfigs": [ + { + "fqdn": "abc.keyvault.com", + "ipAddresses": [ + "10.0.0.10" + ] + } + ], + "ipConfigurations": [ + { + "name": "myIPconfig", + "properties": { + "groupId": "vault", + "memberName": "default", + "privateIPAddress": "10.0.0.10" + } + } + ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "resourceGroupResourceId": "", + "subnetResourceId": "" + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "b50cc72e-a2f2-4c4c-a3ad-86a43feb6ab8", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "secrets": { + "value": [ + { + "attributes": { + "exp": 1725109032, + "nbf": 10000 + }, + "contentType": "Something", + "name": "secretName", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "value": "secretValue" + } + ] + }, + "softDeleteRetentionInDays": { + "value": 7 + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/key-vault/vault:' + +// Required parameters +param name = 'kvvmax002' +// Non-required parameters +param accessPolicies = [ + { + objectId: '' + permissions: { + keys: [ + 'get' + 'list' + 'update' + ] + secrets: [ + 'all' + ] + } + tenantId: '' + } + { + objectId: '' + permissions: { + certificates: [ + 'backup' + 'create' + 'delete' + ] + secrets: [ + 'all' + ] + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'AzurePolicyEvaluationDetails' + } + { + category: 'AuditEvent' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enablePurgeProtection = false +param enableRbacAuthorization = false +param keys = [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + name: 'keyName' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + action: { + type: 'Rotate' + } + trigger: { + timeBeforeExpiry: 'P2M' + } + } + { + action: { + type: 'Notify' + } + trigger: { + timeBeforeExpiry: 'P30D' + } + } + ] + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param networkAcls = { + bypass: 'AzureServices' + defaultAction: 'Deny' + ipRules: [ + { + value: '40.74.28.0/23' + } + ] + virtualNetworkRules: [ + { + id: '' + ignoreMissingVnetServiceEndpoint: false + } + ] +} +param privateEndpoints = [ + { + customDnsConfigs: [ + { + fqdn: 'abc.keyvault.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + resourceGroupResourceId: '' + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: 'b50cc72e-a2f2-4c4c-a3ad-86a43feb6ab8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param secrets = [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + contentType: 'Something' + name: 'secretName' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + value: 'secretValue' + } +] +param softDeleteRetentionInDays = 7 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 4: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module vault 'br/public:avm/res/key-vault/vault:' = { + name: 'vaultDeployment' + params: { + // Required parameters + name: 'kvvrsa002' + // Non-required parameters + enablePurgeProtection: false + enableRbacAuthorization: true + keys: [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + kty: 'RSA' + name: 'keyName' + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + action: { + type: 'Rotate' + } + trigger: { + timeBeforeExpiry: 'P2M' + } + } + { + action: { + type: 'Notify' + } + trigger: { + timeBeforeExpiry: 'P30D' + } + } + ] + } + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "kvvrsa002" + }, + "enablePurgeProtection": { + "value": false + }, + "enableRbacAuthorization": { + "value": true + }, + "keys": { + "value": [ + { + "attributes": { + "exp": 1725109032, + "nbf": 10000 + }, + "kty": "RSA", + "name": "keyName", + "rotationPolicy": { + "attributes": { + "expiryTime": "P2Y" + }, + "lifetimeActions": [ + { + "action": { + "type": "Rotate" + }, + "trigger": { + "timeBeforeExpiry": "P2M" + } + }, + { + "action": { + "type": "Notify" + }, + "trigger": { + "timeBeforeExpiry": "P30D" + } + } + ] + } + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/key-vault/vault:' + +// Required parameters +param name = 'kvvrsa002' +// Non-required parameters +param enablePurgeProtection = false +param enableRbacAuthorization = true +param keys = [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + kty: 'RSA' + name: 'keyName' + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + action: { + type: 'Rotate' + } + trigger: { + timeBeforeExpiry: 'P2M' + } + } + { + action: { + type: 'Notify' + } + trigger: { + timeBeforeExpiry: 'P30D' + } + } + ] + } + } +] +``` + +
+

+ +### Example 5: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module vault 'br/public:avm/res/key-vault/vault:' = { + name: 'vaultDeployment' + params: { + // Required parameters + name: 'kvvwaf002' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + enablePurgeProtection: false + enableRbacAuthorization: true + keys: [ + { + attributes: { + enabled: true + exp: 1702648632 + nbf: 10000 + } + keySize: 4096 + name: 'keyName' + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + action: { + type: 'Rotate' + } + trigger: { + timeBeforeExpiry: 'P2M' + } + } + { + action: { + type: 'Notify' + } + trigger: { + timeBeforeExpiry: 'P30D' + } + } + ] + } + } + ] + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + } + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'vault' + subnetResourceId: '' + } + ] + secrets: [ + { + attributes: { + enabled: true + exp: 1702648632 + nbf: 10000 + } + contentType: 'Something' + name: 'secretName' + value: 'secretValue' + } + ] + softDeleteRetentionInDays: 7 + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "kvvwaf002" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "enablePurgeProtection": { + "value": false + }, + "enableRbacAuthorization": { + "value": true + }, + "keys": { + "value": [ + { + "attributes": { + "enabled": true, + "exp": 1702648632, + "nbf": 10000 + }, + "keySize": 4096, + "name": "keyName", + "rotationPolicy": { + "attributes": { + "expiryTime": "P2Y" + }, + "lifetimeActions": [ + { + "action": { + "type": "Rotate" + }, + "trigger": { + "timeBeforeExpiry": "P2M" + } + }, + { + "action": { + "type": "Notify" + }, + "trigger": { + "timeBeforeExpiry": "P30D" + } + } + ] + } + } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "Deny" + } + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "vault", + "subnetResourceId": "" + } + ] + }, + "secrets": { + "value": [ + { + "attributes": { + "enabled": true, + "exp": 1702648632, + "nbf": 10000 + }, + "contentType": "Something", + "name": "secretName", + "value": "secretValue" + } + ] + }, + "softDeleteRetentionInDays": { + "value": 7 + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/key-vault/vault:' + +// Required parameters +param name = 'kvvwaf002' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enablePurgeProtection = false +param enableRbacAuthorization = true +param keys = [ + { + attributes: { + enabled: true + exp: 1702648632 + nbf: 10000 + } + keySize: 4096 + name: 'keyName' + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + action: { + type: 'Rotate' + } + trigger: { + timeBeforeExpiry: 'P2M' + } + } + { + action: { + type: 'Notify' + } + trigger: { + timeBeforeExpiry: 'P30D' + } + } + ] + } + } +] +param networkAcls = { + bypass: 'AzureServices' + defaultAction: 'Deny' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'vault' + subnetResourceId: '' + } +] +param secrets = [ + { + attributes: { + enabled: true + exp: 1702648632 + nbf: 10000 + } + contentType: 'Something' + name: 'secretName' + value: 'secretValue' + } +] +param softDeleteRetentionInDays = 7 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Key Vault. Must be globally unique. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`accessPolicies`](#parameter-accesspolicies) | array | All access policies to create. | +| [`createMode`](#parameter-createmode) | string | The vault's create mode to indicate whether the vault need to be recovered or not. - recover or default. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enablePurgeProtection`](#parameter-enablepurgeprotection) | bool | Provide 'true' to enable Key Vault's purge protection feature. | +| [`enableRbacAuthorization`](#parameter-enablerbacauthorization) | bool | Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC. | +| [`enableSoftDelete`](#parameter-enablesoftdelete) | bool | Switch to enable/disable Key Vault's soft delete feature. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`enableVaultForDeployment`](#parameter-enablevaultfordeployment) | bool | Specifies if the vault is enabled for deployment by script or compute. | +| [`enableVaultForDiskEncryption`](#parameter-enablevaultfordiskencryption) | bool | Specifies if the azure platform has access to the vault for enabling disk encryption scenarios. | +| [`enableVaultForTemplateDeployment`](#parameter-enablevaultfortemplatedeployment) | bool | Specifies if the vault is enabled for a template deployment. | +| [`keys`](#parameter-keys) | array | All keys to create. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`networkAcls`](#parameter-networkacls) | object | Rules governing the accessibility of the resource from specific network locations. | +| [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`secrets`](#parameter-secrets) | array | All secrets to create. | +| [`sku`](#parameter-sku) | string | Specifies the SKU for the vault. | +| [`softDeleteRetentionInDays`](#parameter-softdeleteretentionindays) | int | softDelete data retention days. It accepts >=7 and <=90. | +| [`tags`](#parameter-tags) | object | Resource tags. | + +### Parameter: `name` + +Name of the Key Vault. Must be globally unique. + +- Required: Yes +- Type: string + +### Parameter: `accessPolicies` + +All access policies to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`objectId`](#parameter-accesspoliciesobjectid) | string | The object ID of a user, service principal or security group in the tenant for the vault. | +| [`permissions`](#parameter-accesspoliciespermissions) | object | Permissions the identity has for keys, secrets and certificates. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationId`](#parameter-accesspoliciesapplicationid) | string | Application ID of the client making request on behalf of a principal. | +| [`tenantId`](#parameter-accesspoliciestenantid) | string | The tenant ID that is used for authenticating requests to the key vault. | + +### Parameter: `accessPolicies.objectId` + +The object ID of a user, service principal or security group in the tenant for the vault. + +- Required: Yes +- Type: string + +### Parameter: `accessPolicies.permissions` + +Permissions the identity has for keys, secrets and certificates. + +- Required: Yes +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`certificates`](#parameter-accesspoliciespermissionscertificates) | array | Permissions to certificates. | +| [`keys`](#parameter-accesspoliciespermissionskeys) | array | Permissions to keys. | +| [`secrets`](#parameter-accesspoliciespermissionssecrets) | array | Permissions to secrets. | +| [`storage`](#parameter-accesspoliciespermissionsstorage) | array | Permissions to storage accounts. | + +### Parameter: `accessPolicies.permissions.certificates` + +Permissions to certificates. + +- Required: No +- Type: array +- Allowed: + ```Bicep + [ + 'all' + 'backup' + 'create' + 'delete' + 'deleteissuers' + 'get' + 'getissuers' + 'import' + 'list' + 'listissuers' + 'managecontacts' + 'manageissuers' + 'purge' + 'recover' + 'restore' + 'setissuers' + 'update' + ] + ``` + +### Parameter: `accessPolicies.permissions.keys` + +Permissions to keys. + +- Required: No +- Type: array +- Allowed: + ```Bicep + [ + 'all' + 'backup' + 'create' + 'decrypt' + 'delete' + 'encrypt' + 'get' + 'getrotationpolicy' + 'import' + 'list' + 'purge' + 'recover' + 'release' + 'restore' + 'rotate' + 'setrotationpolicy' + 'sign' + 'unwrapKey' + 'update' + 'verify' + 'wrapKey' + ] + ``` + +### Parameter: `accessPolicies.permissions.secrets` + +Permissions to secrets. + +- Required: No +- Type: array +- Allowed: + ```Bicep + [ + 'all' + 'backup' + 'delete' + 'get' + 'list' + 'purge' + 'recover' + 'restore' + 'set' + ] + ``` + +### Parameter: `accessPolicies.permissions.storage` + +Permissions to storage accounts. + +- Required: No +- Type: array +- Allowed: + ```Bicep + [ + 'all' + 'backup' + 'delete' + 'deletesas' + 'get' + 'getsas' + 'list' + 'listsas' + 'purge' + 'recover' + 'regeneratekey' + 'restore' + 'set' + 'setsas' + 'update' + ] + ``` + +### Parameter: `accessPolicies.applicationId` + +Application ID of the client making request on behalf of a principal. + +- Required: No +- Type: string + +### Parameter: `accessPolicies.tenantId` + +The tenant ID that is used for authenticating requests to the key vault. + +- Required: No +- Type: string + +### Parameter: `createMode` + +The vault's create mode to indicate whether the vault need to be recovered or not. - recover or default. + +- Required: No +- Type: string +- Default: `'default'` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of the diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of the diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enablePurgeProtection` + +Provide 'true' to enable Key Vault's purge protection feature. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableRbacAuthorization` + +Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableSoftDelete` + +Switch to enable/disable Key Vault's soft delete feature. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableVaultForDeployment` + +Specifies if the vault is enabled for deployment by script or compute. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableVaultForDiskEncryption` + +Specifies if the azure platform has access to the vault for enabling disk encryption scenarios. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableVaultForTemplateDeployment` + +Specifies if the vault is enabled for a template deployment. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `keys` + +All keys to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-keysname) | string | The name of the key. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`attributes`](#parameter-keysattributes) | object | Contains attributes of the key. | +| [`curveName`](#parameter-keyscurvename) | string | The elliptic curve name. Only works if "keySize" equals "EC" or "EC-HSM". Default is "P-256". | +| [`keyOps`](#parameter-keyskeyops) | array | The allowed operations on this key. | +| [`keySize`](#parameter-keyskeysize) | int | The key size in bits. Only works if "keySize" equals "RSA" or "RSA-HSM". Default is "4096". | +| [`kty`](#parameter-keyskty) | string | The type of the key. Default is "EC". | +| [`releasePolicy`](#parameter-keysreleasepolicy) | object | Key release policy. | +| [`roleAssignments`](#parameter-keysroleassignments) | array | Array of role assignments to create. | +| [`rotationPolicy`](#parameter-keysrotationpolicy) | object | Key rotation policy. | +| [`tags`](#parameter-keystags) | object | Resource tags. | + +### Parameter: `keys.name` + +The name of the key. + +- Required: Yes +- Type: string + +### Parameter: `keys.attributes` + +Contains attributes of the key. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-keysattributesenabled) | bool | Defines whether the key is enabled or disabled. | +| [`exp`](#parameter-keysattributesexp) | int | Defines when the key will become invalid. Defined in seconds since 1970-01-01T00:00:00Z. | +| [`nbf`](#parameter-keysattributesnbf) | int | If set, defines the date from which onwards the key becomes valid. Defined in seconds since 1970-01-01T00:00:00Z. | + +### Parameter: `keys.attributes.enabled` + +Defines whether the key is enabled or disabled. + +- Required: No +- Type: bool + +### Parameter: `keys.attributes.exp` + +Defines when the key will become invalid. Defined in seconds since 1970-01-01T00:00:00Z. + +- Required: No +- Type: int + +### Parameter: `keys.attributes.nbf` + +If set, defines the date from which onwards the key becomes valid. Defined in seconds since 1970-01-01T00:00:00Z. + +- Required: No +- Type: int + +### Parameter: `keys.curveName` + +The elliptic curve name. Only works if "keySize" equals "EC" or "EC-HSM". Default is "P-256". + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'P-256' + 'P-256K' + 'P-384' + 'P-521' + ] + ``` + +### Parameter: `keys.keyOps` + +The allowed operations on this key. + +- Required: No +- Type: array +- Allowed: + ```Bicep + [ + 'decrypt' + 'encrypt' + 'import' + 'release' + 'sign' + 'unwrapKey' + 'verify' + 'wrapKey' + ] + ``` + +### Parameter: `keys.keySize` + +The key size in bits. Only works if "keySize" equals "RSA" or "RSA-HSM". Default is "4096". + +- Required: No +- Type: int +- Allowed: + ```Bicep + [ + 2048 + 3072 + 4096 + ] + ``` + +### Parameter: `keys.kty` + +The type of the key. Default is "EC". + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'EC' + 'EC-HSM' + 'RSA' + 'RSA-HSM' + ] + ``` + +### Parameter: `keys.releasePolicy` + +Key release policy. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`contentType`](#parameter-keysreleasepolicycontenttype) | string | Content type and version of key release policy. | +| [`data`](#parameter-keysreleasepolicydata) | string | Blob encoding the policy rules under which the key can be released. | + +### Parameter: `keys.releasePolicy.contentType` + +Content type and version of key release policy. + +- Required: No +- Type: string + +### Parameter: `keys.releasePolicy.data` + +Blob encoding the policy rules under which the key can be released. + +- Required: No +- Type: string + +### Parameter: `keys.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Contributor'` + - `'Key Vault Crypto Officer'` + - `'Key Vault Crypto Service Encryption User'` + - `'Key Vault Crypto User'` + - `'Key Vault Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-keysroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-keysroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-keysroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-keysroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-keysroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-keysroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-keysroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-keysroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `keys.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `keys.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `keys.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `keys.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `keys.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `keys.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `keys.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `keys.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `keys.rotationPolicy` + +Key rotation policy. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`attributes`](#parameter-keysrotationpolicyattributes) | object | The attributes of key rotation policy. | +| [`lifetimeActions`](#parameter-keysrotationpolicylifetimeactions) | array | The lifetimeActions for key rotation action. | + +### Parameter: `keys.rotationPolicy.attributes` + +The attributes of key rotation policy. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`expiryTime`](#parameter-keysrotationpolicyattributesexpirytime) | string | The expiration time for the new key version. It should be in ISO8601 format. Eg: "P90D", "P1Y". | + +### Parameter: `keys.rotationPolicy.attributes.expiryTime` + +The expiration time for the new key version. It should be in ISO8601 format. Eg: "P90D", "P1Y". + +- Required: No +- Type: string + +### Parameter: `keys.rotationPolicy.lifetimeActions` + +The lifetimeActions for key rotation action. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`action`](#parameter-keysrotationpolicylifetimeactionsaction) | object | The action of key rotation policy lifetimeAction. | +| [`trigger`](#parameter-keysrotationpolicylifetimeactionstrigger) | object | The trigger of key rotation policy lifetimeAction. | + +### Parameter: `keys.rotationPolicy.lifetimeActions.action` + +The action of key rotation policy lifetimeAction. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`type`](#parameter-keysrotationpolicylifetimeactionsactiontype) | string | The type of action. | + +### Parameter: `keys.rotationPolicy.lifetimeActions.action.type` + +The type of action. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Notify' + 'Rotate' + ] + ``` + +### Parameter: `keys.rotationPolicy.lifetimeActions.trigger` + +The trigger of key rotation policy lifetimeAction. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`timeAfterCreate`](#parameter-keysrotationpolicylifetimeactionstriggertimeaftercreate) | string | The time duration after key creation to rotate the key. It only applies to rotate. It will be in ISO 8601 duration format. Eg: "P90D", "P1Y". | +| [`timeBeforeExpiry`](#parameter-keysrotationpolicylifetimeactionstriggertimebeforeexpiry) | string | The time duration before key expiring to rotate or notify. It will be in ISO 8601 duration format. Eg: "P90D", "P1Y". | + +### Parameter: `keys.rotationPolicy.lifetimeActions.trigger.timeAfterCreate` + +The time duration after key creation to rotate the key. It only applies to rotate. It will be in ISO 8601 duration format. Eg: "P90D", "P1Y". + +- Required: No +- Type: string + +### Parameter: `keys.rotationPolicy.lifetimeActions.trigger.timeBeforeExpiry` + +The time duration before key expiring to rotate or notify. It will be in ISO 8601 duration format. Eg: "P90D", "P1Y". + +- Required: No +- Type: string + +### Parameter: `keys.tags` + +Resource tags. + +- Required: No +- Type: object + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `networkAcls` + +Rules governing the accessibility of the resource from specific network locations. + +- Required: No +- Type: object + +### Parameter: `privateEndpoints` + +Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationSecurityGroupResourceIds`](#parameter-privateendpointsapplicationsecuritygroupresourceids) | array | Application security groups in which the Private Endpoint IP configuration is included. | +| [`customDnsConfigs`](#parameter-privateendpointscustomdnsconfigs) | array | Custom DNS configurations. | +| [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the Private Endpoint. | +| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | +| [`location`](#parameter-privateendpointslocation) | string | The location to deploy the Private Endpoint to. | +| [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | +| [`name`](#parameter-privateendpointsname) | string | The name of the Private Endpoint. | +| [`privateDnsZoneGroup`](#parameter-privateendpointsprivatednszonegroup) | object | The private DNS Zone Group to configure for the Private Endpoint. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | +| [`resourceGroupResourceId`](#parameter-privateendpointsresourcegroupresourceid) | string | The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the Private Endpoint for. For example "vault" for a Key Vault Private Endpoint. | +| [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/Resource Groups in this deployment. | + +### Parameter: `privateEndpoints.subnetResourceId` + +Resource ID of the subnet where the endpoint needs to be created. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.applicationSecurityGroupResourceIds` + +Application security groups in which the Private Endpoint IP configuration is included. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs` + +Custom DNS configurations. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | FQDN that resolves to private endpoint IP address. | + +### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +A list of private IP addresses of the private endpoint. + +- Required: Yes +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +FQDN that resolves to private endpoint IP address. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.customNetworkInterfaceName` + +The custom name of the network interface attached to the Private Endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.ipConfigurations` + +A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsipconfigurationsname) | string | The name of the resource that is unique within a resource group. | +| [`properties`](#parameter-privateendpointsipconfigurationsproperties) | object | Properties of private endpoint IP configurations. | + +### Parameter: `privateEndpoints.ipConfigurations.name` + +The name of the resource that is unique within a resource group. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties` + +Properties of private endpoint IP configurations. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private IP address obtained from the private endpoint's subnet. | + +### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` + +The ID of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.memberName` + +The member name of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` + +A private IP address obtained from the private endpoint's subnet. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.location` + +The location to deploy the Private Endpoint to. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.lock` + +Specify the type of lock. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-privateendpointslockkind) | string | Specify the type of lock. | +| [`name`](#parameter-privateendpointslockname) | string | Specify the name of lock. | + +### Parameter: `privateEndpoints.lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `privateEndpoints.lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.manualConnectionRequestMessage` + +A message passed to the owner of the remote resource with the manual connection request. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.name` + +The name of the Private Endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup` + +The private DNS Zone Group to configure for the Private Endpoint. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneGroupConfigs`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigs) | array | The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the Private DNS Zone Group. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs` + +The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneResourceId`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsprivatednszoneresourceid) | string | The resource id of the private DNS zone. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsname) | string | The name of the private DNS Zone Group config. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.privateDnsZoneResourceId` + +The resource id of the private DNS zone. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.name` + +The name of the private DNS Zone Group config. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.name` + +The name of the Private DNS Zone Group. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.resourceGroupResourceId` + +The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-privateendpointsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-privateendpointsroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-privateendpointsroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-privateendpointsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-privateendpointsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-privateendpointsroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-privateendpointsroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-privateendpointsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `privateEndpoints.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `privateEndpoints.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `privateEndpoints.service` + +The subresource to deploy the Private Endpoint for. For example "vault" for a Key Vault Private Endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.tags` + +Tags to be applied on all resources/Resource Groups in this deployment. + +- Required: No +- Type: object + +### Parameter: `publicNetworkAccess` + +Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Certificates Officer'` + - `'Key Vault Certificate User'` + - `'Key Vault Contributor'` + - `'Key Vault Crypto Officer'` + - `'Key Vault Crypto Service Encryption User'` + - `'Key Vault Crypto User'` + - `'Key Vault Reader'` + - `'Key Vault Secrets Officer'` + - `'Key Vault Secrets User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `secrets` + +All secrets to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-secretsname) | string | The name of the secret. | +| [`value`](#parameter-secretsvalue) | securestring | The value of the secret. NOTE: "value" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`attributes`](#parameter-secretsattributes) | object | Contains attributes of the secret. | +| [`contentType`](#parameter-secretscontenttype) | string | The content type of the secret. | +| [`roleAssignments`](#parameter-secretsroleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-secretstags) | object | Resource tags. | + +### Parameter: `secrets.name` + +The name of the secret. + +- Required: Yes +- Type: string + +### Parameter: `secrets.value` + +The value of the secret. NOTE: "value" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets. + +- Required: Yes +- Type: securestring + +### Parameter: `secrets.attributes` + +Contains attributes of the secret. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-secretsattributesenabled) | bool | Defines whether the secret is enabled or disabled. | +| [`exp`](#parameter-secretsattributesexp) | int | Defines when the secret will become invalid. Defined in seconds since 1970-01-01T00:00:00Z. | +| [`nbf`](#parameter-secretsattributesnbf) | int | If set, defines the date from which onwards the secret becomes valid. Defined in seconds since 1970-01-01T00:00:00Z. | + +### Parameter: `secrets.attributes.enabled` + +Defines whether the secret is enabled or disabled. + +- Required: No +- Type: bool + +### Parameter: `secrets.attributes.exp` + +Defines when the secret will become invalid. Defined in seconds since 1970-01-01T00:00:00Z. + +- Required: No +- Type: int + +### Parameter: `secrets.attributes.nbf` + +If set, defines the date from which onwards the secret becomes valid. Defined in seconds since 1970-01-01T00:00:00Z. + +- Required: No +- Type: int + +### Parameter: `secrets.contentType` + +The content type of the secret. + +- Required: No +- Type: string + +### Parameter: `secrets.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Contributor'` + - `'Key Vault Reader'` + - `'Key Vault Secrets Officer'` + - `'Key Vault Secrets User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-secretsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-secretsroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-secretsroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-secretsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-secretsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-secretsroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-secretsroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-secretsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `secrets.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `secrets.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `secrets.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `secrets.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `secrets.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `secrets.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `secrets.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `secrets.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `secrets.tags` + +Resource tags. + +- Required: No +- Type: object + +### Parameter: `sku` + +Specifies the SKU for the vault. + +- Required: No +- Type: string +- Default: `'premium'` +- Allowed: + ```Bicep + [ + 'premium' + 'standard' + ] + ``` + +### Parameter: `softDeleteRetentionInDays` + +softDelete data retention days. It accepts >=7 and <=90. + +- Required: No +- Type: int +- Default: `90` + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `keys` | array | The properties of the created keys. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the key vault. | +| `privateEndpoints` | array | The private endpoints of the key vault. | +| `resourceGroupName` | string | The name of the resource group the key vault was created in. | +| `resourceId` | string | The resource ID of the key vault. | +| `secrets` | array | The properties of the created secrets. | +| `uri` | string | The URI of the key vault. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/private-endpoint:0.10.1` | Remote reference | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/key-vault/vault/access-policy/README.md b/avm/1.1.0/res/key-vault/vault/access-policy/README.md new file mode 100644 index 000000000..96339cfd3 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/access-policy/README.md @@ -0,0 +1,212 @@ +# Key Vault Access Policies `[Microsoft.KeyVault/vaults/accessPolicies]` + +This module deploys a Key Vault Access Policy. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.KeyVault/vaults/accessPolicies` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2023-07-01/vaults/accessPolicies) | + +## Parameters + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVaultName`](#parameter-keyvaultname) | string | The name of the parent key vault. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`accessPolicies`](#parameter-accesspolicies) | array | An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID. | + +### Parameter: `keyVaultName` + +The name of the parent key vault. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `accessPolicies` + +An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`objectId`](#parameter-accesspoliciesobjectid) | string | The object ID of a user, service principal or security group in the tenant for the vault. | +| [`permissions`](#parameter-accesspoliciespermissions) | object | Permissions the identity has for keys, secrets and certificates. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationId`](#parameter-accesspoliciesapplicationid) | string | Application ID of the client making request on behalf of a principal. | +| [`tenantId`](#parameter-accesspoliciestenantid) | string | The tenant ID that is used for authenticating requests to the key vault. | + +### Parameter: `accessPolicies.objectId` + +The object ID of a user, service principal or security group in the tenant for the vault. + +- Required: Yes +- Type: string + +### Parameter: `accessPolicies.permissions` + +Permissions the identity has for keys, secrets and certificates. + +- Required: Yes +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`certificates`](#parameter-accesspoliciespermissionscertificates) | array | Permissions to certificates. | +| [`keys`](#parameter-accesspoliciespermissionskeys) | array | Permissions to keys. | +| [`secrets`](#parameter-accesspoliciespermissionssecrets) | array | Permissions to secrets. | +| [`storage`](#parameter-accesspoliciespermissionsstorage) | array | Permissions to storage accounts. | + +### Parameter: `accessPolicies.permissions.certificates` + +Permissions to certificates. + +- Required: No +- Type: array +- Allowed: + ```Bicep + [ + 'all' + 'backup' + 'create' + 'delete' + 'deleteissuers' + 'get' + 'getissuers' + 'import' + 'list' + 'listissuers' + 'managecontacts' + 'manageissuers' + 'purge' + 'recover' + 'restore' + 'setissuers' + 'update' + ] + ``` + +### Parameter: `accessPolicies.permissions.keys` + +Permissions to keys. + +- Required: No +- Type: array +- Allowed: + ```Bicep + [ + 'all' + 'backup' + 'create' + 'decrypt' + 'delete' + 'encrypt' + 'get' + 'getrotationpolicy' + 'import' + 'list' + 'purge' + 'recover' + 'release' + 'restore' + 'rotate' + 'setrotationpolicy' + 'sign' + 'unwrapKey' + 'update' + 'verify' + 'wrapKey' + ] + ``` + +### Parameter: `accessPolicies.permissions.secrets` + +Permissions to secrets. + +- Required: No +- Type: array +- Allowed: + ```Bicep + [ + 'all' + 'backup' + 'delete' + 'get' + 'list' + 'purge' + 'recover' + 'restore' + 'set' + ] + ``` + +### Parameter: `accessPolicies.permissions.storage` + +Permissions to storage accounts. + +- Required: No +- Type: array +- Allowed: + ```Bicep + [ + 'all' + 'backup' + 'delete' + 'deletesas' + 'get' + 'getsas' + 'list' + 'listsas' + 'purge' + 'recover' + 'regeneratekey' + 'restore' + 'set' + 'setsas' + 'update' + ] + ``` + +### Parameter: `accessPolicies.applicationId` + +Application ID of the client making request on behalf of a principal. + +- Required: No +- Type: string + +### Parameter: `accessPolicies.tenantId` + +The tenant ID that is used for authenticating requests to the key vault. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the access policies assignment. | +| `resourceGroupName` | string | The name of the resource group the access policies assignment was created in. | +| `resourceId` | string | The resource ID of the access policies assignment. | diff --git a/avm/1.1.0/res/key-vault/vault/access-policy/main.bicep b/avm/1.1.0/res/key-vault/vault/access-policy/main.bicep new file mode 100644 index 000000000..586ee9e87 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/access-policy/main.bicep @@ -0,0 +1,120 @@ +metadata name = 'Key Vault Access Policies' +metadata description = 'This module deploys a Key Vault Access Policy.' + +@description('Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment.') +param keyVaultName string + +@description('Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault\'s tenant ID.') +param accessPolicies accessPoliciesType[]? + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +resource policies 'Microsoft.KeyVault/vaults/accessPolicies@2023-07-01' = { + name: 'add' + parent: keyVault + properties: { + accessPolicies: [ + for accessPolicy in (accessPolicies ?? []): { + applicationId: accessPolicy.?applicationId ?? '' + objectId: accessPolicy.objectId + permissions: accessPolicy.permissions + tenantId: accessPolicy.?tenantId ?? tenant().tenantId + } + ] + } +} + +@description('The name of the resource group the access policies assignment was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the access policies assignment.') +output name string = policies.name + +@description('The resource ID of the access policies assignment.') +output resourceId string = policies.id + +// ================ // +// Definitions // +// ================ // +@export() +@description('The type for an access policy.') +type accessPoliciesType = { + @description('Optional. The tenant ID that is used for authenticating requests to the key vault.') + tenantId: string? + + @description('Required. The object ID of a user, service principal or security group in the tenant for the vault.') + objectId: string + + @description('Optional. Application ID of the client making request on behalf of a principal.') + applicationId: string? + + @description('Required. Permissions the identity has for keys, secrets and certificates.') + permissions: { + @description('Optional. Permissions to keys.') + keys: ( + | 'all' + | 'backup' + | 'create' + | 'decrypt' + | 'delete' + | 'encrypt' + | 'get' + | 'getrotationpolicy' + | 'import' + | 'list' + | 'purge' + | 'recover' + | 'release' + | 'restore' + | 'rotate' + | 'setrotationpolicy' + | 'sign' + | 'unwrapKey' + | 'update' + | 'verify' + | 'wrapKey')[]? + + @description('Optional. Permissions to secrets.') + secrets: ('all' | 'backup' | 'delete' | 'get' | 'list' | 'purge' | 'recover' | 'restore' | 'set')[]? + + @description('Optional. Permissions to certificates.') + certificates: ( + | 'all' + | 'backup' + | 'create' + | 'delete' + | 'deleteissuers' + | 'get' + | 'getissuers' + | 'import' + | 'list' + | 'listissuers' + | 'managecontacts' + | 'manageissuers' + | 'purge' + | 'recover' + | 'restore' + | 'setissuers' + | 'update')[]? + + @description('Optional. Permissions to storage accounts.') + storage: ( + | 'all' + | 'backup' + | 'delete' + | 'deletesas' + | 'get' + | 'getsas' + | 'list' + | 'listsas' + | 'purge' + | 'recover' + | 'regeneratekey' + | 'restore' + | 'set' + | 'setsas' + | 'update')[]? + } +} diff --git a/avm/1.1.0/res/key-vault/vault/access-policy/main.json b/avm/1.1.0/res/key-vault/vault/access-policy/main.json new file mode 100644 index 000000000..1b7d43a37 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/access-policy/main.json @@ -0,0 +1,219 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "15662374115599475123" + }, + "name": "Key Vault Access Policies", + "description": "This module deploys a Key Vault Access Policy." + }, + "definitions": { + "accessPoliciesType": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + }, + "metadata": { + "description": "Required. Permissions the identity has for keys, secrets and certificates." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an access policy." + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "accessPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/accessPoliciesType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "policies": { + "type": "Microsoft.KeyVault/vaults/accessPolicies", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", + "properties": { + "copy": [ + { + "name": "accessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('accessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('accessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('accessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('accessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ] + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the access policies assignment was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the access policies assignment." + }, + "value": "add" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the access policies assignment." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', parameters('keyVaultName'), 'add')]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/key-vault/vault/key/README.md b/avm/1.1.0/res/key-vault/vault/key/README.md new file mode 100644 index 000000000..0294ca74b --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/key/README.md @@ -0,0 +1,291 @@ +# Key Vault Keys `[Microsoft.KeyVault/vaults/keys]` + +This module deploys a Key Vault Key. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.KeyVault/vaults/keys` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/keys) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the key. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVaultName`](#parameter-keyvaultname) | string | The name of the parent key vault. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`attributesEnabled`](#parameter-attributesenabled) | bool | Determines whether the object is enabled. | +| [`attributesExp`](#parameter-attributesexp) | int | Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible. | +| [`attributesNbf`](#parameter-attributesnbf) | int | Not before date in seconds since 1970-01-01T00:00:00Z. | +| [`curveName`](#parameter-curvename) | string | The elliptic curve name. | +| [`keyOps`](#parameter-keyops) | array | Array of JsonWebKeyOperation. | +| [`keySize`](#parameter-keysize) | int | The key size in bits. For example: 2048, 3072, or 4096 for RSA. | +| [`kty`](#parameter-kty) | string | The type of the key. | +| [`releasePolicy`](#parameter-releasepolicy) | object | Key release policy. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`rotationPolicy`](#parameter-rotationpolicy) | object | Key rotation policy properties object. | +| [`tags`](#parameter-tags) | object | Resource tags. | + +### Parameter: `name` + +The name of the key. + +- Required: Yes +- Type: string + +### Parameter: `keyVaultName` + +The name of the parent key vault. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `attributesEnabled` + +Determines whether the object is enabled. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `attributesExp` + +Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible. + +- Required: No +- Type: int + +### Parameter: `attributesNbf` + +Not before date in seconds since 1970-01-01T00:00:00Z. + +- Required: No +- Type: int + +### Parameter: `curveName` + +The elliptic curve name. + +- Required: No +- Type: string +- Default: `'P-256'` +- Allowed: + ```Bicep + [ + 'P-256' + 'P-256K' + 'P-384' + 'P-521' + ] + ``` + +### Parameter: `keyOps` + +Array of JsonWebKeyOperation. + +- Required: No +- Type: array +- Allowed: + ```Bicep + [ + 'decrypt' + 'encrypt' + 'import' + 'sign' + 'unwrapKey' + 'verify' + 'wrapKey' + ] + ``` + +### Parameter: `keySize` + +The key size in bits. For example: 2048, 3072, or 4096 for RSA. + +- Required: No +- Type: int + +### Parameter: `kty` + +The type of the key. + +- Required: No +- Type: string +- Default: `'EC'` +- Allowed: + ```Bicep + [ + 'EC' + 'EC-HSM' + 'RSA' + 'RSA-HSM' + ] + ``` + +### Parameter: `releasePolicy` + +Key release policy. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Contributor'` + - `'Key Vault Crypto Officer'` + - `'Key Vault Crypto Service Encryption User'` + - `'Key Vault Crypto User'` + - `'Key Vault Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `rotationPolicy` + +Key rotation policy properties object. + +- Required: No +- Type: object + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `keyUri` | string | The uri of the key. | +| `keyUriWithVersion` | string | The uri with version of the key. | +| `name` | string | The name of the key. | +| `resourceGroupName` | string | The name of the resource group the key was created in. | +| `resourceId` | string | The resource ID of the key. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | diff --git a/avm/1.1.0/res/key-vault/vault/key/main.bicep b/avm/1.1.0/res/key-vault/vault/key/main.bicep new file mode 100644 index 000000000..cfa77aa87 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/key/main.bicep @@ -0,0 +1,170 @@ +metadata name = 'Key Vault Keys' +metadata description = 'This module deploys a Key Vault Key.' + +@description('Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment.') +param keyVaultName string + +@description('Required. The name of the key.') +param name string + +@description('Optional. Resource tags.') +param tags object? + +@description('Optional. Determines whether the object is enabled.') +param attributesEnabled bool = true + +@description('Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible.') +param attributesExp int? + +@description('Optional. Not before date in seconds since 1970-01-01T00:00:00Z.') +param attributesNbf int? + +@description('Optional. The elliptic curve name.') +@allowed([ + 'P-256' + 'P-256K' + 'P-384' + 'P-521' +]) +param curveName string = 'P-256' + +@description('Optional. Array of JsonWebKeyOperation.') +@allowed([ + 'decrypt' + 'encrypt' + 'import' + 'sign' + 'unwrapKey' + 'verify' + 'wrapKey' +]) +param keyOps array? + +@description('Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA.') +param keySize int? + +@description('Optional. The type of the key.') +@allowed([ + 'EC' + 'EC-HSM' + 'RSA' + 'RSA-HSM' +]) +param kty string = 'EC' + +@description('Optional. Key release policy.') +param releasePolicy object? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Key rotation policy properties object.') +param rotationPolicy object? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Key Vault Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '00482a5a-887f-4fb3-b363-3b7fe8e74483' + ) + 'Key Vault Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f25e0fa2-a7c8-4377-a976-54943a77a395' + ) + 'Key Vault Crypto Officer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '14b46e9e-c2b7-41b4-b07b-48a6ebf60603' + ) + 'Key Vault Crypto Service Encryption User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'e147488a-f6f5-4113-8e2d-b22465e65bf6' + ) + 'Key Vault Crypto User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) + 'Key Vault Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '21090545-7ca7-4776-b22c-e363652d74d2' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +resource key 'Microsoft.KeyVault/vaults/keys@2022-07-01' = { + name: name + parent: keyVault + tags: tags + properties: { + attributes: { + enabled: attributesEnabled + exp: attributesExp + nbf: attributesNbf + } + curveName: curveName + keyOps: keyOps + keySize: keySize + kty: kty + release_policy: releasePolicy ?? {} + ...(!empty(rotationPolicy) + ? { + rotationPolicy: rotationPolicy + } + : {}) + } +} + +resource key_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(key.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: key + } +] + +@description('The uri of the key.') +output keyUri string = key.properties.keyUri + +@description('The uri with version of the key.') +output keyUriWithVersion string = key.properties.keyUriWithVersion + +@description('The name of the key.') +output name string = key.name + +@description('The resource ID of the key.') +output resourceId string = key.id + +@description('The name of the resource group the key was created in.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/key-vault/vault/key/main.json b/avm/1.1.0/res/key-vault/vault/key/main.json new file mode 100644 index 000000000..ecd8d6c83 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/key/main.json @@ -0,0 +1,302 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "8627699258587559559" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "curveName": { + "type": "string", + "defaultValue": "P-256", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "metadata": { + "description": "Optional. The elliptic curve name." + } + }, + "keyOps": { + "type": "array", + "nullable": true, + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "metadata": { + "description": "Optional. Array of JsonWebKeyOperation." + } + }, + "keySize": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." + } + }, + "kty": { + "type": "string", + "defaultValue": "EC", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "metadata": { + "description": "Optional. The type of the key." + } + }, + "releasePolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "rotationPolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy properties object." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "key": { + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": "[shallowMerge(createArray(createObject('attributes', createObject('enabled', parameters('attributesEnabled'), 'exp', parameters('attributesExp'), 'nbf', parameters('attributesNbf')), 'curveName', parameters('curveName'), 'keyOps', parameters('keyOps'), 'keySize', parameters('keySize'), 'kty', parameters('kty'), 'release_policy', coalesce(parameters('releasePolicy'), createObject())), if(not(empty(parameters('rotationPolicy'))), createObject('rotationPolicy', parameters('rotationPolicy')), createObject())))]" + }, + "key_roleAssignments": { + "copy": { + "name": "key_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "key" + ] + } + }, + "outputs": { + "keyUri": { + "type": "string", + "metadata": { + "description": "The uri of the key." + }, + "value": "[reference('key').keyUri]" + }, + "keyUriWithVersion": { + "type": "string", + "metadata": { + "description": "The uri with version of the key." + }, + "value": "[reference('key').keyUriWithVersion]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the key." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the key was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/key-vault/vault/main.bicep b/avm/1.1.0/res/key-vault/vault/main.bicep new file mode 100644 index 000000000..1650de8ae --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/main.bicep @@ -0,0 +1,651 @@ +metadata name = 'Key Vaults' +metadata description = 'This module deploys a Key Vault.' + +// ================ // +// Parameters // +// ================ // +@description('Required. Name of the Key Vault. Must be globally unique.') +@maxLength(24) +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. All access policies to create.') +param accessPolicies accessPolicyType[]? + +@description('Optional. All secrets to create.') +param secrets secretType[]? + +@description('Optional. All keys to create.') +param keys keyType[]? + +@description('Optional. Specifies if the vault is enabled for deployment by script or compute.') +param enableVaultForDeployment bool = true + +@description('Optional. Specifies if the vault is enabled for a template deployment.') +param enableVaultForTemplateDeployment bool = true + +@description('Optional. Specifies if the azure platform has access to the vault for enabling disk encryption scenarios.') +param enableVaultForDiskEncryption bool = true + +@description('Optional. Switch to enable/disable Key Vault\'s soft delete feature.') +param enableSoftDelete bool = true + +@description('Optional. softDelete data retention days. It accepts >=7 and <=90.') +param softDeleteRetentionInDays int = 90 + +@description('Optional. Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC.') +param enableRbacAuthorization bool = true + +@description('Optional. The vault\'s create mode to indicate whether the vault need to be recovered or not. - recover or default.') +param createMode string = 'default' + +@description('Optional. Provide \'true\' to enable Key Vault\'s purge protection feature.') +param enablePurgeProtection bool = true + +@description('Optional. Specifies the SKU for the vault.') +@allowed([ + 'premium' + 'standard' +]) +param sku string = 'premium' + +@description('Optional. Rules governing the accessibility of the resource from specific network locations.') +param networkAcls object? + +@description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set.') +@allowed([ + '' + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string = '' + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointSingleServiceType[]? + +@description('Optional. Resource tags.') +param tags object? + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// =========== // +// Variables // +// =========== // + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Key Vault Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '00482a5a-887f-4fb3-b363-3b7fe8e74483' + ) + 'Key Vault Certificates Officer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a4417e6f-fecd-4de8-b567-7b0420556985' + ) + 'Key Vault Certificate User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'db79e9a7-68ee-4b58-9aeb-b90e7c24fcba' + ) + 'Key Vault Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f25e0fa2-a7c8-4377-a976-54943a77a395' + ) + 'Key Vault Crypto Officer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '14b46e9e-c2b7-41b4-b07b-48a6ebf60603' + ) + 'Key Vault Crypto Service Encryption User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'e147488a-f6f5-4113-8e2d-b22465e65bf6' + ) + 'Key Vault Crypto User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) + 'Key Vault Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '21090545-7ca7-4776-b22c-e363652d74d2' + ) + 'Key Vault Secrets Officer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7' + ) + 'Key Vault Secrets User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4633458b-17de-408a-b874-0445c86b69e6' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +var formattedAccessPolicies = [ + for accessPolicy in (accessPolicies ?? []): { + applicationId: accessPolicy.?applicationId ?? '' + objectId: accessPolicy.objectId + permissions: accessPolicy.permissions + tenantId: accessPolicy.?tenantId ?? tenant().tenantId + } +] + +// ============ // +// Dependencies // +// ============ // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.keyvault-vault.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: name + location: location + tags: tags + properties: { + enabledForDeployment: enableVaultForDeployment + enabledForTemplateDeployment: enableVaultForTemplateDeployment + enabledForDiskEncryption: enableVaultForDiskEncryption + enableSoftDelete: enableSoftDelete + softDeleteRetentionInDays: softDeleteRetentionInDays + enableRbacAuthorization: enableRbacAuthorization + createMode: createMode + enablePurgeProtection: enablePurgeProtection ? enablePurgeProtection : null + tenantId: subscription().tenantId + accessPolicies: formattedAccessPolicies + sku: { + name: sku + family: 'A' + } + networkAcls: !empty(networkAcls ?? {}) + ? { + bypass: networkAcls.?bypass + defaultAction: networkAcls.?defaultAction + virtualNetworkRules: networkAcls.?virtualNetworkRules ?? [] + ipRules: networkAcls.?ipRules ?? [] + } + : null + publicNetworkAccess: !empty(publicNetworkAccess) + ? publicNetworkAccess + : ((!empty(privateEndpoints ?? []) && empty(networkAcls ?? {})) ? 'Disabled' : null) + } +} + +resource keyVault_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: keyVault +} + +resource keyVault_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: keyVault + } +] + +module keyVault_accessPolicies 'access-policy/main.bicep' = if (!empty(accessPolicies)) { + name: '${uniqueString(deployment().name, location)}-KeyVault-AccessPolicies' + params: { + keyVaultName: keyVault.name + accessPolicies: accessPolicies + } +} + +module keyVault_secrets 'secret/main.bicep' = [ + for (secret, index) in (secrets ?? []): { + name: '${uniqueString(deployment().name, location)}-KeyVault-Secret-${index}' + params: { + name: secret.name + value: secret.value + keyVaultName: keyVault.name + attributesEnabled: secret.?attributes.?enabled + attributesExp: secret.?attributes.?exp + attributesNbf: secret.?attributes.?nbf + contentType: secret.?contentType + tags: secret.?tags ?? tags + roleAssignments: secret.?roleAssignments + } + } +] + +module keyVault_keys 'key/main.bicep' = [ + for (key, index) in (keys ?? []): { + name: '${uniqueString(deployment().name, location)}-KeyVault-Key-${index}' + params: { + name: key.name + keyVaultName: keyVault.name + attributesEnabled: key.?attributes.?enabled + attributesExp: key.?attributes.?exp + attributesNbf: key.?attributes.?nbf + curveName: (key.?kty != 'RSA' && key.?kty != 'RSA-HSM') ? (key.?curveName ?? 'P-256') : null + keyOps: key.?keyOps + keySize: (key.?kty == 'RSA' || key.?kty == 'RSA-HSM') ? (key.?keySize ?? 4096) : null + releasePolicy: key.?releasePolicy ?? {} + kty: key.?kty ?? 'EC' + tags: key.?tags ?? tags + roleAssignments: key.?roleAssignments + rotationPolicy: key.?rotationPolicy + } + } +] + +module keyVault_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.10.1' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-keyVault-PrivateEndpoint-${index}' + scope: resourceGroup( + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[2], + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[4] + ) + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(keyVault.id, '/'))}-${privateEndpoint.?service ?? 'vault'}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(keyVault.id, '/'))}-${privateEndpoint.?service ?? 'vault'}-${index}' + properties: { + privateLinkServiceId: keyVault.id + groupIds: [ + privateEndpoint.?service ?? 'vault' + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(keyVault.id, '/'))}-${privateEndpoint.?service ?? 'vault'}-${index}' + properties: { + privateLinkServiceId: keyVault.id + groupIds: [ + privateEndpoint.?service ?? 'vault' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] + : null + subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry + location: privateEndpoint.?location ?? reference( + split(privateEndpoint.subnetResourceId, '/subnets/')[0], + '2020-06-01', + 'Full' + ).location + lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } + } +] + +resource keyVault_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(keyVault.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: keyVault + } +] + +// =========== // +// Outputs // +// =========== // +@description('The resource ID of the key vault.') +output resourceId string = keyVault.id + +@description('The name of the resource group the key vault was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the key vault.') +output name string = keyVault.name + +@description('The URI of the key vault.') +output uri string = keyVault.properties.vaultUri + +@description('The location the resource was deployed into.') +output location string = keyVault.location + +@description('The private endpoints of the key vault.') +output privateEndpoints privateEndpointOutputType[] = [ + for (item, index) in (privateEndpoints ?? []): { + name: keyVault_privateEndpoints[index].outputs.name + resourceId: keyVault_privateEndpoints[index].outputs.resourceId + groupId: keyVault_privateEndpoints[index].outputs.?groupId! + customDnsConfigs: keyVault_privateEndpoints[index].outputs.customDnsConfigs + networkInterfaceResourceIds: keyVault_privateEndpoints[index].outputs.networkInterfaceResourceIds + } +] + +@description('The properties of the created secrets.') +output secrets credentialOutputType[] = [ + #disable-next-line outputs-should-not-contain-secrets // Only returning the references, not any secret value + for index in range(0, length(secrets ?? [])): { + resourceId: keyVault_secrets[index].outputs.resourceId + uri: keyVault_secrets[index].outputs.secretUri + uriWithVersion: keyVault_secrets[index].outputs.secretUriWithVersion + } +] + +@description('The properties of the created keys.') +output keys credentialOutputType[] = [ + for index in range(0, length(keys ?? [])): { + resourceId: keyVault_keys[index].outputs.resourceId + uri: keyVault_keys[index].outputs.keyUri + uriWithVersion: keyVault_keys[index].outputs.keyUriWithVersion + } +] + +// ================ // +// Definitions // +// ================ // +@export() +type privateEndpointOutputType = { + @description('The name of the private endpoint.') + name: string + + @description('The resource ID of the private endpoint.') + resourceId: string + + @description('The group Id for the private endpoint Group.') + groupId: string? + + @description('The custom DNS configurations of the private endpoint.') + customDnsConfigs: { + @description('FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @description('A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[] + + @description('The IDs of the network interfaces associated with the private endpoint.') + networkInterfaceResourceIds: string[] +} + +@export() +@description('The type for a credential output.') +type credentialOutputType = { + @description('The item\'s resourceId.') + resourceId: string + + @description('The item\'s uri.') + uri: string + + @description('The item\'s uri with version.') + uriWithVersion: string +} + +@export() +@description('The type for an access policy.') +type accessPolicyType = { + @description('Optional. The tenant ID that is used for authenticating requests to the key vault.') + tenantId: string? + + @description('Required. The object ID of a user, service principal or security group in the tenant for the vault.') + objectId: string + + @description('Optional. Application ID of the client making request on behalf of a principal.') + applicationId: string? + + @description('Required. Permissions the identity has for keys, secrets and certificates.') + permissions: { + @description('Optional. Permissions to keys.') + keys: ( + | 'all' + | 'backup' + | 'create' + | 'decrypt' + | 'delete' + | 'encrypt' + | 'get' + | 'getrotationpolicy' + | 'import' + | 'list' + | 'purge' + | 'recover' + | 'release' + | 'restore' + | 'rotate' + | 'setrotationpolicy' + | 'sign' + | 'unwrapKey' + | 'update' + | 'verify' + | 'wrapKey')[]? + + @description('Optional. Permissions to secrets.') + secrets: ('all' | 'backup' | 'delete' | 'get' | 'list' | 'purge' | 'recover' | 'restore' | 'set')[]? + + @description('Optional. Permissions to certificates.') + certificates: ( + | 'all' + | 'backup' + | 'create' + | 'delete' + | 'deleteissuers' + | 'get' + | 'getissuers' + | 'import' + | 'list' + | 'listissuers' + | 'managecontacts' + | 'manageissuers' + | 'purge' + | 'recover' + | 'restore' + | 'setissuers' + | 'update')[]? + + @description('Optional. Permissions to storage accounts.') + storage: ( + | 'all' + | 'backup' + | 'delete' + | 'deletesas' + | 'get' + | 'getsas' + | 'list' + | 'listsas' + | 'purge' + | 'recover' + | 'regeneratekey' + | 'restore' + | 'set' + | 'setsas' + | 'update')[]? + } +} + +@export() +@description('The type for a secret output.') +type secretType = { + @description('Required. The name of the secret.') + name: string + + @description('Optional. Resource tags.') + tags: object? + + @description('Optional. Contains attributes of the secret.') + attributes: { + @description('Optional. Defines whether the secret is enabled or disabled.') + enabled: bool? + + @description('Optional. Defines when the secret will become invalid. Defined in seconds since 1970-01-01T00:00:00Z.') + exp: int? + + @description('Optional. If set, defines the date from which onwards the secret becomes valid. Defined in seconds since 1970-01-01T00:00:00Z.') + nbf: int? + }? + @description('Optional. The content type of the secret.') + contentType: string? + + @description('Required. The value of the secret. NOTE: "value" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets.') + @secure() + value: string + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType[]? +} + +@export() +@description('The type for a key.') +type keyType = { + @description('Required. The name of the key.') + name: string + + @description('Optional. Resource tags.') + tags: object? + + @description('Optional. Contains attributes of the key.') + attributes: { + @description('Optional. Defines whether the key is enabled or disabled.') + enabled: bool? + + @description('Optional. Defines when the key will become invalid. Defined in seconds since 1970-01-01T00:00:00Z.') + exp: int? + + @description('Optional. If set, defines the date from which onwards the key becomes valid. Defined in seconds since 1970-01-01T00:00:00Z.') + nbf: int? + }? + @description('Optional. The elliptic curve name. Only works if "keySize" equals "EC" or "EC-HSM". Default is "P-256".') + curveName: ('P-256' | 'P-256K' | 'P-384' | 'P-521')? + + @description('Optional. The allowed operations on this key.') + keyOps: ('decrypt' | 'encrypt' | 'import' | 'release' | 'sign' | 'unwrapKey' | 'verify' | 'wrapKey')[]? + + @description('Optional. The key size in bits. Only works if "keySize" equals "RSA" or "RSA-HSM". Default is "4096".') + keySize: (2048 | 3072 | 4096)? + + @description('Optional. The type of the key. Default is "EC".') + kty: ('EC' | 'EC-HSM' | 'RSA' | 'RSA-HSM')? + + @description('Optional. Key release policy.') + releasePolicy: { + @description('Optional. Content type and version of key release policy.') + contentType: string? + + @description('Optional. Blob encoding the policy rules under which the key can be released.') + data: string? + }? + + @description('Optional. Key rotation policy.') + rotationPolicy: rotationPolicyType? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType[]? +} + +@description('The type for a rotation policy.') +type rotationPolicyType = { + @description('Optional. The attributes of key rotation policy.') + attributes: { + @description('Optional. The expiration time for the new key version. It should be in ISO8601 format. Eg: "P90D", "P1Y".') + expiryTime: string? + }? + + @description('Optional. The lifetimeActions for key rotation action.') + lifetimeActions: { + @description('Optional. The action of key rotation policy lifetimeAction.') + action: { + @description('Optional. The type of action.') + type: ('Notify' | 'Rotate')? + }? + + @description('Optional. The trigger of key rotation policy lifetimeAction.') + trigger: { + @description('Optional. The time duration after key creation to rotate the key. It only applies to rotate. It will be in ISO 8601 duration format. Eg: "P90D", "P1Y".') + timeAfterCreate: string? + + @description('Optional. The time duration before key expiring to rotate or notify. It will be in ISO 8601 duration format. Eg: "P90D", "P1Y".') + timeBeforeExpiry: string? + }? + }[]? +} diff --git a/avm/1.1.0/res/key-vault/vault/main.json b/avm/1.1.0/res/key-vault/vault/main.json new file mode 100644 index 000000000..2281286ba --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/main.json @@ -0,0 +1,3115 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "3889592928706338435" + }, + "name": "Key Vaults", + "description": "This module deploys a Key Vault." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "credentialOutputType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The item's resourceId." + } + }, + "uri": { + "type": "string", + "metadata": { + "description": "The item's uri." + } + }, + "uriWithVersion": { + "type": "string", + "metadata": { + "description": "The item's uri with version." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a credential output." + } + }, + "accessPolicyType": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + }, + "metadata": { + "description": "Required. Permissions the identity has for keys, secrets and certificates." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an access policy." + } + }, + "secretType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributes": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Defines whether the secret is enabled or disabled." + } + }, + "exp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Defines when the secret will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." + } + }, + "nbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. If set, defines the date from which onwards the secret becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Contains attributes of the secret." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a secret output." + } + }, + "keyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributes": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Defines whether the key is enabled or disabled." + } + }, + "exp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Defines when the key will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." + } + }, + "nbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. If set, defines the date from which onwards the key becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Contains attributes of the key." + } + }, + "curveName": { + "type": "string", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "nullable": true, + "metadata": { + "description": "Optional. The elliptic curve name. Only works if \"keySize\" equals \"EC\" or \"EC-HSM\". Default is \"P-256\"." + } + }, + "keyOps": { + "type": "array", + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "release", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. The allowed operations on this key." + } + }, + "keySize": { + "type": "int", + "allowedValues": [ + 2048, + 3072, + 4096 + ], + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. Only works if \"keySize\" equals \"RSA\" or \"RSA-HSM\". Default is \"4096\"." + } + }, + "kty": { + "type": "string", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the key. Default is \"EC\"." + } + }, + "releasePolicy": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Content type and version of key release policy." + } + }, + "data": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Blob encoding the policy rules under which the key can be released." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "rotationPolicy": { + "$ref": "#/definitions/rotationPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a key." + } + }, + "rotationPolicyType": { + "type": "object", + "properties": { + "attributes": { + "type": "object", + "properties": { + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiration time for the new key version. It should be in ISO8601 format. Eg: \"P90D\", \"P1Y\"." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The attributes of key rotation policy." + } + }, + "lifetimeActions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "action": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "Notify", + "Rotate" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of action." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The action of key rotation policy lifetimeAction." + } + }, + "trigger": { + "type": "object", + "properties": { + "timeAfterCreate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time duration after key creation to rotate the key. It only applies to rotate. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." + } + }, + "timeBeforeExpiry": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time duration before key expiring to rotate or notify. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The trigger of key rotation policy lifetimeAction." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The lifetimeActions for key rotation action." + } + } + }, + "metadata": { + "description": "The type for a rotation policy." + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateEndpointSingleServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private Endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the Private Endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the Private Endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Key Vault. Must be globally unique." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "accessPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/accessPolicyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All access policies to create." + } + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/secretType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All secrets to create." + } + }, + "keys": { + "type": "array", + "items": { + "$ref": "#/definitions/keyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. All keys to create." + } + }, + "enableVaultForDeployment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for deployment by script or compute." + } + }, + "enableVaultForTemplateDeployment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for a template deployment." + } + }, + "enableVaultForDiskEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the azure platform has access to the vault for enabling disk encryption scenarios." + } + }, + "enableSoftDelete": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Switch to enable/disable Key Vault's soft delete feature." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 90, + "metadata": { + "description": "Optional. softDelete data retention days. It accepts >=7 and <=90." + } + }, + "enableRbacAuthorization": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC." + } + }, + "createMode": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The vault's create mode to indicate whether the vault need to be recovered or not. - recover or default." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Provide 'true' to enable Key Vault's purge protection feature." + } + }, + "sku": { + "type": "string", + "defaultValue": "premium", + "allowedValues": [ + "premium", + "standard" + ], + "metadata": { + "description": "Optional. Specifies the SKU for the vault." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Rules governing the accessibility of the resource from specific network locations." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + { + "name": "formattedAccessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Certificates Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a4417e6f-fecd-4de8-b567-7b0420556985')]", + "Key Vault Certificate User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db79e9a7-68ee-4b58-9aeb-b90e7c24fcba')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.keyvault-vault.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "keyVault": { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "enabledForDeployment": "[parameters('enableVaultForDeployment')]", + "enabledForTemplateDeployment": "[parameters('enableVaultForTemplateDeployment')]", + "enabledForDiskEncryption": "[parameters('enableVaultForDiskEncryption')]", + "enableSoftDelete": "[parameters('enableSoftDelete')]", + "softDeleteRetentionInDays": "[parameters('softDeleteRetentionInDays')]", + "enableRbacAuthorization": "[parameters('enableRbacAuthorization')]", + "createMode": "[parameters('createMode')]", + "enablePurgeProtection": "[if(parameters('enablePurgeProtection'), parameters('enablePurgeProtection'), null())]", + "tenantId": "[subscription().tenantId]", + "accessPolicies": "[variables('formattedAccessPolicies')]", + "sku": { + "name": "[parameters('sku')]", + "family": "A" + }, + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(coalesce(parameters('privateEndpoints'), createArray()))), empty(coalesce(parameters('networkAcls'), createObject()))), 'Disabled', null()))]" + } + }, + "keyVault_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_diagnosticSettings": { + "copy": { + "name": "keyVault_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_roleAssignments": { + "copy": { + "name": "keyVault_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_accessPolicies": { + "condition": "[not(empty(parameters('accessPolicies')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-AccessPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('name')]" + }, + "accessPolicies": { + "value": "[parameters('accessPolicies')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "15662374115599475123" + }, + "name": "Key Vault Access Policies", + "description": "This module deploys a Key Vault Access Policy." + }, + "definitions": { + "accessPoliciesType": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + }, + "metadata": { + "description": "Required. Permissions the identity has for keys, secrets and certificates." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an access policy." + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "accessPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/accessPoliciesType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "policies": { + "type": "Microsoft.KeyVault/vaults/accessPolicies", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", + "properties": { + "copy": [ + { + "name": "accessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('accessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('accessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('accessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('accessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ] + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the access policies assignment was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the access policies assignment." + }, + "value": "add" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the access policies assignment." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', parameters('keyVaultName'), 'add')]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_secrets": { + "copy": { + "name": "keyVault_secrets", + "count": "[length(coalesce(parameters('secrets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-Secret-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].value]" + }, + "keyVaultName": { + "value": "[parameters('name')]" + }, + "attributesEnabled": { + "value": "[tryGet(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributes'), 'enabled')]" + }, + "attributesExp": { + "value": "[tryGet(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributes'), 'exp')]" + }, + "attributesNbf": { + "value": "[tryGet(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributes'), 'nbf')]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "7030946530357291103" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "contentType": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secret": { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "contentType": "[parameters('contentType')]", + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "value": "[parameters('value')]" + } + }, + "secret_roleAssignments": { + "copy": { + "name": "secret_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "secret" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the secret." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the secret." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The uri of the secret." + }, + "value": "[reference('secret').secretUri]" + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The uri with version of the secret." + }, + "value": "[reference('secret').secretUriWithVersion]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the secret was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_keys": { + "copy": { + "name": "keyVault_keys", + "count": "[length(coalesce(parameters('keys'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-Key-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('keys'), createArray())[copyIndex()].name]" + }, + "keyVaultName": { + "value": "[parameters('name')]" + }, + "attributesEnabled": { + "value": "[tryGet(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributes'), 'enabled')]" + }, + "attributesExp": { + "value": "[tryGet(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributes'), 'exp')]" + }, + "attributesNbf": { + "value": "[tryGet(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributes'), 'nbf')]" + }, + "curveName": "[if(and(not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA')), not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM'))), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'curveName'), 'P-256')), createObject('value', null()))]", + "keyOps": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keyOps')]" + }, + "keySize": "[if(or(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA'), equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM')), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keySize'), 4096)), createObject('value', null()))]", + "releasePolicy": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'releasePolicy'), createObject())]" + }, + "kty": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'EC')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "rotationPolicy": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'rotationPolicy')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "8627699258587559559" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "curveName": { + "type": "string", + "defaultValue": "P-256", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "metadata": { + "description": "Optional. The elliptic curve name." + } + }, + "keyOps": { + "type": "array", + "nullable": true, + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "metadata": { + "description": "Optional. Array of JsonWebKeyOperation." + } + }, + "keySize": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." + } + }, + "kty": { + "type": "string", + "defaultValue": "EC", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "metadata": { + "description": "Optional. The type of the key." + } + }, + "releasePolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "rotationPolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy properties object." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "key": { + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": "[shallowMerge(createArray(createObject('attributes', createObject('enabled', parameters('attributesEnabled'), 'exp', parameters('attributesExp'), 'nbf', parameters('attributesNbf')), 'curveName', parameters('curveName'), 'keyOps', parameters('keyOps'), 'keySize', parameters('keySize'), 'kty', parameters('kty'), 'release_policy', coalesce(parameters('releasePolicy'), createObject())), if(not(empty(parameters('rotationPolicy'))), createObject('rotationPolicy', parameters('rotationPolicy')), createObject())))]" + }, + "key_roleAssignments": { + "copy": { + "name": "key_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "key" + ] + } + }, + "outputs": { + "keyUri": { + "type": "string", + "metadata": { + "description": "The uri of the key." + }, + "value": "[reference('key').keyUri]" + }, + "keyUriWithVersion": { + "type": "string", + "metadata": { + "description": "The uri with version of the key." + }, + "value": "[reference('key').keyUriWithVersion]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the key." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the key was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_privateEndpoints": { + "copy": { + "name": "keyVault_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyVault-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "15954548978129725136" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.10.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "5440815542537978381" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key vault." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the key vault was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the key vault." + }, + "value": "[parameters('name')]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The URI of the key vault." + }, + "value": "[reference('keyVault').vaultUri]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('keyVault', '2022-07-01', 'full').location]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the key vault." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "secrets": { + "type": "array", + "items": { + "$ref": "#/definitions/credentialOutputType" + }, + "metadata": { + "description": "The properties of the created secrets." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secrets'), createArray()))))]", + "input": { + "resourceId": "[reference(format('keyVault_secrets[{0}]', range(0, length(coalesce(parameters('secrets'), createArray())))[copyIndex()])).outputs.resourceId.value]", + "uri": "[reference(format('keyVault_secrets[{0}]', range(0, length(coalesce(parameters('secrets'), createArray())))[copyIndex()])).outputs.secretUri.value]", + "uriWithVersion": "[reference(format('keyVault_secrets[{0}]', range(0, length(coalesce(parameters('secrets'), createArray())))[copyIndex()])).outputs.secretUriWithVersion.value]" + } + } + }, + "keys": { + "type": "array", + "items": { + "$ref": "#/definitions/credentialOutputType" + }, + "metadata": { + "description": "The properties of the created keys." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('keys'), createArray()))))]", + "input": { + "resourceId": "[reference(format('keyVault_keys[{0}]', range(0, length(coalesce(parameters('keys'), createArray())))[copyIndex()])).outputs.resourceId.value]", + "uri": "[reference(format('keyVault_keys[{0}]', range(0, length(coalesce(parameters('keys'), createArray())))[copyIndex()])).outputs.keyUri.value]", + "uriWithVersion": "[reference(format('keyVault_keys[{0}]', range(0, length(coalesce(parameters('keys'), createArray())))[copyIndex()])).outputs.keyUriWithVersion.value]" + } + } + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/key-vault/vault/secret/README.md b/avm/1.1.0/res/key-vault/vault/secret/README.md new file mode 100644 index 000000000..64d7b573b --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/secret/README.md @@ -0,0 +1,226 @@ +# Key Vault Secrets `[Microsoft.KeyVault/vaults/secrets]` + +This module deploys a Key Vault Secret. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.KeyVault/vaults/secrets` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/secrets) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the secret. | +| [`value`](#parameter-value) | securestring | The value of the secret. NOTE: "value" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVaultName`](#parameter-keyvaultname) | string | The name of the parent key vault. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`attributesEnabled`](#parameter-attributesenabled) | bool | Determines whether the object is enabled. | +| [`attributesExp`](#parameter-attributesexp) | int | Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible. | +| [`attributesNbf`](#parameter-attributesnbf) | int | Not before date in seconds since 1970-01-01T00:00:00Z. | +| [`contentType`](#parameter-contenttype) | securestring | The content type of the secret. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Resource tags. | + +### Parameter: `name` + +The name of the secret. + +- Required: Yes +- Type: string + +### Parameter: `value` + +The value of the secret. NOTE: "value" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets. + +- Required: Yes +- Type: securestring + +### Parameter: `keyVaultName` + +The name of the parent key vault. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `attributesEnabled` + +Determines whether the object is enabled. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `attributesExp` + +Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible. + +- Required: No +- Type: int + +### Parameter: `attributesNbf` + +Not before date in seconds since 1970-01-01T00:00:00Z. + +- Required: No +- Type: int + +### Parameter: `contentType` + +The content type of the secret. + +- Required: No +- Type: securestring + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Contributor'` + - `'Key Vault Reader'` + - `'Key Vault Secrets Officer'` + - `'Key Vault Secrets User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the secret. | +| `resourceGroupName` | string | The name of the resource group the secret was created in. | +| `resourceId` | string | The resource ID of the secret. | +| `secretUri` | string | The uri of the secret. | +| `secretUriWithVersion` | string | The uri with version of the secret. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | diff --git a/avm/1.1.0/res/key-vault/vault/secret/main.bicep b/avm/1.1.0/res/key-vault/vault/secret/main.bicep new file mode 100644 index 000000000..c7a08ee60 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/secret/main.bicep @@ -0,0 +1,127 @@ +metadata name = 'Key Vault Secrets' +metadata description = 'This module deploys a Key Vault Secret.' + +@description('Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment.') +param keyVaultName string + +@description('Required. The name of the secret.') +param name string + +@description('Optional. Resource tags.') +param tags object? + +@description('Optional. Determines whether the object is enabled.') +param attributesEnabled bool = true + +@description('Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible.') +param attributesExp int? + +@description('Optional. Not before date in seconds since 1970-01-01T00:00:00Z.') +param attributesNbf int? + +@description('Optional. The content type of the secret.') +@secure() +param contentType string? + +@description('Required. The value of the secret. NOTE: "value" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets.') +@secure() +param value string + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Key Vault Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '00482a5a-887f-4fb3-b363-3b7fe8e74483' + ) + 'Key Vault Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f25e0fa2-a7c8-4377-a976-54943a77a395' + ) + 'Key Vault Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '21090545-7ca7-4776-b22c-e363652d74d2' + ) + 'Key Vault Secrets Officer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7' + ) + 'Key Vault Secrets User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4633458b-17de-408a-b874-0445c86b69e6' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +resource secret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { + name: name + parent: keyVault + tags: tags + properties: { + contentType: contentType + attributes: { + enabled: attributesEnabled + exp: attributesExp + nbf: attributesNbf + } + value: value + } +} + +resource secret_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(secret.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: secret + } +] + +@description('The name of the secret.') +output name string = secret.name + +@description('The resource ID of the secret.') +output resourceId string = secret.id + +@description('The uri of the secret.') +output secretUri string = secret.properties.secretUri + +@description('The uri with version of the secret.') +output secretUriWithVersion string = secret.properties.secretUriWithVersion + +@description('The name of the resource group the secret was created in.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/key-vault/vault/secret/main.json b/avm/1.1.0/res/key-vault/vault/secret/main.json new file mode 100644 index 000000000..75557e043 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/secret/main.json @@ -0,0 +1,259 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "7030946530357291103" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "contentType": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secret": { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "contentType": "[parameters('contentType')]", + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "value": "[parameters('value')]" + } + }, + "secret_roleAssignments": { + "copy": { + "name": "secret_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "secret" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the secret." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the secret." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The uri of the secret." + }, + "value": "[reference('secret').secretUri]" + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The uri with version of the secret." + }, + "value": "[reference('secret').secretUriWithVersion]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the secret was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/key-vault/vault/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/key-vault/vault/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..89d9dfa44 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,49 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-keyvault.vaults-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'kvvmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + // Only for testing purposes + enablePurgeProtection: false + } + } +] diff --git a/avm/1.1.0/res/key-vault/vault/tests/e2e/eckey/main.test.bicep b/avm/1.1.0/res/key-vault/vault/tests/e2e/eckey/main.test.bicep new file mode 100644 index 000000000..88b1b187f --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/tests/e2e/eckey/main.test.bicep @@ -0,0 +1,83 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-keyvault.vaults-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'kvvec' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + // Only for testing purposes + enablePurgeProtection: false + enableRbacAuthorization: true + keys: [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + name: 'keyName' + kty: 'EC' + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + trigger: { + timeBeforeExpiry: 'P2M' + } + action: { + type: 'Rotate' + } + } + { + trigger: { + timeBeforeExpiry: 'P30D' + } + action: { + type: 'Notify' + } + } + ] + } + } + ] + } + } +] diff --git a/avm/1.1.0/res/key-vault/vault/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/key-vault/vault/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..6c3754d07 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/tests/e2e/max/dependencies.bicep @@ -0,0 +1,65 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + serviceEndpoints: [ + { + service: 'Microsoft.KeyVault' + } + ] + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.vaultcore.azure.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/1.1.0/res/key-vault/vault/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/key-vault/vault/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..896844e9d --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/tests/e2e/max/main.test.bicep @@ -0,0 +1,319 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-keyvault.vaults-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'kvvmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}03' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + location: resourceLocation + accessPolicies: [ + { + objectId: nestedDependencies.outputs.managedIdentityPrincipalId + permissions: { + keys: [ + 'get' + 'list' + 'update' + ] + secrets: [ + 'all' + ] + } + tenantId: tenant().tenantId + } + { + objectId: nestedDependencies.outputs.managedIdentityPrincipalId + permissions: { + certificates: [ + 'backup' + 'create' + 'delete' + ] + secrets: [ + 'all' + ] + } + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + logCategoriesAndGroups: [ + { + category: 'AzurePolicyEvaluationDetails' + } + { + category: 'AuditEvent' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + // Only for testing purposes + enablePurgeProtection: false + enableRbacAuthorization: false + keys: [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + name: 'keyName' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + trigger: { + timeBeforeExpiry: 'P2M' + } + action: { + type: 'Rotate' + } + } + { + trigger: { + timeBeforeExpiry: 'P30D' + } + action: { + type: 'Notify' + } + } + ] + } + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + ipRules: [ + { + value: '40.74.28.0/23' + } + ] + virtualNetworkRules: [ + { + id: nestedDependencies.outputs.subnetResourceId + ignoreMissingVnetServiceEndpoint: false + } + ] + } + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + subnetResourceId: nestedDependencies.outputs.subnetResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] + customDnsConfigs: [ + { + fqdn: 'abc.keyvault.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + resourceGroupResourceId: resourceGroup.id + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + roleAssignments: [ + { + name: 'b50cc72e-a2f2-4c4c-a3ad-86a43feb6ab8' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + secrets: [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + contentType: 'Something' + name: 'secretName' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + value: 'secretValue' + } + ] + softDeleteRetentionInDays: 7 + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] + +output resourceId string = testDeployment[0].outputs.resourceId diff --git a/avm/1.1.0/res/key-vault/vault/tests/e2e/max/tests/connectivity.tests.ps1 b/avm/1.1.0/res/key-vault/vault/tests/e2e/max/tests/connectivity.tests.ps1 new file mode 100644 index 000000000..6ed0e8c83 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/tests/e2e/max/tests/connectivity.tests.ps1 @@ -0,0 +1,39 @@ +###################################### +## Additional post-deployment tests ## +###################################### +## +## You can add any custom post-deployment validation tests you want here, or add them spread accross multiple test files in the test case folder. +## +########################### + +param ( + [Parameter(Mandatory = $false)] + [hashtable] $TestInputData = @{} +) + +Describe 'Validate private endpoint deployment' { + + Context 'Validate sucessful deployment' { + + It 'Private endpoints should be deployed in resource group' { + + $keyVaultResourceId = $TestInputData.DeploymentOutputs.resourceId.Value + $testResourceGroup = ($keyVaultResourceId -split '\/')[4] + $deployedPrivateEndpoints = Get-AzPrivateEndpoint -ResourceGroupName $testResourceGroup + $deployedPrivateEndpoints.Count | Should -BeGreaterThan 0 + } + + It 'Private endpoint should have role assignment' { + + $keyVaultResourceId = $TestInputData.DeploymentOutputs.resourceId.Value + $testResourceGroup = ($keyVaultResourceId -split '\/')[4] + $deployedPrivateEndpoints = Get-AzPrivateEndpoint -ResourceGroupName $testResourceGroup + + $firstPrivateEndpointResourceId = $deployedPrivateEndpoints[0].Id + $firstPrivateEndpointName = ($firstPrivateEndpointResourceId -split '\/')[-1] + + $roleAssignments = Get-AzRoleAssignment -ResourceName $firstPrivateEndpointName -ResourceType 'Microsoft.Network/privateEndpoints' -ResourceGroupName $testResourceGroup + $roleAssignments.Count | Should -BeGreaterThan 0 + } + } +} diff --git a/avm/1.1.0/res/key-vault/vault/tests/e2e/rsakey/main.test.bicep b/avm/1.1.0/res/key-vault/vault/tests/e2e/rsakey/main.test.bicep new file mode 100644 index 000000000..2879588b0 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/tests/e2e/rsakey/main.test.bicep @@ -0,0 +1,83 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-keyvault.vaults-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'kvvrsa' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + // Only for testing purposes + enablePurgeProtection: false + enableRbacAuthorization: true + keys: [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + name: 'keyName' + kty: 'RSA' + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + trigger: { + timeBeforeExpiry: 'P2M' + } + action: { + type: 'Rotate' + } + } + { + trigger: { + timeBeforeExpiry: 'P30D' + } + action: { + type: 'Notify' + } + } + ] + } + } + ] + } + } +] diff --git a/avm/1.1.0/res/key-vault/vault/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/key-vault/vault/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..6c3754d07 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,65 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + serviceEndpoints: [ + { + service: 'Microsoft.KeyVault' + } + ] + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.vaultcore.azure.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/1.1.0/res/key-vault/vault/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/key-vault/vault/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..31d0ef955 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,151 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-keyvault.vaults-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'kvvwaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}03' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + diagnosticSettings: [ + { + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + // Only for testing purposes + enablePurgeProtection: false + enableRbacAuthorization: true + keys: [ + { + attributes: { + enabled: true + exp: 1702648632 + nbf: 10000 + } + name: 'keyName' + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + trigger: { + timeBeforeExpiry: 'P2M' + } + action: { + type: 'Rotate' + } + } + { + trigger: { + timeBeforeExpiry: 'P30D' + } + action: { + type: 'Notify' + } + } + ] + } + keySize: 4096 + } + ] + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + } + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + service: 'vault' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + secrets: [ + { + attributes: { + enabled: true + exp: 1702648632 + nbf: 10000 + } + contentType: 'Something' + name: 'secretName' + value: 'secretValue' + } + ] + softDeleteRetentionInDays: 7 + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/key-vault/vault/tests/unit/custom.tests.ps1 b/avm/1.1.0/res/key-vault/vault/tests/unit/custom.tests.ps1 new file mode 100644 index 000000000..36b53af9c --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/tests/unit/custom.tests.ps1 @@ -0,0 +1,7 @@ +########################### +## Additional unit tests ## +########################### +## +## You can add any custom static validation tests you want here, or add them spread accross multiple test files in the unit folder. +## +########################### diff --git a/avm/1.1.0/res/key-vault/vault/version.json b/avm/1.1.0/res/key-vault/vault/version.json new file mode 100644 index 000000000..15548e8d1 --- /dev/null +++ b/avm/1.1.0/res/key-vault/vault/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.12", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/res/managed-identity/user-assigned-identity/README.md b/avm/1.1.0/res/managed-identity/user-assigned-identity/README.md new file mode 100644 index 000000000..c84308a3f --- /dev/null +++ b/avm/1.1.0/res/managed-identity/user-assigned-identity/README.md @@ -0,0 +1,706 @@ +# User Assigned Identities `[Microsoft.ManagedIdentity/userAssignedIdentities]` + +This module deploys a User Assigned Identity. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.ManagedIdentity/userAssignedIdentities` | [2023-01-31](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ManagedIdentity/2023-01-31/userAssignedIdentities) | +| `Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials` | [2023-01-31](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ManagedIdentity/2023-01-31/userAssignedIdentities/federatedIdentityCredentials) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/managed-identity/user-assigned-identity:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:' = { + name: 'userAssignedIdentityDeployment' + params: { + // Required parameters + name: 'miuaimin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "miuaimin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-identity/user-assigned-identity:' + +// Required parameters +param name = 'miuaimin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:' = { + name: 'userAssignedIdentityDeployment' + params: { + // Required parameters + name: 'miuaimax001' + // Non-required parameters + federatedIdentityCredentials: [ + { + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: '' + name: 'test-fed-cred-miuaimax-001' + subject: 'system:serviceaccount:default:workload-identity-sa' + } + { + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: '' + name: 'test-fed-cred-miuaimax-002' + subject: 'system:serviceaccount:default:workload-identity-sa' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'b1a2c427-c4b1-435a-9b82-40c1b59537ac' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "miuaimax001" + }, + // Non-required parameters + "federatedIdentityCredentials": { + "value": [ + { + "audiences": [ + "api://AzureADTokenExchange" + ], + "issuer": "", + "name": "test-fed-cred-miuaimax-001", + "subject": "system:serviceaccount:default:workload-identity-sa" + }, + { + "audiences": [ + "api://AzureADTokenExchange" + ], + "issuer": "", + "name": "test-fed-cred-miuaimax-002", + "subject": "system:serviceaccount:default:workload-identity-sa" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "b1a2c427-c4b1-435a-9b82-40c1b59537ac", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-identity/user-assigned-identity:' + +// Required parameters +param name = 'miuaimax001' +// Non-required parameters +param federatedIdentityCredentials = [ + { + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: '' + name: 'test-fed-cred-miuaimax-001' + subject: 'system:serviceaccount:default:workload-identity-sa' + } + { + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: '' + name: 'test-fed-cred-miuaimax-002' + subject: 'system:serviceaccount:default:workload-identity-sa' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'b1a2c427-c4b1-435a-9b82-40c1b59537ac' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:' = { + name: 'userAssignedIdentityDeployment' + params: { + // Required parameters + name: 'miuaiwaf001' + // Non-required parameters + federatedIdentityCredentials: [ + { + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: '' + name: 'test-fed-cred-miuaiwaf-001' + subject: 'system:serviceaccount:default:workload-identity-sa' + } + { + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: '' + name: 'test-fed-cred-miuaiwaf-002' + subject: 'system:serviceaccount:default:workload-identity-sa' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "miuaiwaf001" + }, + // Non-required parameters + "federatedIdentityCredentials": { + "value": [ + { + "audiences": [ + "api://AzureADTokenExchange" + ], + "issuer": "", + "name": "test-fed-cred-miuaiwaf-001", + "subject": "system:serviceaccount:default:workload-identity-sa" + }, + { + "audiences": [ + "api://AzureADTokenExchange" + ], + "issuer": "", + "name": "test-fed-cred-miuaiwaf-002", + "subject": "system:serviceaccount:default:workload-identity-sa" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-identity/user-assigned-identity:' + +// Required parameters +param name = 'miuaiwaf001' +// Non-required parameters +param federatedIdentityCredentials = [ + { + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: '' + name: 'test-fed-cred-miuaiwaf-001' + subject: 'system:serviceaccount:default:workload-identity-sa' + } + { + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: '' + name: 'test-fed-cred-miuaiwaf-002' + subject: 'system:serviceaccount:default:workload-identity-sa' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the User Assigned Identity. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`federatedIdentityCredentials`](#parameter-federatedidentitycredentials) | array | The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `name` + +Name of the User Assigned Identity. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `federatedIdentityCredentials` + +The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`audiences`](#parameter-federatedidentitycredentialsaudiences) | array | The list of audiences that can appear in the issued token. | +| [`issuer`](#parameter-federatedidentitycredentialsissuer) | string | The URL of the issuer to be trusted. | +| [`name`](#parameter-federatedidentitycredentialsname) | string | The name of the federated identity credential. | +| [`subject`](#parameter-federatedidentitycredentialssubject) | string | The identifier of the external identity. | + +### Parameter: `federatedIdentityCredentials.audiences` + +The list of audiences that can appear in the issued token. + +- Required: Yes +- Type: array + +### Parameter: `federatedIdentityCredentials.issuer` + +The URL of the issuer to be trusted. + +- Required: Yes +- Type: string + +### Parameter: `federatedIdentityCredentials.name` + +The name of the federated identity credential. + +- Required: Yes +- Type: string + +### Parameter: `federatedIdentityCredentials.subject` + +The identifier of the external identity. + +- Required: Yes +- Type: string + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Managed Identity Contributor'` + - `'Managed Identity Operator'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | 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. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/managed-identity/user-assigned-identity/federated-identity-credential/README.md b/avm/1.1.0/res/managed-identity/user-assigned-identity/federated-identity-credential/README.md new file mode 100644 index 000000000..6cd90eab2 --- /dev/null +++ b/avm/1.1.0/res/managed-identity/user-assigned-identity/federated-identity-credential/README.md @@ -0,0 +1,75 @@ +# User Assigned Identity Federated Identity Credential `[Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials]` + +This module deploys a User Assigned Identity Federated Identity Credential. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials` | [2023-01-31](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ManagedIdentity/2023-01-31/userAssignedIdentities/federatedIdentityCredentials) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`audiences`](#parameter-audiences) | array | The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token. | +| [`issuer`](#parameter-issuer) | string | The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged. | +| [`name`](#parameter-name) | string | The name of the secret. | +| [`subject`](#parameter-subject) | string | The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`userAssignedIdentityName`](#parameter-userassignedidentityname) | string | The name of the parent user assigned identity. Required if the template is used in a standalone deployment. | + +### Parameter: `audiences` + +The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token. + +- Required: Yes +- Type: array + +### Parameter: `issuer` + +The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the secret. + +- Required: Yes +- Type: string + +### Parameter: `subject` + +The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD. + +- Required: Yes +- Type: string + +### Parameter: `userAssignedIdentityName` + +The name of the parent user assigned identity. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the federated identity credential. | +| `resourceGroupName` | string | The name of the resource group the federated identity credential was created in. | +| `resourceId` | string | The resource ID of the federated identity credential. | diff --git a/avm/1.1.0/res/managed-identity/user-assigned-identity/federated-identity-credential/main.bicep b/avm/1.1.0/res/managed-identity/user-assigned-identity/federated-identity-credential/main.bicep new file mode 100644 index 000000000..a203c14db --- /dev/null +++ b/avm/1.1.0/res/managed-identity/user-assigned-identity/federated-identity-credential/main.bicep @@ -0,0 +1,40 @@ +metadata name = 'User Assigned Identity Federated Identity Credential' +metadata description = 'This module deploys a User Assigned Identity Federated Identity Credential.' + +@description('Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment.') +param userAssignedIdentityName string + +@description('Required. The name of the secret.') +param name string + +@description('Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token.') +param audiences array + +@description('Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged.') +param issuer string + +@description('Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD.') +param subject string + +resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = { + name: userAssignedIdentityName +} + +resource federatedIdentityCredential 'Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials@2023-01-31' = { + name: name + parent: userAssignedIdentity + properties: { + audiences: audiences + issuer: issuer + subject: subject + } +} + +@description('The name of the federated identity credential.') +output name string = federatedIdentityCredential.name + +@description('The resource ID of the federated identity credential.') +output resourceId string = federatedIdentityCredential.id + +@description('The name of the resource group the federated identity credential was created in.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/managed-identity/user-assigned-identity/federated-identity-credential/main.json b/avm/1.1.0/res/managed-identity/user-assigned-identity/federated-identity-credential/main.json new file mode 100644 index 000000000..65368695f --- /dev/null +++ b/avm/1.1.0/res/managed-identity/user-assigned-identity/federated-identity-credential/main.json @@ -0,0 +1,80 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "16526104427295478987" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." + }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "audiences": { + "type": "array", + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2023-01-31", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the federated identity credential." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/managed-identity/user-assigned-identity/main.bicep b/avm/1.1.0/res/managed-identity/user-assigned-identity/main.bicep new file mode 100644 index 000000000..592566fa8 --- /dev/null +++ b/avm/1.1.0/res/managed-identity/user-assigned-identity/main.bicep @@ -0,0 +1,196 @@ +metadata name = 'User Assigned Identities' +metadata description = 'This module deploys a User Assigned Identity.' + +@description('Required. Name of the User Assigned Identity.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object.') +param federatedIdentityCredentials federatedIdentityCredentialsType + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Managed Identity Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59' + ) + 'Managed Identity Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f1a07417-d97a-45cb-824c-7a7467783830' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.managedidentity-userassignedidentity.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: name + location: location + tags: tags +} + +resource userAssignedIdentity_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: userAssignedIdentity +} + +@batchSize(1) +module userAssignedIdentity_federatedIdentityCredentials 'federated-identity-credential/main.bicep' = [ + for (federatedIdentityCredential, index) in (federatedIdentityCredentials ?? []): { + name: '${uniqueString(deployment().name, location)}-UserMSI-FederatedIdentityCredential-${index}' + params: { + name: federatedIdentityCredential.name + userAssignedIdentityName: userAssignedIdentity.name + audiences: federatedIdentityCredential.audiences + issuer: federatedIdentityCredential.issuer + subject: federatedIdentityCredential.subject + } + } +] + +resource userAssignedIdentity_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + userAssignedIdentity.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: userAssignedIdentity + } +] + +@description('The name of the user assigned identity.') +output name string = userAssignedIdentity.name + +@description('The resource ID of the user assigned identity.') +output resourceId string = userAssignedIdentity.id + +@description('The principal ID (object ID) of the user assigned identity.') +output principalId string = userAssignedIdentity.properties.principalId + +@description('The client ID (application ID) of the user assigned identity.') +output clientId string = userAssignedIdentity.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 = userAssignedIdentity.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type federatedIdentityCredentialsType = { + @description('Required. The name of the federated identity credential.') + name: string + + @description('Required. The list of audiences that can appear in the issued token.') + audiences: string[] + + @description('Required. The URL of the issuer to be trusted.') + issuer: string + + @description('Required. The identifier of the external identity.') + subject: string +}[]? diff --git a/avm/1.1.0/res/managed-identity/user-assigned-identity/main.json b/avm/1.1.0/res/managed-identity/user-assigned-identity/main.json new file mode 100644 index 000000000..157f12734 --- /dev/null +++ b/avm/1.1.0/res/managed-identity/user-assigned-identity/main.json @@ -0,0 +1,441 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3367002951676335937" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "federatedIdentityCredentialsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the federated identity credential." + } + }, + "audiences": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "$ref": "#/definitions/federatedIdentityCredentialsType", + "metadata": { + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "userAssignedIdentity_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-UserMSI-FederatedIdentityCredential-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" + }, + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "16526104427295478987" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential." + }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "audiences": { + "type": "array", + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2023-01-31", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the federated identity credential." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2023-01-31', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..627b39486 --- /dev/null +++ b/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-managedidentity.userassignedidentities-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'miuaimin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..20a1079db --- /dev/null +++ b/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/max/main.test.bicep @@ -0,0 +1,110 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-managedidentity.userassignedidentities-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'miuaimax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// Set to fixed location as the RP function returns unsupported locations +// Right now (2024/03) the following locations are NOT supported: East Asia, Qatar Central, Malaysia South, Italy North, Israel Central +param enforcedLocation string = 'westeurope' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: enforcedLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + federatedIdentityCredentials: [ + { + name: 'test-fed-cred-${serviceShort}-001' + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: 'https://contoso.com/${subscription().tenantId}/${guid(deployment().name)}01/' + subject: 'system:serviceaccount:default:workload-identity-sa' + } + { + name: 'test-fed-cred-${serviceShort}-002' + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: 'https://contoso.com/${subscription().tenantId}/${guid(deployment().name)}02/' + subject: 'system:serviceaccount:default:workload-identity-sa' + } + ] + roleAssignments: [ + { + name: 'b1a2c427-c4b1-435a-9b82-40c1b59537ac' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..c0852d659 --- /dev/null +++ b/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,79 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-managedidentity.userassignedidentities-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'miuaiwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// Set to fixed location as the RP function returns unsupported locations +// Right now (2024/03) the following locations are NOT supported for federated identity credentials: East Asia, Qatar Central, Malaysia South, Italy North, Israel Central +param enforcedLocation string = 'westeurope' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + federatedIdentityCredentials: [ + { + name: 'test-fed-cred-${serviceShort}-001' + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: 'https://contoso.com/${subscription().tenantId}/${guid(deployment().name)}01/' + subject: 'system:serviceaccount:default:workload-identity-sa' + } + { + name: 'test-fed-cred-${serviceShort}-002' + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: 'https://contoso.com/${subscription().tenantId}/${guid(deployment().name)}02/' + subject: 'system:serviceaccount:default:workload-identity-sa' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/unit/custom.tests.ps1 b/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/unit/custom.tests.ps1 new file mode 100644 index 000000000..36b53af9c --- /dev/null +++ b/avm/1.1.0/res/managed-identity/user-assigned-identity/tests/unit/custom.tests.ps1 @@ -0,0 +1,7 @@ +########################### +## Additional unit tests ## +########################### +## +## You can add any custom static validation tests you want here, or add them spread accross multiple test files in the unit folder. +## +########################### diff --git a/avm/1.1.0/res/managed-identity/user-assigned-identity/version.json b/avm/1.1.0/res/managed-identity/user-assigned-identity/version.json new file mode 100644 index 000000000..3f863a2be --- /dev/null +++ b/avm/1.1.0/res/managed-identity/user-assigned-identity/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.4", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/net-app/net-app-account/README.md b/avm/1.1.0/res/net-app/net-app-account/README.md new file mode 100644 index 000000000..19f465524 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/README.md @@ -0,0 +1,2851 @@ +# Azure NetApp Files `[Microsoft.NetApp/netAppAccounts]` + +This module deploys an Azure NetApp File. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.NetApp/netAppAccounts` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts) | +| `Microsoft.NetApp/netAppAccounts/backupPolicies` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/backupPolicies) | +| `Microsoft.NetApp/netAppAccounts/backupVaults` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/backupVaults) | +| `Microsoft.NetApp/netAppAccounts/backupVaults/backups` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/backupVaults/backups) | +| `Microsoft.NetApp/netAppAccounts/capacityPools` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/capacityPools) | +| `Microsoft.NetApp/netAppAccounts/capacityPools/volumes` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/capacityPools/volumes) | +| `Microsoft.NetApp/netAppAccounts/snapshotPolicies` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/snapshotPolicies) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/net-app/net-app-account:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [Using nfs31 parameter set](#example-3-using-nfs31-parameter-set) +- [WAF-aligned](#example-4-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = { + name: 'netAppAccountDeployment' + params: { + // Required parameters + name: 'nanaamin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nanaamin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/net-app/net-app-account:' + +// Required parameters +param name = 'nanaamin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = { + name: 'netAppAccountDeployment' + params: { + // Required parameters + name: 'nanaamax001' + // Non-required parameters + backupPolicies: [ + { + name: 'myBackupPolicy' + } + ] + backupVault: { + backups: [ + { + capacityPoolName: 'cp-001' + label: 'myLabel' + name: 'myBackup01' + volumeName: 'vol-001' + } + ] + name: 'myVault' + } + capacityPools: [ + { + name: 'cp-001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [ + { + dataProtection: { + backup: { + backupPolicyName: 'myBackupPolicy' + backupVaultName: 'myVault' + policyEnforced: false + } + snapshot: { + snapshotPolicyName: 'mySnapshotPolicy' + } + } + encryptionKeySource: '' + exportPolicy: { + rules: [ + { + allowedClients: '0.0.0.0/0' + kerberos5iReadOnly: false + kerberos5iReadWrite: false + kerberos5pReadOnly: false + kerberos5pReadWrite: false + kerberos5ReadOnly: false + kerberos5ReadWrite: false + nfsv3: false + nfsv41: true + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: true + } + ] + } + name: 'vol-001' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv4.1' + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + 1 + ] + } + { + encryptionKeySource: '' + exportPolicy: { + rules: [ + { + allowedClients: '0.0.0.0/0' + kerberos5iReadOnly: false + kerberos5iReadWrite: false + kerberos5pReadOnly: false + kerberos5pReadWrite: false + kerberos5ReadOnly: false + kerberos5ReadWrite: false + nfsv3: false + nfsv41: true + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: false + } + ] + } + kerberosEnabled: false + name: 'vol-002' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv4.1' + ] + smbContinuouslyAvailable: false + smbEncryption: false + smbNonBrowsable: 'Disabled' + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + 1 + ] + } + ] + } + { + name: 'cp-002' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [] + } + ] + location: '' + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + roleAssignments: [ + { + name: '18051111-2a33-4f8e-8b24-441aac1e6562' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + snapshotPolicies: [ + { + dailySchedule: { + hour: 0 + minute: 0 + snapshotsToKeep: 1 + } + name: 'mySnapshotPolicy' + } + ] + tags: { + Contact: 'test.user@testcompany.com' + CostCenter: '7890' + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + PurchaseOrder: '1234' + Role: 'DeploymentValidation' + ServiceName: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nanaamax001" + }, + // Non-required parameters + "backupPolicies": { + "value": [ + { + "name": "myBackupPolicy" + } + ] + }, + "backupVault": { + "value": { + "backups": [ + { + "capacityPoolName": "cp-001", + "label": "myLabel", + "name": "myBackup01", + "volumeName": "vol-001" + } + ], + "name": "myVault" + } + }, + "capacityPools": { + "value": [ + { + "name": "cp-001", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "serviceLevel": "Premium", + "size": 4398046511104, + "volumes": [ + { + "dataProtection": { + "backup": { + "backupPolicyName": "myBackupPolicy", + "backupVaultName": "myVault", + "policyEnforced": false + }, + "snapshot": { + "snapshotPolicyName": "mySnapshotPolicy" + } + }, + "encryptionKeySource": "", + "exportPolicy": { + "rules": [ + { + "allowedClients": "0.0.0.0/0", + "kerberos5iReadOnly": false, + "kerberos5iReadWrite": false, + "kerberos5pReadOnly": false, + "kerberos5pReadWrite": false, + "kerberos5ReadOnly": false, + "kerberos5ReadWrite": false, + "nfsv3": false, + "nfsv41": true, + "ruleIndex": 1, + "unixReadOnly": false, + "unixReadWrite": true + } + ] + }, + "name": "vol-001", + "networkFeatures": "Standard", + "protocolTypes": [ + "NFSv4.1" + ], + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "subnetResourceId": "", + "usageThreshold": 107374182400, + "zones": [ + 1 + ] + }, + { + "encryptionKeySource": "", + "exportPolicy": { + "rules": [ + { + "allowedClients": "0.0.0.0/0", + "kerberos5iReadOnly": false, + "kerberos5iReadWrite": false, + "kerberos5pReadOnly": false, + "kerberos5pReadWrite": false, + "kerberos5ReadOnly": false, + "kerberos5ReadWrite": false, + "nfsv3": false, + "nfsv41": true, + "ruleIndex": 1, + "unixReadOnly": false, + "unixReadWrite": false + } + ] + }, + "kerberosEnabled": false, + "name": "vol-002", + "networkFeatures": "Standard", + "protocolTypes": [ + "NFSv4.1" + ], + "smbContinuouslyAvailable": false, + "smbEncryption": false, + "smbNonBrowsable": "Disabled", + "subnetResourceId": "", + "usageThreshold": 107374182400, + "zones": [ + 1 + ] + } + ] + }, + { + "name": "cp-002", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "serviceLevel": "Premium", + "size": 4398046511104, + "volumes": [] + } + ] + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "roleAssignments": { + "value": [ + { + "name": "18051111-2a33-4f8e-8b24-441aac1e6562", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "snapshotPolicies": { + "value": [ + { + "dailySchedule": { + "hour": 0, + "minute": 0, + "snapshotsToKeep": 1 + }, + "name": "mySnapshotPolicy" + } + ] + }, + "tags": { + "value": { + "Contact": "test.user@testcompany.com", + "CostCenter": "7890", + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "PurchaseOrder": "1234", + "Role": "DeploymentValidation", + "ServiceName": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/net-app/net-app-account:' + +// Required parameters +param name = 'nanaamax001' +// Non-required parameters +param backupPolicies = [ + { + name: 'myBackupPolicy' + } +] +param backupVault = { + backups: [ + { + capacityPoolName: 'cp-001' + label: 'myLabel' + name: 'myBackup01' + volumeName: 'vol-001' + } + ] + name: 'myVault' +} +param capacityPools = [ + { + name: 'cp-001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [ + { + dataProtection: { + backup: { + backupPolicyName: 'myBackupPolicy' + backupVaultName: 'myVault' + policyEnforced: false + } + snapshot: { + snapshotPolicyName: 'mySnapshotPolicy' + } + } + encryptionKeySource: '' + exportPolicy: { + rules: [ + { + allowedClients: '0.0.0.0/0' + kerberos5iReadOnly: false + kerberos5iReadWrite: false + kerberos5pReadOnly: false + kerberos5pReadWrite: false + kerberos5ReadOnly: false + kerberos5ReadWrite: false + nfsv3: false + nfsv41: true + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: true + } + ] + } + name: 'vol-001' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv4.1' + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + 1 + ] + } + { + encryptionKeySource: '' + exportPolicy: { + rules: [ + { + allowedClients: '0.0.0.0/0' + kerberos5iReadOnly: false + kerberos5iReadWrite: false + kerberos5pReadOnly: false + kerberos5pReadWrite: false + kerberos5ReadOnly: false + kerberos5ReadWrite: false + nfsv3: false + nfsv41: true + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: false + } + ] + } + kerberosEnabled: false + name: 'vol-002' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv4.1' + ] + smbContinuouslyAvailable: false + smbEncryption: false + smbNonBrowsable: 'Disabled' + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + 1 + ] + } + ] + } + { + name: 'cp-002' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [] + } +] +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: '18051111-2a33-4f8e-8b24-441aac1e6562' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param snapshotPolicies = [ + { + dailySchedule: { + hour: 0 + minute: 0 + snapshotsToKeep: 1 + } + name: 'mySnapshotPolicy' + } +] +param tags = { + Contact: 'test.user@testcompany.com' + CostCenter: '7890' + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + PurchaseOrder: '1234' + Role: 'DeploymentValidation' + ServiceName: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _Using nfs31 parameter set_ + +This instance deploys the module with nfs31. + + +

+ +via Bicep module + +```bicep +module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = { + name: 'netAppAccountDeployment' + params: { + // Required parameters + name: 'nanaanfs3001' + // Non-required parameters + capacityPools: [ + { + name: 'nanaanfs3-cp-001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [ + { + encryptionKeySource: '' + exportPolicy: { + rules: [ + { + allowedClients: '0.0.0.0/0' + kerberos5iReadOnly: false + kerberos5iReadWrite: false + kerberos5pReadOnly: false + kerberos5pReadWrite: false + kerberos5ReadOnly: false + kerberos5ReadWrite: false + nfsv3: true + nfsv41: false + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: true + } + ] + } + name: 'nanaanfs3-vol-001' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv3' + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + 1 + ] + } + { + encryptionKeySource: '' + name: 'nanaanfs3-vol-002' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv3' + ] + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + 1 + ] + } + ] + } + { + name: 'nanaanfs3-cp-002' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [] + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Contact: 'test.user@testcompany.com' + CostCenter: '7890' + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + PurchaseOrder: '1234' + Role: 'DeploymentValidation' + ServiceName: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nanaanfs3001" + }, + // Non-required parameters + "capacityPools": { + "value": [ + { + "name": "nanaanfs3-cp-001", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "serviceLevel": "Premium", + "size": 4398046511104, + "volumes": [ + { + "encryptionKeySource": "", + "exportPolicy": { + "rules": [ + { + "allowedClients": "0.0.0.0/0", + "kerberos5iReadOnly": false, + "kerberos5iReadWrite": false, + "kerberos5pReadOnly": false, + "kerberos5pReadWrite": false, + "kerberos5ReadOnly": false, + "kerberos5ReadWrite": false, + "nfsv3": true, + "nfsv41": false, + "ruleIndex": 1, + "unixReadOnly": false, + "unixReadWrite": true + } + ] + }, + "name": "nanaanfs3-vol-001", + "networkFeatures": "Standard", + "protocolTypes": [ + "NFSv3" + ], + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "subnetResourceId": "", + "usageThreshold": 107374182400, + "zones": [ + 1 + ] + }, + { + "encryptionKeySource": "", + "name": "nanaanfs3-vol-002", + "networkFeatures": "Standard", + "protocolTypes": [ + "NFSv3" + ], + "subnetResourceId": "", + "usageThreshold": 107374182400, + "zones": [ + 1 + ] + } + ] + }, + { + "name": "nanaanfs3-cp-002", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "serviceLevel": "Premium", + "size": 4398046511104, + "volumes": [] + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Contact": "test.user@testcompany.com", + "CostCenter": "7890", + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "PurchaseOrder": "1234", + "Role": "DeploymentValidation", + "ServiceName": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/net-app/net-app-account:' + +// Required parameters +param name = 'nanaanfs3001' +// Non-required parameters +param capacityPools = [ + { + name: 'nanaanfs3-cp-001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [ + { + encryptionKeySource: '' + exportPolicy: { + rules: [ + { + allowedClients: '0.0.0.0/0' + kerberos5iReadOnly: false + kerberos5iReadWrite: false + kerberos5pReadOnly: false + kerberos5pReadWrite: false + kerberos5ReadOnly: false + kerberos5ReadWrite: false + nfsv3: true + nfsv41: false + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: true + } + ] + } + name: 'nanaanfs3-vol-001' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv3' + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + 1 + ] + } + { + encryptionKeySource: '' + name: 'nanaanfs3-vol-002' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv3' + ] + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + 1 + ] + } + ] + } + { + name: 'nanaanfs3-cp-002' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [] + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Contact: 'test.user@testcompany.com' + CostCenter: '7890' + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + PurchaseOrder: '1234' + Role: 'DeploymentValidation' + ServiceName: 'DeploymentValidation' +} +``` + +
+

+ +### Example 4: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = { + name: 'netAppAccountDeployment' + params: { + // Required parameters + name: 'nanaawaf001' + // Non-required parameters + location: '' + tags: { + service: 'netapp' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nanaawaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "tags": { + "value": { + "service": "netapp" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/net-app/net-app-account:' + +// Required parameters +param name = 'nanaawaf001' +// Non-required parameters +param location = '' +param tags = { + service: 'netapp' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the NetApp account. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`adName`](#parameter-adname) | string | Name of the active directory host as part of Kerberos Realm used for Kerberos authentication. | +| [`aesEncryption`](#parameter-aesencryption) | bool | Enable AES encryption on the SMB Server. | +| [`backupPolicies`](#parameter-backuppolicies) | array | The backup policies to create. | +| [`backupVault`](#parameter-backupvault) | object | The netapp backup vault to create & configure. | +| [`capacityPools`](#parameter-capacitypools) | array | Capacity pools to create. | +| [`customerManagedKey`](#parameter-customermanagedkey) | object | The customer managed key definition. | +| [`dnsServers`](#parameter-dnsservers) | string | Required if domainName is specified. Comma separated list of DNS server IP addresses (IPv4 only) required for the Active Directory (AD) domain join and SMB authentication operations to succeed. | +| [`domainJoinOU`](#parameter-domainjoinou) | string | Used only if domainName is specified. LDAP Path for the Organization Unit (OU) where SMB Server machine accounts will be created (i.e. 'OU=SecondLevel,OU=FirstLevel'). | +| [`domainJoinPassword`](#parameter-domainjoinpassword) | securestring | Required if domainName is specified. Password of the user specified in domainJoinUser parameter. | +| [`domainJoinUser`](#parameter-domainjoinuser) | string | Required if domainName is specified. Username of Active Directory domain administrator, with permissions to create SMB server machine account in the AD domain. | +| [`domainName`](#parameter-domainname) | string | Fully Qualified Active Directory DNS Domain Name (e.g. 'contoso.com'). | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`encryptDCConnections`](#parameter-encryptdcconnections) | bool | Specifies whether encryption should be used for communication between SMB server and domain controller (DC). SMB3 only. | +| [`kdcIP`](#parameter-kdcip) | string | Kerberos Key Distribution Center (KDC) as part of Kerberos Realm used for Kerberos authentication. | +| [`ldapOverTLS`](#parameter-ldapovertls) | bool | Specifies whether to use TLS when NFS (with/without Kerberos) and SMB volumes communicate with an LDAP server. A server root CA certificate must be uploaded if enabled (serverRootCACertificate). | +| [`ldapSigning`](#parameter-ldapsigning) | bool | Specifies whether or not the LDAP traffic needs to be signed. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`serverRootCACertificate`](#parameter-serverrootcacertificate) | string | A server Root certificate is required of ldapOverTLS is enabled. | +| [`smbServerNamePrefix`](#parameter-smbservernameprefix) | string | Required if domainName is specified. NetBIOS name of the SMB server. A computer account with this prefix will be registered in the AD and used to mount volumes. | +| [`snapshotPolicies`](#parameter-snapshotpolicies) | array | The snapshot policies to create. | +| [`tags`](#parameter-tags) | object | Tags for all resources. | + +### Parameter: `name` + +The name of the NetApp account. + +- Required: Yes +- Type: string + +### Parameter: `adName` + +Name of the active directory host as part of Kerberos Realm used for Kerberos authentication. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `aesEncryption` + +Enable AES encryption on the SMB Server. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `backupPolicies` + +The backup policies to create. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dailyBackupsToKeep`](#parameter-backuppoliciesdailybackupstokeep) | int | The daily backups to keep. | +| [`enabled`](#parameter-backuppoliciesenabled) | bool | Indicates whether the backup policy is enabled. | +| [`location`](#parameter-backuppolicieslocation) | string | The location of the backup policy. | +| [`monthlyBackupsToKeep`](#parameter-backuppoliciesmonthlybackupstokeep) | int | The monthly backups to keep. | +| [`name`](#parameter-backuppoliciesname) | string | The name of the backup policy. | +| [`weeklyBackupsToKeep`](#parameter-backuppoliciesweeklybackupstokeep) | int | The weekly backups to keep. | + +### Parameter: `backupPolicies.dailyBackupsToKeep` + +The daily backups to keep. + +- Required: No +- Type: int +- MinValue: 2 +- MaxValue: 1019 + +### Parameter: `backupPolicies.enabled` + +Indicates whether the backup policy is enabled. + +- Required: No +- Type: bool +- MinValue: 2 +- MaxValue: 1019 + +### Parameter: `backupPolicies.location` + +The location of the backup policy. + +- Required: No +- Type: string +- MinValue: 2 +- MaxValue: 1019 + +### Parameter: `backupPolicies.monthlyBackupsToKeep` + +The monthly backups to keep. + +- Required: No +- Type: int +- MinValue: 2 +- MaxValue: 1019 + +### Parameter: `backupPolicies.name` + +The name of the backup policy. + +- Required: No +- Type: string +- MinValue: 2 +- MaxValue: 1019 + +### Parameter: `backupPolicies.weeklyBackupsToKeep` + +The weekly backups to keep. + +- Required: No +- Type: int +- MinValue: 2 +- MaxValue: 1019 + +### Parameter: `backupVault` + +The netapp backup vault to create & configure. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backups`](#parameter-backupvaultbackups) | array | The list of backups to create. | +| [`location`](#parameter-backupvaultlocation) | string | Location of the backup vault. | +| [`name`](#parameter-backupvaultname) | string | The name of the backup vault. | + +### Parameter: `backupVault.backups` + +The list of backups to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`capacityPoolName`](#parameter-backupvaultbackupscapacitypoolname) | string | The name of the capacity pool containing the volume. | +| [`volumeName`](#parameter-backupvaultbackupsvolumename) | string | The name of the volume to backup. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`label`](#parameter-backupvaultbackupslabel) | string | Label for backup. | +| [`name`](#parameter-backupvaultbackupsname) | string | The name of the backup. | +| [`snapshotName`](#parameter-backupvaultbackupssnapshotname) | string | The name of the snapshot. | + +### Parameter: `backupVault.backups.capacityPoolName` + +The name of the capacity pool containing the volume. + +- Required: Yes +- Type: string + +### Parameter: `backupVault.backups.volumeName` + +The name of the volume to backup. + +- Required: Yes +- Type: string + +### Parameter: `backupVault.backups.label` + +Label for backup. + +- Required: No +- Type: string + +### Parameter: `backupVault.backups.name` + +The name of the backup. + +- Required: No +- Type: string + +### Parameter: `backupVault.backups.snapshotName` + +The name of the snapshot. + +- Required: No +- Type: string + +### Parameter: `backupVault.location` + +Location of the backup vault. + +- Required: No +- Type: string + +### Parameter: `backupVault.name` + +The name of the backup vault. + +- Required: No +- Type: string + +### Parameter: `capacityPools` + +Capacity pools to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-capacitypoolsname) | string | The name of the capacity pool. | +| [`size`](#parameter-capacitypoolssize) | int | Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104). | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`coolAccess`](#parameter-capacitypoolscoolaccess) | bool | If enabled (true) the pool can contain cool Access enabled volumes. | +| [`encryptionType`](#parameter-capacitypoolsencryptiontype) | string | Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool. | +| [`location`](#parameter-capacitypoolslocation) | string | Location of the pool volume. | +| [`qosType`](#parameter-capacitypoolsqostype) | string | The qos type of the pool. | +| [`roleAssignments`](#parameter-capacitypoolsroleassignments) | array | Array of role assignments to create. | +| [`serviceLevel`](#parameter-capacitypoolsservicelevel) | string | The pool service level. | +| [`tags`](#parameter-capacitypoolstags) | object | Tags for the capcity pool. | +| [`volumes`](#parameter-capacitypoolsvolumes) | array | List of volumes to create in the capacity pool. | + +### Parameter: `capacityPools.name` + +The name of the capacity pool. + +- Required: Yes +- Type: string + +### Parameter: `capacityPools.size` + +Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104). + +- Required: Yes +- Type: int + +### Parameter: `capacityPools.coolAccess` + +If enabled (true) the pool can contain cool Access enabled volumes. + +- Required: No +- Type: bool + +### Parameter: `capacityPools.encryptionType` + +Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Double' + 'Single' + ] + ``` + +### Parameter: `capacityPools.location` + +Location of the pool volume. + +- Required: No +- Type: string + +### Parameter: `capacityPools.qosType` + +The qos type of the pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Auto' + 'Manual' + ] + ``` + +### Parameter: `capacityPools.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-capacitypoolsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-capacitypoolsroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-capacitypoolsroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-capacitypoolsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-capacitypoolsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-capacitypoolsroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-capacitypoolsroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-capacitypoolsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `capacityPools.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `capacityPools.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `capacityPools.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `capacityPools.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `capacityPools.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `capacityPools.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `capacityPools.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `capacityPools.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `capacityPools.serviceLevel` + +The pool service level. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Premium' + 'Standard' + 'StandardZRS' + 'Ultra' + ] + ``` + +### Parameter: `capacityPools.tags` + +Tags for the capcity pool. + +- Required: No +- Type: object + +### Parameter: `capacityPools.volumes` + +List of volumes to create in the capacity pool. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-capacitypoolsvolumesname) | string | The name of the pool volume. | +| [`subnetResourceId`](#parameter-capacitypoolsvolumessubnetresourceid) | string | The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes. | +| [`usageThreshold`](#parameter-capacitypoolsvolumesusagethreshold) | int | Maximum storage quota allowed for a file system in bytes. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`coolAccess`](#parameter-capacitypoolsvolumescoolaccess) | bool | If enabled (true) the pool can contain cool Access enabled volumes. | +| [`coolAccessRetrievalPolicy`](#parameter-capacitypoolsvolumescoolaccessretrievalpolicy) | string | Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read). | +| [`coolnessPeriod`](#parameter-capacitypoolsvolumescoolnessperiod) | int | Specifies the number of days after which data that is not accessed by clients will be tiered. | +| [`creationToken`](#parameter-capacitypoolsvolumescreationtoken) | string | A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription. | +| [`dataProtection`](#parameter-capacitypoolsvolumesdataprotection) | object | DataProtection type volumes include an object containing details of the replication. | +| [`encryptionKeySource`](#parameter-capacitypoolsvolumesencryptionkeysource) | string | The source of the encryption key. | +| [`exportPolicy`](#parameter-capacitypoolsvolumesexportpolicy) | object | Export policy rules. | +| [`kerberosEnabled`](#parameter-capacitypoolsvolumeskerberosenabled) | bool | Define if a volume is KerberosEnabled. | +| [`keyVaultPrivateEndpointResourceId`](#parameter-capacitypoolsvolumeskeyvaultprivateendpointresourceid) | string | The resource ID of the key vault private endpoint. | +| [`location`](#parameter-capacitypoolsvolumeslocation) | string | Location of the pool volume. | +| [`networkFeatures`](#parameter-capacitypoolsvolumesnetworkfeatures) | string | Network feature for the volume. | +| [`protocolTypes`](#parameter-capacitypoolsvolumesprotocoltypes) | array | Set of protocol types. | +| [`roleAssignments`](#parameter-capacitypoolsvolumesroleassignments) | array | Array of role assignments to create. | +| [`serviceLevel`](#parameter-capacitypoolsvolumesservicelevel) | string | The pool service level. Must match the one of the parent capacity pool. | +| [`smbContinuouslyAvailable`](#parameter-capacitypoolsvolumessmbcontinuouslyavailable) | bool | Enables continuously available share property for SMB volume. Only applicable for SMB volume. | +| [`smbEncryption`](#parameter-capacitypoolsvolumessmbencryption) | bool | Enables SMB encryption. Only applicable for SMB/DualProtocol volume. | +| [`smbNonBrowsable`](#parameter-capacitypoolsvolumessmbnonbrowsable) | string | Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume. | +| [`volumeType`](#parameter-capacitypoolsvolumesvolumetype) | string | The type of the volume. DataProtection volumes are used for replication. | +| [`zones`](#parameter-capacitypoolsvolumeszones) | array | Zone where the volume will be placed. | + +### Parameter: `capacityPools.volumes.name` + +The name of the pool volume. + +- Required: Yes +- Type: string + +### Parameter: `capacityPools.volumes.subnetResourceId` + +The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes. + +- Required: Yes +- Type: string + +### Parameter: `capacityPools.volumes.usageThreshold` + +Maximum storage quota allowed for a file system in bytes. + +- Required: Yes +- Type: int + +### Parameter: `capacityPools.volumes.coolAccess` + +If enabled (true) the pool can contain cool Access enabled volumes. + +- Required: No +- Type: bool + +### Parameter: `capacityPools.volumes.coolAccessRetrievalPolicy` + +Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read). + +- Required: No +- Type: string + +### Parameter: `capacityPools.volumes.coolnessPeriod` + +Specifies the number of days after which data that is not accessed by clients will be tiered. + +- Required: No +- Type: int + +### Parameter: `capacityPools.volumes.creationToken` + +A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription. + +- Required: No +- Type: string + +### Parameter: `capacityPools.volumes.dataProtection` + +DataProtection type volumes include an object containing details of the replication. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backup`](#parameter-capacitypoolsvolumesdataprotectionbackup) | object | Backup properties. | +| [`replication`](#parameter-capacitypoolsvolumesdataprotectionreplication) | object | Replication properties. | +| [`snapshot`](#parameter-capacitypoolsvolumesdataprotectionsnapshot) | object | Snapshot properties. | + +### Parameter: `capacityPools.volumes.dataProtection.backup` + +Backup properties. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backupPolicyName`](#parameter-capacitypoolsvolumesdataprotectionbackupbackuppolicyname) | string | The name of the backup policy to link. | +| [`backupVaultName`](#parameter-capacitypoolsvolumesdataprotectionbackupbackupvaultname) | string | The name of the Backup Vault. | +| [`policyEnforced`](#parameter-capacitypoolsvolumesdataprotectionbackuppolicyenforced) | bool | Enable to enforce the policy. | + +### Parameter: `capacityPools.volumes.dataProtection.backup.backupPolicyName` + +The name of the backup policy to link. + +- Required: Yes +- Type: string + +### Parameter: `capacityPools.volumes.dataProtection.backup.backupVaultName` + +The name of the Backup Vault. + +- Required: Yes +- Type: string + +### Parameter: `capacityPools.volumes.dataProtection.backup.policyEnforced` + +Enable to enforce the policy. + +- Required: Yes +- Type: bool + +### Parameter: `capacityPools.volumes.dataProtection.replication` + +Replication properties. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`endpointType`](#parameter-capacitypoolsvolumesdataprotectionreplicationendpointtype) | string | Indicates whether the local volume is the source or destination for the Volume Replication. | +| [`replicationSchedule`](#parameter-capacitypoolsvolumesdataprotectionreplicationreplicationschedule) | string | The replication schedule for the volume. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`remotePath`](#parameter-capacitypoolsvolumesdataprotectionreplicationremotepath) | object | The full path to a volume that is to be migrated into ANF. Required for Migration volumes. | +| [`remoteVolumeRegion`](#parameter-capacitypoolsvolumesdataprotectionreplicationremotevolumeregion) | string | The remote region for the other end of the Volume Replication.Required for Data Protection volumes. | +| [`remoteVolumeResourceId`](#parameter-capacitypoolsvolumesdataprotectionreplicationremotevolumeresourceid) | string | The resource ID of the remote volume. Required for Data Protection volumes. | + +### Parameter: `capacityPools.volumes.dataProtection.replication.endpointType` + +Indicates whether the local volume is the source or destination for the Volume Replication. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'dst' + 'src' + ] + ``` + +### Parameter: `capacityPools.volumes.dataProtection.replication.replicationSchedule` + +The replication schedule for the volume. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + '_10minutely' + 'daily' + 'hourly' + ] + ``` + +### Parameter: `capacityPools.volumes.dataProtection.replication.remotePath` + +The full path to a volume that is to be migrated into ANF. Required for Migration volumes. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`externalHostName`](#parameter-capacitypoolsvolumesdataprotectionreplicationremotepathexternalhostname) | string | The Path to a ONTAP Host. | +| [`serverName`](#parameter-capacitypoolsvolumesdataprotectionreplicationremotepathservername) | string | The name of a server on the ONTAP Host. | +| [`volumeName`](#parameter-capacitypoolsvolumesdataprotectionreplicationremotepathvolumename) | string | The name of a volume on the server. | + +### Parameter: `capacityPools.volumes.dataProtection.replication.remotePath.externalHostName` + +The Path to a ONTAP Host. + +- Required: Yes +- Type: string + +### Parameter: `capacityPools.volumes.dataProtection.replication.remotePath.serverName` + +The name of a server on the ONTAP Host. + +- Required: Yes +- Type: string + +### Parameter: `capacityPools.volumes.dataProtection.replication.remotePath.volumeName` + +The name of a volume on the server. + +- Required: Yes +- Type: string + +### Parameter: `capacityPools.volumes.dataProtection.replication.remoteVolumeRegion` + +The remote region for the other end of the Volume Replication.Required for Data Protection volumes. + +- Required: No +- Type: string + +### Parameter: `capacityPools.volumes.dataProtection.replication.remoteVolumeResourceId` + +The resource ID of the remote volume. Required for Data Protection volumes. + +- Required: No +- Type: string + +### Parameter: `capacityPools.volumes.dataProtection.snapshot` + +Snapshot properties. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`snapshotPolicyName`](#parameter-capacitypoolsvolumesdataprotectionsnapshotsnapshotpolicyname) | string | The name of the snapshot policy to link. | + +### Parameter: `capacityPools.volumes.dataProtection.snapshot.snapshotPolicyName` + +The name of the snapshot policy to link. + +- Required: Yes +- Type: string + +### Parameter: `capacityPools.volumes.encryptionKeySource` + +The source of the encryption key. + +- Required: No +- Type: string + +### Parameter: `capacityPools.volumes.exportPolicy` + +Export policy rules. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`rules`](#parameter-capacitypoolsvolumesexportpolicyrules) | array | The Export policy rules. | + +### Parameter: `capacityPools.volumes.exportPolicy.rules` + +The Export policy rules. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kerberos5iReadOnly`](#parameter-capacitypoolsvolumesexportpolicyruleskerberos5ireadonly) | bool | Kerberos5i Read only access. | +| [`kerberos5iReadWrite`](#parameter-capacitypoolsvolumesexportpolicyruleskerberos5ireadwrite) | bool | Kerberos5i Read and write access. | +| [`kerberos5pReadOnly`](#parameter-capacitypoolsvolumesexportpolicyruleskerberos5preadonly) | bool | Kerberos5p Read only access. | +| [`kerberos5pReadWrite`](#parameter-capacitypoolsvolumesexportpolicyruleskerberos5preadwrite) | bool | Kerberos5p Read and write access. | +| [`kerberos5ReadOnly`](#parameter-capacitypoolsvolumesexportpolicyruleskerberos5readonly) | bool | Kerberos5 Read only access. | +| [`kerberos5ReadWrite`](#parameter-capacitypoolsvolumesexportpolicyruleskerberos5readwrite) | bool | Kerberos5 Read and write access. | +| [`nfsv3`](#parameter-capacitypoolsvolumesexportpolicyrulesnfsv3) | bool | Allows NFSv3 protocol. Enable only for NFSv3 type volumes. | +| [`nfsv41`](#parameter-capacitypoolsvolumesexportpolicyrulesnfsv41) | bool | Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes. | +| [`ruleIndex`](#parameter-capacitypoolsvolumesexportpolicyrulesruleindex) | int | Order index. | +| [`unixReadOnly`](#parameter-capacitypoolsvolumesexportpolicyrulesunixreadonly) | bool | Read only access. | +| [`unixReadWrite`](#parameter-capacitypoolsvolumesexportpolicyrulesunixreadwrite) | bool | Read and write access. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowedClients`](#parameter-capacitypoolsvolumesexportpolicyrulesallowedclients) | string | Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names. | +| [`chownMode`](#parameter-capacitypoolsvolumesexportpolicyruleschownmode) | string | This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own. | +| [`cifs`](#parameter-capacitypoolsvolumesexportpolicyrulescifs) | bool | Allows CIFS protocol. | +| [`hasRootAccess`](#parameter-capacitypoolsvolumesexportpolicyruleshasrootaccess) | bool | Has root access to volume. | + +### Parameter: `capacityPools.volumes.exportPolicy.rules.kerberos5iReadOnly` + +Kerberos5i Read only access. + +- Required: Yes +- Type: bool + +### Parameter: `capacityPools.volumes.exportPolicy.rules.kerberos5iReadWrite` + +Kerberos5i Read and write access. + +- Required: Yes +- Type: bool + +### Parameter: `capacityPools.volumes.exportPolicy.rules.kerberos5pReadOnly` + +Kerberos5p Read only access. + +- Required: Yes +- Type: bool + +### Parameter: `capacityPools.volumes.exportPolicy.rules.kerberos5pReadWrite` + +Kerberos5p Read and write access. + +- Required: Yes +- Type: bool + +### Parameter: `capacityPools.volumes.exportPolicy.rules.kerberos5ReadOnly` + +Kerberos5 Read only access. + +- Required: Yes +- Type: bool + +### Parameter: `capacityPools.volumes.exportPolicy.rules.kerberos5ReadWrite` + +Kerberos5 Read and write access. + +- Required: Yes +- Type: bool + +### Parameter: `capacityPools.volumes.exportPolicy.rules.nfsv3` + +Allows NFSv3 protocol. Enable only for NFSv3 type volumes. + +- Required: Yes +- Type: bool + +### Parameter: `capacityPools.volumes.exportPolicy.rules.nfsv41` + +Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes. + +- Required: Yes +- Type: bool + +### Parameter: `capacityPools.volumes.exportPolicy.rules.ruleIndex` + +Order index. + +- Required: Yes +- Type: int + +### Parameter: `capacityPools.volumes.exportPolicy.rules.unixReadOnly` + +Read only access. + +- Required: Yes +- Type: bool + +### Parameter: `capacityPools.volumes.exportPolicy.rules.unixReadWrite` + +Read and write access. + +- Required: Yes +- Type: bool + +### Parameter: `capacityPools.volumes.exportPolicy.rules.allowedClients` + +Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names. + +- Required: No +- Type: string + +### Parameter: `capacityPools.volumes.exportPolicy.rules.chownMode` + +This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Restricted' + 'Unrestricted' + ] + ``` + +### Parameter: `capacityPools.volumes.exportPolicy.rules.cifs` + +Allows CIFS protocol. + +- Required: No +- Type: bool + +### Parameter: `capacityPools.volumes.exportPolicy.rules.hasRootAccess` + +Has root access to volume. + +- Required: No +- Type: bool + +### Parameter: `capacityPools.volumes.kerberosEnabled` + +Define if a volume is KerberosEnabled. + +- Required: No +- Type: bool + +### Parameter: `capacityPools.volumes.keyVaultPrivateEndpointResourceId` + +The resource ID of the key vault private endpoint. + +- Required: No +- Type: string + +### Parameter: `capacityPools.volumes.location` + +Location of the pool volume. + +- Required: No +- Type: string + +### Parameter: `capacityPools.volumes.networkFeatures` + +Network feature for the volume. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Basic' + 'Basic_Standard' + 'Standard' + 'Standard_Basic' + ] + ``` + +### Parameter: `capacityPools.volumes.protocolTypes` + +Set of protocol types. + +- Required: No +- Type: array + +### Parameter: `capacityPools.volumes.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-capacitypoolsvolumesroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-capacitypoolsvolumesroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-capacitypoolsvolumesroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-capacitypoolsvolumesroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-capacitypoolsvolumesroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-capacitypoolsvolumesroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-capacitypoolsvolumesroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-capacitypoolsvolumesroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `capacityPools.volumes.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `capacityPools.volumes.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `capacityPools.volumes.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `capacityPools.volumes.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `capacityPools.volumes.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `capacityPools.volumes.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `capacityPools.volumes.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `capacityPools.volumes.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `capacityPools.volumes.serviceLevel` + +The pool service level. Must match the one of the parent capacity pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Premium' + 'Standard' + 'StandardZRS' + 'Ultra' + ] + ``` + +### Parameter: `capacityPools.volumes.smbContinuouslyAvailable` + +Enables continuously available share property for SMB volume. Only applicable for SMB volume. + +- Required: No +- Type: bool + +### Parameter: `capacityPools.volumes.smbEncryption` + +Enables SMB encryption. Only applicable for SMB/DualProtocol volume. + +- Required: No +- Type: bool + +### Parameter: `capacityPools.volumes.smbNonBrowsable` + +Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `capacityPools.volumes.volumeType` + +The type of the volume. DataProtection volumes are used for replication. + +- Required: No +- Type: string + +### Parameter: `capacityPools.volumes.zones` + +Zone where the volume will be placed. + +- Required: No +- Type: array + +### Parameter: `customerManagedKey` + +The customer managed key definition. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyName`](#parameter-customermanagedkeykeyname) | string | The name of the customer managed key to use for encryption. | +| [`keyVaultResourceId`](#parameter-customermanagedkeykeyvaultresourceid) | string | The resource ID of a key vault to reference a customer managed key for encryption from. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVersion`](#parameter-customermanagedkeykeyversion) | string | The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time. | +| [`userAssignedIdentityResourceId`](#parameter-customermanagedkeyuserassignedidentityresourceid) | string | User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use. | + +### Parameter: `customerManagedKey.keyName` + +The name of the customer managed key to use for encryption. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKey.keyVaultResourceId` + +The resource ID of a key vault to reference a customer managed key for encryption from. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKey.keyVersion` + +The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time. + +- Required: No +- Type: string + +### Parameter: `customerManagedKey.userAssignedIdentityResourceId` + +User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use. + +- Required: No +- Type: string + +### Parameter: `dnsServers` + +Required if domainName is specified. Comma separated list of DNS server IP addresses (IPv4 only) required for the Active Directory (AD) domain join and SMB authentication operations to succeed. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `domainJoinOU` + +Used only if domainName is specified. LDAP Path for the Organization Unit (OU) where SMB Server machine accounts will be created (i.e. 'OU=SecondLevel,OU=FirstLevel'). + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `domainJoinPassword` + +Required if domainName is specified. Password of the user specified in domainJoinUser parameter. + +- Required: No +- Type: securestring +- Default: `''` + +### Parameter: `domainJoinUser` + +Required if domainName is specified. Username of Active Directory domain administrator, with permissions to create SMB server machine account in the AD domain. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `domainName` + +Fully Qualified Active Directory DNS Domain Name (e.g. 'contoso.com'). + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `encryptDCConnections` + +Specifies whether encryption should be used for communication between SMB server and domain controller (DC). SMB3 only. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `kdcIP` + +Kerberos Key Distribution Center (KDC) as part of Kerberos Realm used for Kerberos authentication. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `ldapOverTLS` + +Specifies whether to use TLS when NFS (with/without Kerberos) and SMB volumes communicate with an LDAP server. A server root CA certificate must be uploaded if enabled (serverRootCACertificate). + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `ldapSigning` + +Specifies whether or not the LDAP traffic needs to be signed. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. | + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. + +- Required: No +- Type: array + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `serverRootCACertificate` + +A server Root certificate is required of ldapOverTLS is enabled. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `smbServerNamePrefix` + +Required if domainName is specified. NetBIOS name of the SMB server. A computer account with this prefix will be registered in the AD and used to mount volumes. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `snapshotPolicies` + +The snapshot policies to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-snapshotpoliciesname) | string | The name of the snapshot policy. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dailySchedule`](#parameter-snapshotpoliciesdailyschedule) | object | Daily schedule for the snapshot policy. | +| [`hourlySchedule`](#parameter-snapshotpolicieshourlyschedule) | object | Hourly schedule for the snapshot policy. | +| [`location`](#parameter-snapshotpolicieslocation) | string | Location of the snapshot policy. | +| [`monthlySchedule`](#parameter-snapshotpoliciesmonthlyschedule) | object | Monthly schedule for the snapshot policy. | +| [`weeklySchedule`](#parameter-snapshotpoliciesweeklyschedule) | object | Weekly schedule for the snapshot policy. | + +### Parameter: `snapshotPolicies.name` + +The name of the snapshot policy. + +- Required: Yes +- Type: string + +### Parameter: `snapshotPolicies.dailySchedule` + +Daily schedule for the snapshot policy. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`hour`](#parameter-snapshotpoliciesdailyschedulehour) | int | The daily snapshot hour. | +| [`minute`](#parameter-snapshotpoliciesdailyscheduleminute) | int | The daily snapshot minute. | +| [`snapshotsToKeep`](#parameter-snapshotpoliciesdailyschedulesnapshotstokeep) | int | Daily snapshot count to keep. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`usedBytes`](#parameter-snapshotpoliciesdailyscheduleusedbytes) | int | Resource size in bytes, current storage usage for the volume in bytes. | + +### Parameter: `snapshotPolicies.dailySchedule.hour` + +The daily snapshot hour. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 23 + +### Parameter: `snapshotPolicies.dailySchedule.minute` + +The daily snapshot minute. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 59 + +### Parameter: `snapshotPolicies.dailySchedule.snapshotsToKeep` + +Daily snapshot count to keep. + +- Required: Yes +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `snapshotPolicies.dailySchedule.usedBytes` + +Resource size in bytes, current storage usage for the volume in bytes. + +- Required: No +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `snapshotPolicies.hourlySchedule` + +Hourly schedule for the snapshot policy. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`minute`](#parameter-snapshotpolicieshourlyscheduleminute) | int | The hourly snapshot minute. | +| [`snapshotsToKeep`](#parameter-snapshotpolicieshourlyschedulesnapshotstokeep) | int | Hourly snapshot count to keep. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`usedBytes`](#parameter-snapshotpolicieshourlyscheduleusedbytes) | int | Resource size in bytes, current storage usage for the volume in bytes. | + +### Parameter: `snapshotPolicies.hourlySchedule.minute` + +The hourly snapshot minute. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 59 + +### Parameter: `snapshotPolicies.hourlySchedule.snapshotsToKeep` + +Hourly snapshot count to keep. + +- Required: Yes +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `snapshotPolicies.hourlySchedule.usedBytes` + +Resource size in bytes, current storage usage for the volume in bytes. + +- Required: No +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `snapshotPolicies.location` + +Location of the snapshot policy. + +- Required: No +- Type: string + +### Parameter: `snapshotPolicies.monthlySchedule` + +Monthly schedule for the snapshot policy. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`daysOfMonth`](#parameter-snapshotpoliciesmonthlyscheduledaysofmonth) | string | Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'. | +| [`hour`](#parameter-snapshotpoliciesmonthlyschedulehour) | int | The monthly snapshot hour. | +| [`minute`](#parameter-snapshotpoliciesmonthlyscheduleminute) | int | The monthly snapshot minute. | +| [`snapshotsToKeep`](#parameter-snapshotpoliciesmonthlyschedulesnapshotstokeep) | int | Monthly snapshot count to keep. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`usedBytes`](#parameter-snapshotpoliciesmonthlyscheduleusedbytes) | int | Resource size in bytes, current storage usage for the volume in bytes. | + +### Parameter: `snapshotPolicies.monthlySchedule.daysOfMonth` + +Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'. + +- Required: Yes +- Type: string + +### Parameter: `snapshotPolicies.monthlySchedule.hour` + +The monthly snapshot hour. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 23 + +### Parameter: `snapshotPolicies.monthlySchedule.minute` + +The monthly snapshot minute. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 59 + +### Parameter: `snapshotPolicies.monthlySchedule.snapshotsToKeep` + +Monthly snapshot count to keep. + +- Required: Yes +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `snapshotPolicies.monthlySchedule.usedBytes` + +Resource size in bytes, current storage usage for the volume in bytes. + +- Required: No +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `snapshotPolicies.weeklySchedule` + +Weekly schedule for the snapshot policy. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`day`](#parameter-snapshotpoliciesweeklyscheduleday) | string | The weekly snapshot day. | +| [`hour`](#parameter-snapshotpoliciesweeklyschedulehour) | int | The weekly snapshot hour. | +| [`minute`](#parameter-snapshotpoliciesweeklyscheduleminute) | int | The weekly snapshot minute. | +| [`snapshotsToKeep`](#parameter-snapshotpoliciesweeklyschedulesnapshotstokeep) | int | Weekly snapshot count to keep. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`usedBytes`](#parameter-snapshotpoliciesweeklyscheduleusedbytes) | int | Resource size in bytes, current storage usage for the volume in bytes. | + +### Parameter: `snapshotPolicies.weeklySchedule.day` + +The weekly snapshot day. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Friday' + 'Monday' + 'Saturday' + 'Sunday' + 'Thursday' + 'Tuesday' + 'Wednesday' + ] + ``` + +### Parameter: `snapshotPolicies.weeklySchedule.hour` + +The weekly snapshot hour. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 23 + +### Parameter: `snapshotPolicies.weeklySchedule.minute` + +The weekly snapshot minute. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 59 + +### Parameter: `snapshotPolicies.weeklySchedule.snapshotsToKeep` + +Weekly snapshot count to keep. + +- Required: Yes +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `snapshotPolicies.weeklySchedule.usedBytes` + +Resource size in bytes, current storage usage for the volume in bytes. + +- Required: No +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `tags` + +Tags for all resources. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `capacityPoolResourceIds` | array | The resource IDs of the created capacity pools & their volumes. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the NetApp account. | +| `resourceGroupName` | string | The name of the Resource Group the NetApp account was created in. | +| `resourceId` | string | The Resource ID of the NetApp account. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.4.0` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/net-app/net-app-account/backup-policies/README.md b/avm/1.1.0/res/net-app/net-app-account/backup-policies/README.md new file mode 100644 index 000000000..a4a644ab1 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/backup-policies/README.md @@ -0,0 +1,109 @@ +# Azure NetApp Files Backup Policy `[Microsoft.NetApp/netAppAccounts/backupPolicies]` + +This module deploys a Backup Policy for Azure NetApp File. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.NetApp/netAppAccounts/backupPolicies` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/backupPolicies) | + +## Parameters + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`netAppAccountName`](#parameter-netappaccountname) | string | The name of the parent NetApp account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dailyBackupsToKeep`](#parameter-dailybackupstokeep) | int | The daily backups to keep. | +| [`enabled`](#parameter-enabled) | bool | Indicates whether the backup policy is enabled. | +| [`location`](#parameter-location) | string | The location of the backup policy. | +| [`monthlyBackupsToKeep`](#parameter-monthlybackupstokeep) | int | The monthly backups to keep. | +| [`name`](#parameter-name) | string | The name of the backup policy. | +| [`weeklyBackupsToKeep`](#parameter-weeklybackupstokeep) | int | The weekly backups to keep. | + +### Parameter: `netAppAccountName` + +The name of the parent NetApp account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `dailyBackupsToKeep` + +The daily backups to keep. + +- Required: No +- Type: int +- Default: `2` +- MinValue: 2 +- MaxValue: 1019 + +### Parameter: `enabled` + +Indicates whether the backup policy is enabled. + +- Required: No +- Type: bool +- Default: `True` +- MinValue: 2 +- MaxValue: 1019 + +### Parameter: `location` + +The location of the backup policy. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` +- MinValue: 2 +- MaxValue: 1019 + +### Parameter: `monthlyBackupsToKeep` + +The monthly backups to keep. + +- Required: No +- Type: int +- Default: `0` +- MinValue: 2 +- MaxValue: 1019 + +### Parameter: `name` + +The name of the backup policy. + +- Required: No +- Type: string +- Default: `'backupPolicy'` +- MinValue: 2 +- MaxValue: 1019 + +### Parameter: `weeklyBackupsToKeep` + +The weekly backups to keep. + +- Required: No +- Type: int +- Default: `0` +- MinValue: 2 +- MaxValue: 1019 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the Backup Policy. | +| `resourceGroupName` | string | The name of the Resource Group the Backup Policy was created in. | +| `resourceId` | string | The resource IDs of the backup Policy created within volume. | diff --git a/avm/1.1.0/res/net-app/net-app-account/backup-policies/main.bicep b/avm/1.1.0/res/net-app/net-app-account/backup-policies/main.bicep new file mode 100644 index 000000000..61e25a472 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/backup-policies/main.bicep @@ -0,0 +1,49 @@ +metadata name = 'Azure NetApp Files Backup Policy' +metadata description = 'This module deploys a Backup Policy for Azure NetApp File.' + +@description('Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment.') +param netAppAccountName string + +@description('Optional. The name of the backup policy.') +param name string = 'backupPolicy' + +@description('Optional. The location of the backup policy.') +param location string = resourceGroup().location + +@description('Optional. The daily backups to keep.') +@minValue(2) +@maxValue(1019) +param dailyBackupsToKeep int = 2 + +@description('Optional. The monthly backups to keep.') +param monthlyBackupsToKeep int = 0 + +@description('Optional. The weekly backups to keep.') +param weeklyBackupsToKeep int = 0 + +@description('Optional. Indicates whether the backup policy is enabled.') +param enabled bool = true + +resource netAppAccount 'Microsoft.NetApp/netAppAccounts@2024-07-01' existing = { + name: netAppAccountName +} + +resource backupPolicies 'Microsoft.NetApp/netAppAccounts/backupPolicies@2024-07-01' = { + name: name + parent: netAppAccount + location: location + properties: { + enabled: enabled + dailyBackupsToKeep: dailyBackupsToKeep + weeklyBackupsToKeep: weeklyBackupsToKeep + monthlyBackupsToKeep: monthlyBackupsToKeep + } +} +@description('The resource IDs of the backup Policy created within volume.') +output resourceId string = backupPolicies.id + +@description('The name of the Backup Policy.') +output name string = backupPolicies.name + +@description('The name of the Resource Group the Backup Policy was created in.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/net-app/net-app-account/backup-policies/main.json b/avm/1.1.0/res/net-app/net-app-account/backup-policies/main.json new file mode 100644 index 000000000..a77278bec --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/backup-policies/main.json @@ -0,0 +1,102 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "7141176618644423280" + }, + "name": "Azure NetApp Files Backup Policy", + "description": "This module deploys a Backup Policy for Azure NetApp File." + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "backupPolicy", + "metadata": { + "description": "Optional. The name of the backup policy." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the backup policy." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "defaultValue": 2, + "minValue": 2, + "maxValue": 1019, + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "enabled": "[parameters('enabled')]", + "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", + "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]", + "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the backup Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Backup Policy was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/net-app/net-app-account/backup-vault/README.md b/avm/1.1.0/res/net-app/net-app-account/backup-vault/README.md new file mode 100644 index 000000000..b800706df --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/backup-vault/README.md @@ -0,0 +1,121 @@ +# Azure NetApp Files Volume Backup Vault `[Microsoft.NetApp/netAppAccounts/backupVaults]` + +This module deploys a NetApp Files Backup Vault. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.NetApp/netAppAccounts/backupVaults` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/backupVaults) | +| `Microsoft.NetApp/netAppAccounts/backupVaults/backups` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/backupVaults/backups) | + +## Parameters + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`netAppAccountName`](#parameter-netappaccountname) | string | The name of the parent NetApp account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backups`](#parameter-backups) | array | The list of backups to create. | +| [`location`](#parameter-location) | string | Location of the backup vault. | +| [`name`](#parameter-name) | string | The name of the backup vault. | + +### Parameter: `netAppAccountName` + +The name of the parent NetApp account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `backups` + +The list of backups to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`capacityPoolName`](#parameter-backupscapacitypoolname) | string | The name of the capacity pool containing the volume. | +| [`volumeName`](#parameter-backupsvolumename) | string | The name of the volume to backup. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`label`](#parameter-backupslabel) | string | Label for backup. | +| [`name`](#parameter-backupsname) | string | The name of the backup. | +| [`snapshotName`](#parameter-backupssnapshotname) | string | The name of the snapshot. | + +### Parameter: `backups.capacityPoolName` + +The name of the capacity pool containing the volume. + +- Required: Yes +- Type: string + +### Parameter: `backups.volumeName` + +The name of the volume to backup. + +- Required: Yes +- Type: string + +### Parameter: `backups.label` + +Label for backup. + +- Required: No +- Type: string + +### Parameter: `backups.name` + +The name of the backup. + +- Required: No +- Type: string + +### Parameter: `backups.snapshotName` + +The name of the snapshot. + +- Required: No +- Type: string + +### Parameter: `location` + +Location of the backup vault. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `name` + +The name of the backup vault. + +- Required: No +- Type: string +- Default: `'vault'` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the backup vault. | +| `resourceGroupName` | string | The name of the Resource Group the backup vault was created in. | +| `resourceId` | string | The Resource ID of the backup vault. | diff --git a/avm/1.1.0/res/net-app/net-app-account/backup-vault/backup/README.md b/avm/1.1.0/res/net-app/net-app-account/backup-vault/backup/README.md new file mode 100644 index 000000000..05f791c95 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/backup-vault/backup/README.md @@ -0,0 +1,97 @@ +# Azure NetApp Files Volume Backup `[Microsoft.NetApp/netAppAccounts/backupVaults/backups]` + +This module deploys a backup of a NetApp Files Volume. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.NetApp/netAppAccounts/backupVaults/backups` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/backupVaults/backups) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`capacityPoolName`](#parameter-capacitypoolname) | string | The name of the capacity pool containing the volume. | +| [`volumeName`](#parameter-volumename) | string | The name of the volume to backup. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backupVaultName`](#parameter-backupvaultname) | string | The name of the parent backup vault. Required if the template is used in a standalone deployment. | +| [`netAppAccountName`](#parameter-netappaccountname) | string | The name of the parent NetApp account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`label`](#parameter-label) | string | Label for backup. | +| [`name`](#parameter-name) | string | The name of the backup. | +| [`snapshotName`](#parameter-snapshotname) | string | The name of the snapshot. | + +### Parameter: `capacityPoolName` + +The name of the capacity pool containing the volume. + +- Required: Yes +- Type: string + +### Parameter: `volumeName` + +The name of the volume to backup. + +- Required: Yes +- Type: string + +### Parameter: `backupVaultName` + +The name of the parent backup vault. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `netAppAccountName` + +The name of the parent NetApp account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `label` + +Label for backup. + +- Required: No +- Type: string + +### Parameter: `name` + +The name of the backup. + +- Required: No +- Type: string +- Default: `'backup'` + +### Parameter: `snapshotName` + +The name of the snapshot. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the backup. | +| `resourceGroupName` | string | The name of the Resource Group the backup was created in. | +| `resourceId` | string | The Resource ID of the backup. | diff --git a/avm/1.1.0/res/net-app/net-app-account/backup-vault/backup/main.bicep b/avm/1.1.0/res/net-app/net-app-account/backup-vault/backup/main.bicep new file mode 100644 index 000000000..4532249c5 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/backup-vault/backup/main.bicep @@ -0,0 +1,58 @@ +metadata name = 'Azure NetApp Files Volume Backup' +metadata description = 'This module deploys a backup of a NetApp Files Volume.' + +@description('Optional. The name of the backup.') +param name string = 'backup' + +@description('Conditional. The name of the parent backup vault. Required if the template is used in a standalone deployment.') +param backupVaultName string + +@description('Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment.') +param netAppAccountName string + +@description('Optional. Label for backup.') +param label string? + +@description('Optional. The name of the snapshot.') +param snapshotName string? + +@description('Required. The name of the volume to backup.') +param volumeName string + +@description('Required. The name of the capacity pool containing the volume.') +param capacityPoolName string + +resource netAppAccount 'Microsoft.NetApp/netAppAccounts@2024-07-01' existing = { + name: netAppAccountName + + resource backupVault 'backupVaults@2024-07-01' existing = { + name: backupVaultName + } + + resource remoteCapacityPool 'capacityPools@2024-07-01' existing = { + name: capacityPoolName + + resource volume 'volumes@2024-07-01' existing = { + name: volumeName + } + } +} + +resource backup 'Microsoft.NetApp/netAppAccounts/backupVaults/backups@2024-07-01' = { + name: name + parent: netAppAccount::backupVault + properties: { + label: label + snapshotName: snapshotName + volumeResourceId: netAppAccount::remoteCapacityPool::volume.id + } +} + +@description('The name of the backup.') +output name string = backup.name + +@description('The Resource ID of the backup.') +output resourceId string = backup.id + +@description('The name of the Resource Group the backup was created in.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/net-app/net-app-account/backup-vault/backup/main.json b/avm/1.1.0/res/net-app/net-app-account/backup-vault/backup/main.json new file mode 100644 index 000000000..5257b0d5a --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/backup-vault/backup/main.json @@ -0,0 +1,120 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "3948084235912412629" + }, + "name": "Azure NetApp Files Volume Backup", + "description": "This module deploys a backup of a NetApp Files Volume." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "backup", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent backup vault. Required if the template is used in a standalone deployment." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "resources": { + "netAppAccount::remoteCapacityPool::volume": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + }, + "netAppAccount::backupVault": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupVaultName'))]" + }, + "netAppAccount::remoteCapacityPool": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" + }, + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backup": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults/backups", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]", + "properties": { + "label": "[parameters('label')]", + "snapshotName": "[parameters('snapshotName')]", + "volumeResourceId": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults/backups', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/net-app/net-app-account/backup-vault/main.bicep b/avm/1.1.0/res/net-app/net-app-account/backup-vault/main.bicep new file mode 100644 index 000000000..bf683b069 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/backup-vault/main.bicep @@ -0,0 +1,75 @@ +metadata name = 'Azure NetApp Files Volume Backup Vault' +metadata description = 'This module deploys a NetApp Files Backup Vault.' + +@description('Optional. The name of the backup vault.') +param name string = 'vault' + +@description('Optional. Location of the backup vault.') +param location string = resourceGroup().location + +@description('Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment.') +param netAppAccountName string + +@description('Optional. The list of backups to create.') +param backups backupType[]? + +resource netAppAccount 'Microsoft.NetApp/netAppAccounts@2024-07-01' existing = { + name: netAppAccountName +} + +resource backupVault 'Microsoft.NetApp/netAppAccounts/backupVaults@2024-07-01' = { + name: name + parent: netAppAccount + location: location + properties: {} +} + +module backupVault_backups 'backup/main.bicep' = [ + for (backup, index) in (backups ?? []): { + name: '${uniqueString(deployment().name, location)}-ANF-Backup-${index}' + params: { + netAppAccountName: netAppAccount.name + backupVaultName: backupVault.name + name: backup.?name + label: backup.?label + snapshotName: backup.?snapshotName + volumeName: backup.volumeName + capacityPoolName: backup.capacityPoolName + } + } +] + +@description('The name of the backup vault.') +output name string = backupVault.name + +@description('The Resource ID of the backup vault.') +output resourceId string = backupVault.id + +@description('The name of the Resource Group the backup vault was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = backupVault.location + +// ================ // +// Definitions // +// ================ // + +@export() +@description('The type for a backup.') +type backupType = { + @description('Optional. The name of the backup.') + name: string? + + @description('Optional. Label for backup.') + label: string? + + @description('Optional. The name of the snapshot.') + snapshotName: string? + + @description('Required. The name of the volume to backup.') + volumeName: string + + @description('Required. The name of the capacity pool containing the volume.') + capacityPoolName: string +} diff --git a/avm/1.1.0/res/net-app/net-app-account/backup-vault/main.json b/avm/1.1.0/res/net-app/net-app-account/backup-vault/main.json new file mode 100644 index 000000000..7a827614d --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/backup-vault/main.json @@ -0,0 +1,296 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "9738469557677047438" + }, + "name": "Azure NetApp Files Volume Backup Vault", + "description": "This module deploys a NetApp Files Backup Vault." + }, + "definitions": { + "backupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backup." + } + } + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "vault", + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the backup vault." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backups": { + "type": "array", + "items": { + "$ref": "#/definitions/backupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of backups to create." + } + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backupVault": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": {} + }, + "backupVault_backups": { + "copy": { + "name": "backupVault_backups", + "count": "[length(coalesce(parameters('backups'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANF-Backup-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "backupVaultName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'name')]" + }, + "label": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'label')]" + }, + "snapshotName": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'snapshotName')]" + }, + "volumeName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].volumeName]" + }, + "capacityPoolName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].capacityPoolName]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "3948084235912412629" + }, + "name": "Azure NetApp Files Volume Backup", + "description": "This module deploys a backup of a NetApp Files Volume." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "backup", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent backup vault. Required if the template is used in a standalone deployment." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "resources": { + "netAppAccount::remoteCapacityPool::volume": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + }, + "netAppAccount::backupVault": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupVaultName'))]" + }, + "netAppAccount::remoteCapacityPool": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" + }, + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backup": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults/backups", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]", + "properties": { + "label": "[parameters('label')]", + "snapshotName": "[parameters('snapshotName')]", + "volumeResourceId": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults/backups', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "backupVault" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup vault." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup vault." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup vault was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('backupVault', '2024-07-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/net-app/net-app-account/capacity-pool/README.md b/avm/1.1.0/res/net-app/net-app-account/capacity-pool/README.md new file mode 100644 index 000000000..092e072e7 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/capacity-pool/README.md @@ -0,0 +1,887 @@ +# Azure NetApp Files Capacity Pools `[Microsoft.NetApp/netAppAccounts/capacityPools]` + +This module deploys an Azure NetApp Files Capacity Pool. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.NetApp/netAppAccounts/capacityPools` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/capacityPools) | +| `Microsoft.NetApp/netAppAccounts/capacityPools/volumes` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/capacityPools/volumes) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the capacity pool. | +| [`size`](#parameter-size) | int | Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104). | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`netAppAccountName`](#parameter-netappaccountname) | string | The name of the parent NetApp account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`coolAccess`](#parameter-coolaccess) | bool | If enabled (true) the pool can contain cool Access enabled volumes. | +| [`encryptionType`](#parameter-encryptiontype) | string | Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool. | +| [`location`](#parameter-location) | string | Location of the pool volume. | +| [`qosType`](#parameter-qostype) | string | The qos type of the pool. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`serviceLevel`](#parameter-servicelevel) | string | The pool service level. | +| [`tags`](#parameter-tags) | object | Tags for all resources. | +| [`volumes`](#parameter-volumes) | array | List of volumes to create in the capacity pool. | + +### Parameter: `name` + +The name of the capacity pool. + +- Required: Yes +- Type: string + +### Parameter: `size` + +Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104). + +- Required: Yes +- Type: int + +### Parameter: `netAppAccountName` + +The name of the parent NetApp account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `coolAccess` + +If enabled (true) the pool can contain cool Access enabled volumes. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `encryptionType` + +Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool. + +- Required: No +- Type: string +- Default: `'Single'` +- Allowed: + ```Bicep + [ + 'Double' + 'Single' + ] + ``` + +### Parameter: `location` + +Location of the pool volume. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `qosType` + +The qos type of the pool. + +- Required: No +- Type: string +- Default: `'Auto'` +- Allowed: + ```Bicep + [ + 'Auto' + 'Manual' + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `serviceLevel` + +The pool service level. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Premium' + 'Standard' + 'StandardZRS' + 'Ultra' + ] + ``` + +### Parameter: `tags` + +Tags for all resources. + +- Required: No +- Type: object + +### Parameter: `volumes` + +List of volumes to create in the capacity pool. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-volumesname) | string | The name of the pool volume. | +| [`subnetResourceId`](#parameter-volumessubnetresourceid) | string | The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes. | +| [`usageThreshold`](#parameter-volumesusagethreshold) | int | Maximum storage quota allowed for a file system in bytes. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`coolAccess`](#parameter-volumescoolaccess) | bool | If enabled (true) the pool can contain cool Access enabled volumes. | +| [`coolAccessRetrievalPolicy`](#parameter-volumescoolaccessretrievalpolicy) | string | Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read). | +| [`coolnessPeriod`](#parameter-volumescoolnessperiod) | int | Specifies the number of days after which data that is not accessed by clients will be tiered. | +| [`creationToken`](#parameter-volumescreationtoken) | string | A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription. | +| [`dataProtection`](#parameter-volumesdataprotection) | object | DataProtection type volumes include an object containing details of the replication. | +| [`encryptionKeySource`](#parameter-volumesencryptionkeysource) | string | The source of the encryption key. | +| [`exportPolicy`](#parameter-volumesexportpolicy) | object | Export policy rules. | +| [`kerberosEnabled`](#parameter-volumeskerberosenabled) | bool | Define if a volume is KerberosEnabled. | +| [`keyVaultPrivateEndpointResourceId`](#parameter-volumeskeyvaultprivateendpointresourceid) | string | The resource ID of the key vault private endpoint. | +| [`location`](#parameter-volumeslocation) | string | Location of the pool volume. | +| [`networkFeatures`](#parameter-volumesnetworkfeatures) | string | Network feature for the volume. | +| [`protocolTypes`](#parameter-volumesprotocoltypes) | array | Set of protocol types. | +| [`roleAssignments`](#parameter-volumesroleassignments) | array | Array of role assignments to create. | +| [`serviceLevel`](#parameter-volumesservicelevel) | string | The pool service level. Must match the one of the parent capacity pool. | +| [`smbContinuouslyAvailable`](#parameter-volumessmbcontinuouslyavailable) | bool | Enables continuously available share property for SMB volume. Only applicable for SMB volume. | +| [`smbEncryption`](#parameter-volumessmbencryption) | bool | Enables SMB encryption. Only applicable for SMB/DualProtocol volume. | +| [`smbNonBrowsable`](#parameter-volumessmbnonbrowsable) | string | Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume. | +| [`volumeType`](#parameter-volumesvolumetype) | string | The type of the volume. DataProtection volumes are used for replication. | +| [`zones`](#parameter-volumeszones) | array | Zone where the volume will be placed. | + +### Parameter: `volumes.name` + +The name of the pool volume. + +- Required: Yes +- Type: string + +### Parameter: `volumes.subnetResourceId` + +The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes. + +- Required: Yes +- Type: string + +### Parameter: `volumes.usageThreshold` + +Maximum storage quota allowed for a file system in bytes. + +- Required: Yes +- Type: int + +### Parameter: `volumes.coolAccess` + +If enabled (true) the pool can contain cool Access enabled volumes. + +- Required: No +- Type: bool + +### Parameter: `volumes.coolAccessRetrievalPolicy` + +Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read). + +- Required: No +- Type: string + +### Parameter: `volumes.coolnessPeriod` + +Specifies the number of days after which data that is not accessed by clients will be tiered. + +- Required: No +- Type: int + +### Parameter: `volumes.creationToken` + +A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription. + +- Required: No +- Type: string + +### Parameter: `volumes.dataProtection` + +DataProtection type volumes include an object containing details of the replication. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backup`](#parameter-volumesdataprotectionbackup) | object | Backup properties. | +| [`replication`](#parameter-volumesdataprotectionreplication) | object | Replication properties. | +| [`snapshot`](#parameter-volumesdataprotectionsnapshot) | object | Snapshot properties. | + +### Parameter: `volumes.dataProtection.backup` + +Backup properties. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backupPolicyName`](#parameter-volumesdataprotectionbackupbackuppolicyname) | string | The name of the backup policy to link. | +| [`backupVaultName`](#parameter-volumesdataprotectionbackupbackupvaultname) | string | The name of the Backup Vault. | +| [`policyEnforced`](#parameter-volumesdataprotectionbackuppolicyenforced) | bool | Enable to enforce the policy. | + +### Parameter: `volumes.dataProtection.backup.backupPolicyName` + +The name of the backup policy to link. + +- Required: Yes +- Type: string + +### Parameter: `volumes.dataProtection.backup.backupVaultName` + +The name of the Backup Vault. + +- Required: Yes +- Type: string + +### Parameter: `volumes.dataProtection.backup.policyEnforced` + +Enable to enforce the policy. + +- Required: Yes +- Type: bool + +### Parameter: `volumes.dataProtection.replication` + +Replication properties. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`endpointType`](#parameter-volumesdataprotectionreplicationendpointtype) | string | Indicates whether the local volume is the source or destination for the Volume Replication. | +| [`replicationSchedule`](#parameter-volumesdataprotectionreplicationreplicationschedule) | string | The replication schedule for the volume. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`remotePath`](#parameter-volumesdataprotectionreplicationremotepath) | object | The full path to a volume that is to be migrated into ANF. Required for Migration volumes. | +| [`remoteVolumeRegion`](#parameter-volumesdataprotectionreplicationremotevolumeregion) | string | The remote region for the other end of the Volume Replication.Required for Data Protection volumes. | +| [`remoteVolumeResourceId`](#parameter-volumesdataprotectionreplicationremotevolumeresourceid) | string | The resource ID of the remote volume. Required for Data Protection volumes. | + +### Parameter: `volumes.dataProtection.replication.endpointType` + +Indicates whether the local volume is the source or destination for the Volume Replication. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'dst' + 'src' + ] + ``` + +### Parameter: `volumes.dataProtection.replication.replicationSchedule` + +The replication schedule for the volume. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + '_10minutely' + 'daily' + 'hourly' + ] + ``` + +### Parameter: `volumes.dataProtection.replication.remotePath` + +The full path to a volume that is to be migrated into ANF. Required for Migration volumes. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`externalHostName`](#parameter-volumesdataprotectionreplicationremotepathexternalhostname) | string | The Path to a ONTAP Host. | +| [`serverName`](#parameter-volumesdataprotectionreplicationremotepathservername) | string | The name of a server on the ONTAP Host. | +| [`volumeName`](#parameter-volumesdataprotectionreplicationremotepathvolumename) | string | The name of a volume on the server. | + +### Parameter: `volumes.dataProtection.replication.remotePath.externalHostName` + +The Path to a ONTAP Host. + +- Required: Yes +- Type: string + +### Parameter: `volumes.dataProtection.replication.remotePath.serverName` + +The name of a server on the ONTAP Host. + +- Required: Yes +- Type: string + +### Parameter: `volumes.dataProtection.replication.remotePath.volumeName` + +The name of a volume on the server. + +- Required: Yes +- Type: string + +### Parameter: `volumes.dataProtection.replication.remoteVolumeRegion` + +The remote region for the other end of the Volume Replication.Required for Data Protection volumes. + +- Required: No +- Type: string + +### Parameter: `volumes.dataProtection.replication.remoteVolumeResourceId` + +The resource ID of the remote volume. Required for Data Protection volumes. + +- Required: No +- Type: string + +### Parameter: `volumes.dataProtection.snapshot` + +Snapshot properties. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`snapshotPolicyName`](#parameter-volumesdataprotectionsnapshotsnapshotpolicyname) | string | The name of the snapshot policy to link. | + +### Parameter: `volumes.dataProtection.snapshot.snapshotPolicyName` + +The name of the snapshot policy to link. + +- Required: Yes +- Type: string + +### Parameter: `volumes.encryptionKeySource` + +The source of the encryption key. + +- Required: No +- Type: string + +### Parameter: `volumes.exportPolicy` + +Export policy rules. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`rules`](#parameter-volumesexportpolicyrules) | array | The Export policy rules. | + +### Parameter: `volumes.exportPolicy.rules` + +The Export policy rules. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kerberos5iReadOnly`](#parameter-volumesexportpolicyruleskerberos5ireadonly) | bool | Kerberos5i Read only access. | +| [`kerberos5iReadWrite`](#parameter-volumesexportpolicyruleskerberos5ireadwrite) | bool | Kerberos5i Read and write access. | +| [`kerberos5pReadOnly`](#parameter-volumesexportpolicyruleskerberos5preadonly) | bool | Kerberos5p Read only access. | +| [`kerberos5pReadWrite`](#parameter-volumesexportpolicyruleskerberos5preadwrite) | bool | Kerberos5p Read and write access. | +| [`kerberos5ReadOnly`](#parameter-volumesexportpolicyruleskerberos5readonly) | bool | Kerberos5 Read only access. | +| [`kerberos5ReadWrite`](#parameter-volumesexportpolicyruleskerberos5readwrite) | bool | Kerberos5 Read and write access. | +| [`nfsv3`](#parameter-volumesexportpolicyrulesnfsv3) | bool | Allows NFSv3 protocol. Enable only for NFSv3 type volumes. | +| [`nfsv41`](#parameter-volumesexportpolicyrulesnfsv41) | bool | Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes. | +| [`ruleIndex`](#parameter-volumesexportpolicyrulesruleindex) | int | Order index. | +| [`unixReadOnly`](#parameter-volumesexportpolicyrulesunixreadonly) | bool | Read only access. | +| [`unixReadWrite`](#parameter-volumesexportpolicyrulesunixreadwrite) | bool | Read and write access. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowedClients`](#parameter-volumesexportpolicyrulesallowedclients) | string | Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names. | +| [`chownMode`](#parameter-volumesexportpolicyruleschownmode) | string | This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own. | +| [`cifs`](#parameter-volumesexportpolicyrulescifs) | bool | Allows CIFS protocol. | +| [`hasRootAccess`](#parameter-volumesexportpolicyruleshasrootaccess) | bool | Has root access to volume. | + +### Parameter: `volumes.exportPolicy.rules.kerberos5iReadOnly` + +Kerberos5i Read only access. + +- Required: Yes +- Type: bool + +### Parameter: `volumes.exportPolicy.rules.kerberos5iReadWrite` + +Kerberos5i Read and write access. + +- Required: Yes +- Type: bool + +### Parameter: `volumes.exportPolicy.rules.kerberos5pReadOnly` + +Kerberos5p Read only access. + +- Required: Yes +- Type: bool + +### Parameter: `volumes.exportPolicy.rules.kerberos5pReadWrite` + +Kerberos5p Read and write access. + +- Required: Yes +- Type: bool + +### Parameter: `volumes.exportPolicy.rules.kerberos5ReadOnly` + +Kerberos5 Read only access. + +- Required: Yes +- Type: bool + +### Parameter: `volumes.exportPolicy.rules.kerberos5ReadWrite` + +Kerberos5 Read and write access. + +- Required: Yes +- Type: bool + +### Parameter: `volumes.exportPolicy.rules.nfsv3` + +Allows NFSv3 protocol. Enable only for NFSv3 type volumes. + +- Required: Yes +- Type: bool + +### Parameter: `volumes.exportPolicy.rules.nfsv41` + +Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes. + +- Required: Yes +- Type: bool + +### Parameter: `volumes.exportPolicy.rules.ruleIndex` + +Order index. + +- Required: Yes +- Type: int + +### Parameter: `volumes.exportPolicy.rules.unixReadOnly` + +Read only access. + +- Required: Yes +- Type: bool + +### Parameter: `volumes.exportPolicy.rules.unixReadWrite` + +Read and write access. + +- Required: Yes +- Type: bool + +### Parameter: `volumes.exportPolicy.rules.allowedClients` + +Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names. + +- Required: No +- Type: string + +### Parameter: `volumes.exportPolicy.rules.chownMode` + +This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Restricted' + 'Unrestricted' + ] + ``` + +### Parameter: `volumes.exportPolicy.rules.cifs` + +Allows CIFS protocol. + +- Required: No +- Type: bool + +### Parameter: `volumes.exportPolicy.rules.hasRootAccess` + +Has root access to volume. + +- Required: No +- Type: bool + +### Parameter: `volumes.kerberosEnabled` + +Define if a volume is KerberosEnabled. + +- Required: No +- Type: bool + +### Parameter: `volumes.keyVaultPrivateEndpointResourceId` + +The resource ID of the key vault private endpoint. + +- Required: No +- Type: string + +### Parameter: `volumes.location` + +Location of the pool volume. + +- Required: No +- Type: string + +### Parameter: `volumes.networkFeatures` + +Network feature for the volume. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Basic' + 'Basic_Standard' + 'Standard' + 'Standard_Basic' + ] + ``` + +### Parameter: `volumes.protocolTypes` + +Set of protocol types. + +- Required: No +- Type: array + +### Parameter: `volumes.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-volumesroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-volumesroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-volumesroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-volumesroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-volumesroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-volumesroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-volumesroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-volumesroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `volumes.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `volumes.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `volumes.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `volumes.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `volumes.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `volumes.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `volumes.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `volumes.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `volumes.serviceLevel` + +The pool service level. Must match the one of the parent capacity pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Premium' + 'Standard' + 'StandardZRS' + 'Ultra' + ] + ``` + +### Parameter: `volumes.smbContinuouslyAvailable` + +Enables continuously available share property for SMB volume. Only applicable for SMB volume. + +- Required: No +- Type: bool + +### Parameter: `volumes.smbEncryption` + +Enables SMB encryption. Only applicable for SMB/DualProtocol volume. + +- Required: No +- Type: bool + +### Parameter: `volumes.smbNonBrowsable` + +Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `volumes.volumeType` + +The type of the volume. DataProtection volumes are used for replication. + +- Required: No +- Type: string + +### Parameter: `volumes.zones` + +Zone where the volume will be placed. + +- Required: No +- Type: array + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the Capacity Pool. | +| `resourceGroupName` | string | The name of the Resource Group the Capacity Pool was created in. | +| `resourceId` | string | The resource ID of the Capacity Pool. | +| `volumeResourceIds` | array | The resource IDs of the volume created in the capacity pool. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.4.0` | Remote reference | diff --git a/avm/1.1.0/res/net-app/net-app-account/capacity-pool/main.bicep b/avm/1.1.0/res/net-app/net-app-account/capacity-pool/main.bicep new file mode 100644 index 000000000..16f124f16 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/capacity-pool/main.bicep @@ -0,0 +1,234 @@ +metadata name = 'Azure NetApp Files Capacity Pools' +metadata description = 'This module deploys an Azure NetApp Files Capacity Pool.' + +@description('Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment.') +param netAppAccountName string + +@description('Required. The name of the capacity pool.') +param name string + +@description('Optional. Location of the pool volume.') +param location string = resourceGroup().location + +@description('Optional. Tags for all resources.') +param tags object? + +@description('Optional. The pool service level.') +@allowed([ + 'Premium' + 'Standard' + 'StandardZRS' + 'Ultra' +]) +param serviceLevel string = 'Standard' + +@description('Required. Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104).') +param size int + +@description('Optional. The qos type of the pool.') +@allowed([ + 'Auto' + 'Manual' +]) +param qosType string = 'Auto' + +@description('Optional. List of volumes to create in the capacity pool.') +param volumes volumeType[]? + +@description('Optional. If enabled (true) the pool can contain cool Access enabled volumes.') +param coolAccess bool = false + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool.') +@allowed([ + 'Double' + 'Single' +]) +param encryptionType string = 'Single' + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource netAppAccount 'Microsoft.NetApp/netAppAccounts@2024-07-01' existing = { + name: netAppAccountName +} + +resource capacityPool 'Microsoft.NetApp/netAppAccounts/capacityPools@2024-07-01' = { + name: name + parent: netAppAccount + location: location + tags: tags + properties: { + serviceLevel: serviceLevel + size: size + qosType: qosType + coolAccess: coolAccess + encryptionType: encryptionType + } +} + +@batchSize(1) +module capacityPool_volumes 'volume/main.bicep' = [ + for (volume, index) in (volumes ?? []): { + name: '${deployment().name}-Vol-${index}' + params: { + netAppAccountName: netAppAccount.name + capacityPoolName: capacityPool.name + name: volume.name + location: location + serviceLevel: serviceLevel + creationToken: volume.?creationToken ?? volume.name + usageThreshold: volume.usageThreshold + protocolTypes: volume.?protocolTypes + subnetResourceId: volume.subnetResourceId + exportPolicy: volume.?exportPolicy + roleAssignments: volume.?roleAssignments + networkFeatures: volume.?networkFeatures + zones: volume.?zones + coolAccess: volume.?coolAccess ?? false + coolAccessRetrievalPolicy: volume.?coolAccessRetrievalPolicy + coolnessPeriod: volume.?coolnessPeriod + encryptionKeySource: volume.?encryptionKeySource ?? 'Microsoft.NetApp' + keyVaultPrivateEndpointResourceId: volume.?keyVaultPrivateEndpointResourceId + dataProtection: volume.?dataProtection + kerberosEnabled: volume.?kerberosEnabled + smbContinuouslyAvailable: volume.?smbContinuouslyAvailable + smbEncryption: volume.?smbEncryption + smbNonBrowsable: volume.?smbNonBrowsable + volumeType: volume.?volumeType + } + } +] + +resource capacityPool_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(capacityPool.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: capacityPool + } +] + +@description('The name of the Capacity Pool.') +output name string = capacityPool.name + +@description('The resource ID of the Capacity Pool.') +output resourceId string = capacityPool.id + +@description('The name of the Resource Group the Capacity Pool was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = capacityPool.location + +@description('The resource IDs of the volume created in the capacity pool.') +output volumeResourceIds string[] = [ + for (volume, index) in (volumes ?? []): capacityPool_volumes[index].outputs.resourceId +] + +// ================ // +// Definitions // +// ================ // + +import { dataProtectionType, exportPolicyType } from 'volume/main.bicep' +@export() +@description('The type for a volume in the capacity pool.') +type volumeType = { + @description('Required. The name of the pool volume.') + name: string + + @description('Optional. If enabled (true) the pool can contain cool Access enabled volumes.') + coolAccess: bool? + + @description('Optional. Specifies the number of days after which data that is not accessed by clients will be tiered.') + coolnessPeriod: int? + + @description('Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read).') + coolAccessRetrievalPolicy: string? + + @description('Optional. The source of the encryption key.') + encryptionKeySource: string? + + @description('Optional. The resource ID of the key vault private endpoint.') + keyVaultPrivateEndpointResourceId: string? + + @description('Optional. DataProtection type volumes include an object containing details of the replication.') + dataProtection: dataProtectionType? + + @description('Optional. Location of the pool volume.') + location: string? + + @description('Optional. Zone where the volume will be placed.') + zones: int[]? + + @description('Optional. The pool service level. Must match the one of the parent capacity pool.') + serviceLevel: ('Premium' | 'Standard' | 'StandardZRS' | 'Ultra')? + + @description('Optional. Network feature for the volume.') + networkFeatures: ('Basic' | 'Basic_Standard' | 'Standard' | 'Standard_Basic')? + + @description('Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription.') + creationToken: string? + + @description('Required. Maximum storage quota allowed for a file system in bytes.') + usageThreshold: int + + @description('Optional. Set of protocol types.') + protocolTypes: string[]? + + @description('Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes.') + subnetResourceId: string + + @description('Optional. Export policy rules.') + exportPolicy: exportPolicyType? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType[]? + + @description('Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume.') + smbEncryption: bool? + + @description('Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume.') + smbContinuouslyAvailable: bool? + + @description('Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume.') + smbNonBrowsable: ('Enabled' | 'Disabled')? + + @description('Optional. Define if a volume is KerberosEnabled.') + kerberosEnabled: bool? + + @description('Optional. The type of the volume. DataProtection volumes are used for replication.') + volumeType: string? +} diff --git a/avm/1.1.0/res/net-app/net-app-account/capacity-pool/main.json b/avm/1.1.0/res/net-app/net-app-account/capacity-pool/main.json new file mode 100644 index 000000000..6c3e2b32c --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/capacity-pool/main.json @@ -0,0 +1,1543 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "9255104616647372037" + }, + "name": "Azure NetApp Files Capacity Pools", + "description": "This module deploys an Azure NetApp Files Capacity Pool." + }, + "definitions": { + "volumeType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the pool volume." + } + }, + "coolAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "coolnessPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." + } + }, + "coolAccessRetrievalPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." + } + }, + "encryptionKeySource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source of the encryption key." + } + }, + "keyVaultPrivateEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the key vault private endpoint." + } + }, + "dataProtection": { + "$ref": "#/definitions/dataProtectionType", + "nullable": true, + "metadata": { + "description": "Optional. DataProtection type volumes include an object containing details of the replication." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. Zone where the volume will be placed." + } + }, + "serviceLevel": { + "type": "string", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "nullable": true, + "metadata": { + "description": "Optional. The pool service level. Must match the one of the parent capacity pool." + } + }, + "networkFeatures": { + "type": "string", + "allowedValues": [ + "Basic", + "Basic_Standard", + "Standard", + "Standard_Basic" + ], + "nullable": true, + "metadata": { + "description": "Optional. Network feature for the volume." + } + }, + "creationToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." + } + }, + "usageThreshold": { + "type": "int", + "metadata": { + "description": "Required. Maximum storage quota allowed for a file system in bytes." + } + }, + "protocolTypes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Set of protocol types." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." + } + }, + "exportPolicy": { + "$ref": "#/definitions/exportPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Export policy rules." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "smbEncryption": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." + } + }, + "smbContinuouslyAvailable": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." + } + }, + "smbNonBrowsable": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." + } + }, + "kerberosEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Define if a volume is KerberosEnabled." + } + }, + "volumeType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of the volume. DataProtection volumes are used for replication." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a volume in the capacity pool." + } + }, + "_1.backupType": { + "type": "object", + "properties": { + "backupPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the backup policy to link." + } + }, + "policyEnforced": { + "type": "bool", + "metadata": { + "description": "Required. Enable to enforce the policy." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Backup Vault." + } + } + }, + "metadata": { + "description": "The type for the backup properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "_1.replicationType": { + "type": "object", + "properties": { + "endpointType": { + "type": "string", + "allowedValues": [ + "dst", + "src" + ], + "metadata": { + "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." + } + }, + "remoteVolumeRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." + } + }, + "remoteVolumeResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." + } + }, + "replicationSchedule": { + "type": "string", + "allowedValues": [ + "_10minutely", + "daily", + "hourly" + ], + "metadata": { + "description": "Required. The replication schedule for the volume." + } + }, + "remotePath": { + "type": "object", + "properties": { + "externalHostName": { + "type": "string", + "metadata": { + "description": "Required. The Path to a ONTAP Host." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Required. The name of a server on the ONTAP Host." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of a volume on the server." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." + } + } + }, + "metadata": { + "description": "The type for the replication properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "_1.snapshotType": { + "type": "object", + "properties": { + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy to link." + } + } + }, + "metadata": { + "description": "The type for the snapshot properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "dataProtectionType": { + "type": "object", + "properties": { + "replication": { + "$ref": "#/definitions/_1.replicationType", + "nullable": true, + "metadata": { + "description": "Optional. Replication properties." + } + }, + "backup": { + "$ref": "#/definitions/_1.backupType", + "nullable": true, + "metadata": { + "description": "Optional. Backup properties." + } + }, + "snapshot": { + "$ref": "#/definitions/_1.snapshotType", + "nullable": true, + "metadata": { + "description": "Optional. Snapshot properties." + } + } + }, + "metadata": { + "description": "The type for the data protection properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "exportPolicyType": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleIndex": { + "type": "int", + "metadata": { + "description": "Required. Order index." + } + }, + "allowedClients": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." + } + }, + "chownMode": { + "type": "string", + "allowedValues": [ + "Restricted", + "Unrestricted" + ], + "nullable": true, + "metadata": { + "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." + } + }, + "cifs": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allows CIFS protocol." + } + }, + "hasRootAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Has root access to volume." + } + }, + "kerberos5ReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read only access." + } + }, + "kerberos5ReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read and write access." + } + }, + "kerberos5iReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read only access." + } + }, + "kerberos5iReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read and write access." + } + }, + "kerberos5pReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read only access." + } + }, + "kerberos5pReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read and write access." + } + }, + "nfsv3": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." + } + }, + "nfsv41": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." + } + }, + "unixReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Read only access." + } + }, + "unixReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Read and write access." + } + } + } + }, + "metadata": { + "description": "Required. The Export policy rules." + } + } + }, + "metadata": { + "description": "The type for export policy rules.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + } + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for all resources." + } + }, + "serviceLevel": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "metadata": { + "description": "Optional. The pool service level." + } + }, + "size": { + "type": "int", + "metadata": { + "description": "Required. Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104)." + } + }, + "qosType": { + "type": "string", + "defaultValue": "Auto", + "allowedValues": [ + "Auto", + "Manual" + ], + "metadata": { + "description": "Optional. The qos type of the pool." + } + }, + "volumes": { + "type": "array", + "items": { + "$ref": "#/definitions/volumeType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of volumes to create in the capacity pool." + } + }, + "coolAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "encryptionType": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Double", + "Single" + ], + "metadata": { + "description": "Optional. Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "capacityPool": { + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "serviceLevel": "[parameters('serviceLevel')]", + "size": "[parameters('size')]", + "qosType": "[parameters('qosType')]", + "coolAccess": "[parameters('coolAccess')]", + "encryptionType": "[parameters('encryptionType')]" + } + }, + "capacityPool_roleAssignments": { + "copy": { + "name": "capacityPool_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}/capacityPools/{1}', parameters('netAppAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts/capacityPools', parameters('netAppAccountName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "capacityPool" + ] + }, + "capacityPool_volumes": { + "copy": { + "name": "capacityPool_volumes", + "count": "[length(coalesce(parameters('volumes'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Vol-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "capacityPoolName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "serviceLevel": { + "value": "[parameters('serviceLevel')]" + }, + "creationToken": { + "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'creationToken'), coalesce(parameters('volumes'), createArray())[copyIndex()].name)]" + }, + "usageThreshold": { + "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].usageThreshold]" + }, + "protocolTypes": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'protocolTypes')]" + }, + "subnetResourceId": { + "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].subnetResourceId]" + }, + "exportPolicy": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'exportPolicy')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "networkFeatures": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'networkFeatures')]" + }, + "zones": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'zones')]" + }, + "coolAccess": { + "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolAccess'), false())]" + }, + "coolAccessRetrievalPolicy": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolAccessRetrievalPolicy')]" + }, + "coolnessPeriod": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolnessPeriod')]" + }, + "encryptionKeySource": { + "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'encryptionKeySource'), 'Microsoft.NetApp')]" + }, + "keyVaultPrivateEndpointResourceId": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'keyVaultPrivateEndpointResourceId')]" + }, + "dataProtection": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'dataProtection')]" + }, + "kerberosEnabled": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'kerberosEnabled')]" + }, + "smbContinuouslyAvailable": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbContinuouslyAvailable')]" + }, + "smbEncryption": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbEncryption')]" + }, + "smbNonBrowsable": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbNonBrowsable')]" + }, + "volumeType": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'volumeType')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "13717060947862126529" + }, + "name": "Azure NetApp Files Capacity Pool Volumes", + "description": "This module deploys an Azure NetApp Files Capacity Pool Volume." + }, + "definitions": { + "dataProtectionType": { + "type": "object", + "properties": { + "replication": { + "$ref": "#/definitions/replicationType", + "nullable": true, + "metadata": { + "description": "Optional. Replication properties." + } + }, + "backup": { + "$ref": "#/definitions/backupType", + "nullable": true, + "metadata": { + "description": "Optional. Backup properties." + } + }, + "snapshot": { + "$ref": "#/definitions/snapshotType", + "nullable": true, + "metadata": { + "description": "Optional. Snapshot properties." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data protection properties." + } + }, + "replicationType": { + "type": "object", + "properties": { + "endpointType": { + "type": "string", + "allowedValues": [ + "dst", + "src" + ], + "metadata": { + "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." + } + }, + "remoteVolumeRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." + } + }, + "remoteVolumeResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." + } + }, + "replicationSchedule": { + "type": "string", + "allowedValues": [ + "_10minutely", + "daily", + "hourly" + ], + "metadata": { + "description": "Required. The replication schedule for the volume." + } + }, + "remotePath": { + "type": "object", + "properties": { + "externalHostName": { + "type": "string", + "metadata": { + "description": "Required. The Path to a ONTAP Host." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Required. The name of a server on the ONTAP Host." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of a volume on the server." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." + } + } + }, + "metadata": { + "description": "The type for the replication properties." + } + }, + "backupType": { + "type": "object", + "properties": { + "backupPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the backup policy to link." + } + }, + "policyEnforced": { + "type": "bool", + "metadata": { + "description": "Required. Enable to enforce the policy." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Backup Vault." + } + } + }, + "metadata": { + "description": "The type for the backup properties." + } + }, + "snapshotType": { + "type": "object", + "properties": { + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy to link." + } + } + }, + "metadata": { + "description": "The type for the snapshot properties." + } + }, + "exportPolicyType": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleIndex": { + "type": "int", + "metadata": { + "description": "Required. Order index." + } + }, + "allowedClients": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." + } + }, + "chownMode": { + "type": "string", + "allowedValues": [ + "Restricted", + "Unrestricted" + ], + "nullable": true, + "metadata": { + "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." + } + }, + "cifs": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allows CIFS protocol." + } + }, + "hasRootAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Has root access to volume." + } + }, + "kerberos5ReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read only access." + } + }, + "kerberos5ReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read and write access." + } + }, + "kerberos5iReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read only access." + } + }, + "kerberos5iReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read and write access." + } + }, + "kerberos5pReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read only access." + } + }, + "kerberos5pReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read and write access." + } + }, + "nfsv3": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." + } + }, + "nfsv41": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." + } + }, + "unixReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Read only access." + } + }, + "unixReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Read and write access." + } + } + } + }, + "metadata": { + "description": "Required. The Export policy rules." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for export policy rules." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + } + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent capacity pool. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the pool volume." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "coolAccess": { + "type": "bool", + "metadata": { + "description": "Required. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "coolnessPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." + } + }, + "coolAccessRetrievalPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." + } + }, + "encryptionKeySource": { + "type": "string", + "metadata": { + "description": "Required. The source of the encryption key." + } + }, + "keyVaultPrivateEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the key vault private endpoint." + } + }, + "volumeType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of the volume. DataProtection volumes are used for replication." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. Zone where the volume will be placed." + } + }, + "serviceLevel": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "metadata": { + "description": "Optional. The pool service level. Must match the one of the parent capacity pool." + } + }, + "networkFeatures": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Basic_Standard", + "Standard", + "Standard_Basic" + ], + "metadata": { + "description": "Optional. Network feature for the volume." + } + }, + "creationToken": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." + } + }, + "usageThreshold": { + "type": "int", + "metadata": { + "description": "Required. Maximum storage quota allowed for a file system in bytes." + } + }, + "protocolTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Set of protocol types." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." + } + }, + "exportPolicy": { + "$ref": "#/definitions/exportPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. The export policy rules." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "dataProtection": { + "$ref": "#/definitions/dataProtectionType", + "nullable": true, + "metadata": { + "description": "Optional. DataProtection type volumes include an object containing details of the replication." + } + }, + "smbEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." + } + }, + "smbContinuouslyAvailable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." + } + }, + "smbNonBrowsable": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." + } + }, + "kerberosEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Define if a volume is KerberosEnabled." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "remoteCapacityPoolName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], '')]", + "remoteNetAppName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], '')]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "netAppAccount::capacityPool": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" + }, + "netAppAccount::backupVault": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))]" + }, + "netAppAccount::backupPolicy": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName'))]" + }, + "netAppAccount::snapshotPolicy": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'snapshot')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))]" + }, + "remoteNetAppAccount::remoteCapacityPool::remoteVolume": { + "condition": "[and(and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName'))))), not(empty(tryGet(parameters('dataProtection'), 'replication'))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}/{2}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/')))]" + }, + "remoteNetAppAccount::remoteCapacityPool": { + "condition": "[and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName')))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10])]" + }, + "vnet::subnet": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/')))]" + }, + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "keyVaultPrivateEndpoint": { + "condition": "[not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp'))]", + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/'))]" + }, + "remoteNetAppAccount": { + "condition": "[and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName'))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8]]" + }, + "vnet": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", + "name": "[split(parameters('subnetResourceId'), '/')[8]]" + }, + "volume": { + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": "[shallowMerge(createArray(createObject('coolAccess', parameters('coolAccess'), 'coolAccessRetrievalPolicy', parameters('coolAccessRetrievalPolicy'), 'coolnessPeriod', parameters('coolnessPeriod'), 'encryptionKeySource', parameters('encryptionKeySource')), if(not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp')), createObject('keyVaultPrivateEndpointResourceId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2], split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]), 'Microsoft.Network/privateEndpoints', last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/')))), createObject()), if(not(empty(parameters('volumeType'))), createObject('volumeType', parameters('volumeType')), createObject()), createObject('dataProtection', if(not(empty(parameters('dataProtection'))), createObject('replication', if(not(empty(tryGet(parameters('dataProtection'), 'replication'))), createObject('endpointType', tryGet(parameters('dataProtection'), 'replication', 'endpointType'), 'remoteVolumeRegion', if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]), 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/'))), null()), 'remoteVolumeResourceId', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'replicationSchedule', tryGet(parameters('dataProtection'), 'replication', 'replicationSchedule'), 'remotePath', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remotePath')), createObject()), 'backup', if(not(empty(tryGet(parameters('dataProtection'), 'backup'))), createObject('backupPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName')), 'policyEnforced', coalesce(tryGet(parameters('dataProtection'), 'backup', 'policyEnforced'), false()), 'backupVaultId', resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))), createObject()), 'snapshot', if(not(empty(tryGet(parameters('dataProtection'), 'snapshot'))), createObject('snapshotPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))), createObject())), null()), 'networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('subnetResourceId'), '/')[2], split(parameters('subnetResourceId'), '/')[4]), 'Microsoft.Network/virtualNetworks/subnets', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/'))), 'exportPolicy', parameters('exportPolicy'), 'smbContinuouslyAvailable', parameters('smbContinuouslyAvailable'), 'smbEncryption', parameters('smbEncryption'), 'smbNonBrowsable', parameters('smbNonBrowsable'), 'kerberosEnabled', parameters('kerberosEnabled'))))]", + "zones": "[map(parameters('zones'), lambda('zone', format('{0}', lambdaVariables('zone'))))]" + }, + "volume_roleAssignments": { + "copy": { + "name": "volume_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}/capacityPools/{1}/volumes/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "volume" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Volume." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the Volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Volume was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('volume', '2024-07-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "capacityPool" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Capacity Pool." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Capacity Pool." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools', parameters('netAppAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Capacity Pool was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('capacityPool', '2024-07-01', 'full').location]" + }, + "volumeResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the volume created in the capacity pool." + }, + "copy": { + "count": "[length(coalesce(parameters('volumes'), createArray()))]", + "input": "[reference(format('capacityPool_volumes[{0}]', copyIndex())).outputs.resourceId.value]" + } + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/net-app/net-app-account/capacity-pool/volume/README.md b/avm/1.1.0/res/net-app/net-app-account/capacity-pool/volume/README.md new file mode 100644 index 000000000..26213e73b --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/capacity-pool/volume/README.md @@ -0,0 +1,696 @@ +# Azure NetApp Files Capacity Pool Volumes `[Microsoft.NetApp/netAppAccounts/capacityPools/volumes]` + +This module deploys an Azure NetApp Files Capacity Pool Volume. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.NetApp/netAppAccounts/capacityPools/volumes` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/capacityPools/volumes) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`coolAccess`](#parameter-coolaccess) | bool | If enabled (true) the pool can contain cool Access enabled volumes. | +| [`encryptionKeySource`](#parameter-encryptionkeysource) | string | The source of the encryption key. | +| [`name`](#parameter-name) | string | The name of the pool volume. | +| [`subnetResourceId`](#parameter-subnetresourceid) | string | The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes. | +| [`usageThreshold`](#parameter-usagethreshold) | int | Maximum storage quota allowed for a file system in bytes. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`capacityPoolName`](#parameter-capacitypoolname) | string | The name of the parent capacity pool. Required if the template is used in a standalone deployment. | +| [`netAppAccountName`](#parameter-netappaccountname) | string | The name of the parent NetApp account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`coolAccessRetrievalPolicy`](#parameter-coolaccessretrievalpolicy) | string | Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read). | +| [`coolnessPeriod`](#parameter-coolnessperiod) | int | Specifies the number of days after which data that is not accessed by clients will be tiered. | +| [`creationToken`](#parameter-creationtoken) | string | A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription. | +| [`dataProtection`](#parameter-dataprotection) | object | DataProtection type volumes include an object containing details of the replication. | +| [`exportPolicy`](#parameter-exportpolicy) | object | The export policy rules. | +| [`kerberosEnabled`](#parameter-kerberosenabled) | bool | Define if a volume is KerberosEnabled. | +| [`keyVaultPrivateEndpointResourceId`](#parameter-keyvaultprivateendpointresourceid) | string | The resource ID of the key vault private endpoint. | +| [`location`](#parameter-location) | string | Location of the pool volume. | +| [`networkFeatures`](#parameter-networkfeatures) | string | Network feature for the volume. | +| [`protocolTypes`](#parameter-protocoltypes) | array | Set of protocol types. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`serviceLevel`](#parameter-servicelevel) | string | The pool service level. Must match the one of the parent capacity pool. | +| [`smbContinuouslyAvailable`](#parameter-smbcontinuouslyavailable) | bool | Enables continuously available share property for SMB volume. Only applicable for SMB volume. | +| [`smbEncryption`](#parameter-smbencryption) | bool | Enables SMB encryption. Only applicable for SMB/DualProtocol volume. | +| [`smbNonBrowsable`](#parameter-smbnonbrowsable) | string | Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume. | +| [`volumeType`](#parameter-volumetype) | string | The type of the volume. DataProtection volumes are used for replication. | +| [`zones`](#parameter-zones) | array | Zone where the volume will be placed. | + +### Parameter: `coolAccess` + +If enabled (true) the pool can contain cool Access enabled volumes. + +- Required: Yes +- Type: bool + +### Parameter: `encryptionKeySource` + +The source of the encryption key. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the pool volume. + +- Required: Yes +- Type: string + +### Parameter: `subnetResourceId` + +The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes. + +- Required: Yes +- Type: string + +### Parameter: `usageThreshold` + +Maximum storage quota allowed for a file system in bytes. + +- Required: Yes +- Type: int + +### Parameter: `capacityPoolName` + +The name of the parent capacity pool. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `netAppAccountName` + +The name of the parent NetApp account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `coolAccessRetrievalPolicy` + +Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read). + +- Required: No +- Type: string + +### Parameter: `coolnessPeriod` + +Specifies the number of days after which data that is not accessed by clients will be tiered. + +- Required: No +- Type: int + +### Parameter: `creationToken` + +A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription. + +- Required: No +- Type: string +- Default: `[parameters('name')]` + +### Parameter: `dataProtection` + +DataProtection type volumes include an object containing details of the replication. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backup`](#parameter-dataprotectionbackup) | object | Backup properties. | +| [`replication`](#parameter-dataprotectionreplication) | object | Replication properties. | +| [`snapshot`](#parameter-dataprotectionsnapshot) | object | Snapshot properties. | + +### Parameter: `dataProtection.backup` + +Backup properties. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backupPolicyName`](#parameter-dataprotectionbackupbackuppolicyname) | string | The name of the backup policy to link. | +| [`backupVaultName`](#parameter-dataprotectionbackupbackupvaultname) | string | The name of the Backup Vault. | +| [`policyEnforced`](#parameter-dataprotectionbackuppolicyenforced) | bool | Enable to enforce the policy. | + +### Parameter: `dataProtection.backup.backupPolicyName` + +The name of the backup policy to link. + +- Required: Yes +- Type: string + +### Parameter: `dataProtection.backup.backupVaultName` + +The name of the Backup Vault. + +- Required: Yes +- Type: string + +### Parameter: `dataProtection.backup.policyEnforced` + +Enable to enforce the policy. + +- Required: Yes +- Type: bool + +### Parameter: `dataProtection.replication` + +Replication properties. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`endpointType`](#parameter-dataprotectionreplicationendpointtype) | string | Indicates whether the local volume is the source or destination for the Volume Replication. | +| [`replicationSchedule`](#parameter-dataprotectionreplicationreplicationschedule) | string | The replication schedule for the volume. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`remotePath`](#parameter-dataprotectionreplicationremotepath) | object | The full path to a volume that is to be migrated into ANF. Required for Migration volumes. | +| [`remoteVolumeRegion`](#parameter-dataprotectionreplicationremotevolumeregion) | string | The remote region for the other end of the Volume Replication.Required for Data Protection volumes. | +| [`remoteVolumeResourceId`](#parameter-dataprotectionreplicationremotevolumeresourceid) | string | The resource ID of the remote volume. Required for Data Protection volumes. | + +### Parameter: `dataProtection.replication.endpointType` + +Indicates whether the local volume is the source or destination for the Volume Replication. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'dst' + 'src' + ] + ``` + +### Parameter: `dataProtection.replication.replicationSchedule` + +The replication schedule for the volume. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + '_10minutely' + 'daily' + 'hourly' + ] + ``` + +### Parameter: `dataProtection.replication.remotePath` + +The full path to a volume that is to be migrated into ANF. Required for Migration volumes. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`externalHostName`](#parameter-dataprotectionreplicationremotepathexternalhostname) | string | The Path to a ONTAP Host. | +| [`serverName`](#parameter-dataprotectionreplicationremotepathservername) | string | The name of a server on the ONTAP Host. | +| [`volumeName`](#parameter-dataprotectionreplicationremotepathvolumename) | string | The name of a volume on the server. | + +### Parameter: `dataProtection.replication.remotePath.externalHostName` + +The Path to a ONTAP Host. + +- Required: Yes +- Type: string + +### Parameter: `dataProtection.replication.remotePath.serverName` + +The name of a server on the ONTAP Host. + +- Required: Yes +- Type: string + +### Parameter: `dataProtection.replication.remotePath.volumeName` + +The name of a volume on the server. + +- Required: Yes +- Type: string + +### Parameter: `dataProtection.replication.remoteVolumeRegion` + +The remote region for the other end of the Volume Replication.Required for Data Protection volumes. + +- Required: No +- Type: string + +### Parameter: `dataProtection.replication.remoteVolumeResourceId` + +The resource ID of the remote volume. Required for Data Protection volumes. + +- Required: No +- Type: string + +### Parameter: `dataProtection.snapshot` + +Snapshot properties. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`snapshotPolicyName`](#parameter-dataprotectionsnapshotsnapshotpolicyname) | string | The name of the snapshot policy to link. | + +### Parameter: `dataProtection.snapshot.snapshotPolicyName` + +The name of the snapshot policy to link. + +- Required: Yes +- Type: string + +### Parameter: `exportPolicy` + +The export policy rules. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`rules`](#parameter-exportpolicyrules) | array | The Export policy rules. | + +### Parameter: `exportPolicy.rules` + +The Export policy rules. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kerberos5iReadOnly`](#parameter-exportpolicyruleskerberos5ireadonly) | bool | Kerberos5i Read only access. | +| [`kerberos5iReadWrite`](#parameter-exportpolicyruleskerberos5ireadwrite) | bool | Kerberos5i Read and write access. | +| [`kerberos5pReadOnly`](#parameter-exportpolicyruleskerberos5preadonly) | bool | Kerberos5p Read only access. | +| [`kerberos5pReadWrite`](#parameter-exportpolicyruleskerberos5preadwrite) | bool | Kerberos5p Read and write access. | +| [`kerberos5ReadOnly`](#parameter-exportpolicyruleskerberos5readonly) | bool | Kerberos5 Read only access. | +| [`kerberos5ReadWrite`](#parameter-exportpolicyruleskerberos5readwrite) | bool | Kerberos5 Read and write access. | +| [`nfsv3`](#parameter-exportpolicyrulesnfsv3) | bool | Allows NFSv3 protocol. Enable only for NFSv3 type volumes. | +| [`nfsv41`](#parameter-exportpolicyrulesnfsv41) | bool | Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes. | +| [`ruleIndex`](#parameter-exportpolicyrulesruleindex) | int | Order index. | +| [`unixReadOnly`](#parameter-exportpolicyrulesunixreadonly) | bool | Read only access. | +| [`unixReadWrite`](#parameter-exportpolicyrulesunixreadwrite) | bool | Read and write access. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowedClients`](#parameter-exportpolicyrulesallowedclients) | string | Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names. | +| [`chownMode`](#parameter-exportpolicyruleschownmode) | string | This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own. | +| [`cifs`](#parameter-exportpolicyrulescifs) | bool | Allows CIFS protocol. | +| [`hasRootAccess`](#parameter-exportpolicyruleshasrootaccess) | bool | Has root access to volume. | + +### Parameter: `exportPolicy.rules.kerberos5iReadOnly` + +Kerberos5i Read only access. + +- Required: Yes +- Type: bool + +### Parameter: `exportPolicy.rules.kerberos5iReadWrite` + +Kerberos5i Read and write access. + +- Required: Yes +- Type: bool + +### Parameter: `exportPolicy.rules.kerberos5pReadOnly` + +Kerberos5p Read only access. + +- Required: Yes +- Type: bool + +### Parameter: `exportPolicy.rules.kerberos5pReadWrite` + +Kerberos5p Read and write access. + +- Required: Yes +- Type: bool + +### Parameter: `exportPolicy.rules.kerberos5ReadOnly` + +Kerberos5 Read only access. + +- Required: Yes +- Type: bool + +### Parameter: `exportPolicy.rules.kerberos5ReadWrite` + +Kerberos5 Read and write access. + +- Required: Yes +- Type: bool + +### Parameter: `exportPolicy.rules.nfsv3` + +Allows NFSv3 protocol. Enable only for NFSv3 type volumes. + +- Required: Yes +- Type: bool + +### Parameter: `exportPolicy.rules.nfsv41` + +Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes. + +- Required: Yes +- Type: bool + +### Parameter: `exportPolicy.rules.ruleIndex` + +Order index. + +- Required: Yes +- Type: int + +### Parameter: `exportPolicy.rules.unixReadOnly` + +Read only access. + +- Required: Yes +- Type: bool + +### Parameter: `exportPolicy.rules.unixReadWrite` + +Read and write access. + +- Required: Yes +- Type: bool + +### Parameter: `exportPolicy.rules.allowedClients` + +Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names. + +- Required: No +- Type: string + +### Parameter: `exportPolicy.rules.chownMode` + +This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Restricted' + 'Unrestricted' + ] + ``` + +### Parameter: `exportPolicy.rules.cifs` + +Allows CIFS protocol. + +- Required: No +- Type: bool + +### Parameter: `exportPolicy.rules.hasRootAccess` + +Has root access to volume. + +- Required: No +- Type: bool + +### Parameter: `kerberosEnabled` + +Define if a volume is KerberosEnabled. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `keyVaultPrivateEndpointResourceId` + +The resource ID of the key vault private endpoint. + +- Required: No +- Type: string + +### Parameter: `location` + +Location of the pool volume. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `networkFeatures` + +Network feature for the volume. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Basic_Standard' + 'Standard' + 'Standard_Basic' + ] + ``` + +### Parameter: `protocolTypes` + +Set of protocol types. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `serviceLevel` + +The pool service level. Must match the one of the parent capacity pool. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Premium' + 'Standard' + 'StandardZRS' + 'Ultra' + ] + ``` + +### Parameter: `smbContinuouslyAvailable` + +Enables continuously available share property for SMB volume. Only applicable for SMB volume. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `smbEncryption` + +Enables SMB encryption. Only applicable for SMB/DualProtocol volume. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `smbNonBrowsable` + +Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume. + +- Required: No +- Type: string +- Default: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `volumeType` + +The type of the volume. DataProtection volumes are used for replication. + +- Required: No +- Type: string + +### Parameter: `zones` + +Zone where the volume will be placed. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the Volume. | +| `resourceGroupName` | string | The name of the Resource Group the Volume was created in. | +| `resourceId` | string | The Resource ID of the Volume. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.4.0` | Remote reference | diff --git a/avm/1.1.0/res/net-app/net-app-account/capacity-pool/volume/main.bicep b/avm/1.1.0/res/net-app/net-app-account/capacity-pool/volume/main.bicep new file mode 100644 index 000000000..f61ed7b97 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/capacity-pool/volume/main.bicep @@ -0,0 +1,380 @@ +metadata name = 'Azure NetApp Files Capacity Pool Volumes' +metadata description = 'This module deploys an Azure NetApp Files Capacity Pool Volume.' + +@description('Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment.') +param netAppAccountName string + +@description('Conditional. The name of the parent capacity pool. Required if the template is used in a standalone deployment.') +param capacityPoolName string + +@description('Required. The name of the pool volume.') +param name string + +@description('Optional. Location of the pool volume.') +param location string = resourceGroup().location + +@description('Required. If enabled (true) the pool can contain cool Access enabled volumes.') +param coolAccess bool + +@description('Optional. Specifies the number of days after which data that is not accessed by clients will be tiered.') +param coolnessPeriod int? + +@description('Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read).') +param coolAccessRetrievalPolicy string? + +@description('Required. The source of the encryption key.') +param encryptionKeySource string + +@description('Optional. The resource ID of the key vault private endpoint.') +param keyVaultPrivateEndpointResourceId string? + +@description('Optional. The type of the volume. DataProtection volumes are used for replication.') +param volumeType string? + +@description('Optional. Zone where the volume will be placed.') +param zones int[] = [1, 2, 3] + +@description('Optional. The pool service level. Must match the one of the parent capacity pool.') +@allowed([ + 'Premium' + 'Standard' + 'StandardZRS' + 'Ultra' +]) +param serviceLevel string = 'Standard' + +@description('Optional. Network feature for the volume.') +@allowed([ + 'Basic' + 'Basic_Standard' + 'Standard' + 'Standard_Basic' +]) +param networkFeatures string = 'Standard' + +@description('Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription.') +param creationToken string = name + +@description('Required. Maximum storage quota allowed for a file system in bytes.') +param usageThreshold int + +@description('Optional. Set of protocol types.') +param protocolTypes array = [] + +@description('Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes.') +param subnetResourceId string + +@description('Optional. The export policy rules.') +param exportPolicy exportPolicyType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. DataProtection type volumes include an object containing details of the replication.') +param dataProtection dataProtectionType? + +@description('Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume.') +param smbEncryption bool = false + +@description('Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume.') +param smbContinuouslyAvailable bool = false + +@description('Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param smbNonBrowsable string = 'Disabled' + +@description('Optional. Define if a volume is KerberosEnabled.') +param kerberosEnabled bool = false + +var remoteCapacityPoolName = !empty(dataProtection.?replication.?remoteVolumeResourceId) + ? split((dataProtection.?replication.?remoteVolumeResourceId ?? '//'), '/')[10] + : '' +var remoteNetAppName = !empty(dataProtection.?replication.?remoteVolumeResourceId) + ? split((dataProtection.?replication.?remoteVolumeResourceId ?? '//'), '/')[8] + : '' + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource netAppAccount 'Microsoft.NetApp/netAppAccounts@2024-07-01' existing = { + name: netAppAccountName + + //cp-na-anfs-swc-y01 + resource capacityPool 'capacityPools@2024-07-01' existing = { + name: capacityPoolName + } + + resource backupVault 'backupVaults@2024-07-01' existing = if (!empty(dataProtection.?backup)) { + name: dataProtection.?backup!.backupVaultName + } + + resource backupPolicy 'backupPolicies@2024-07-01' existing = if (!empty(dataProtection.?backup)) { + name: dataProtection.?backup!.backupPolicyName + } + + resource snapshotPolicy 'snapshotPolicies@2024-07-01' existing = if (!empty(dataProtection.?snapshot)) { + name: dataProtection.?snapshot!.snapshotPolicyName + } +} + +resource keyVaultPrivateEndpoint 'Microsoft.Network/privateEndpoints@2024-03-01' existing = if (encryptionKeySource != 'Microsoft.NetApp') { + name: last(split(keyVaultPrivateEndpointResourceId ?? 'dummyVault', '/')) + scope: resourceGroup( + split((keyVaultPrivateEndpointResourceId ?? '//'), '/')[2], + split((keyVaultPrivateEndpointResourceId ?? '////'), '/')[4] + ) +} + +resource remoteNetAppAccount 'Microsoft.NetApp/netAppAccounts@2024-07-01' existing = if (!empty(dataProtection.?replication.?remoteVolumeResourceId) && (remoteNetAppName != netAppAccountName)) { + name: split((dataProtection.?replication.?remoteVolumeResourceId ?? '//'), '/')[8] + scope: resourceGroup( + split((dataProtection.?replication.?remoteVolumeResourceId ?? '//'), '/')[2], + split((dataProtection.?replication.?remoteVolumeResourceId ?? '////'), '/')[4] + ) + + //cp-na-anfs-swc-y01 + resource remoteCapacityPool 'capacityPools@2024-07-01' existing = if (!empty(dataProtection.?replication.?remoteVolumeResourceId) && (remoteCapacityPoolName != capacityPoolName)) { + name: split((dataProtection.?replication.?remoteVolumeResourceId ?? '//'), '/')[10] + + resource remoteVolume 'volumes@2024-07-01' existing = if (!empty(dataProtection.?replication)) { + name: last(split(dataProtection.?replication.?remoteVolumeResourceId ?? 'dummyvolume', '/')) + } + } +} + +resource vnet 'Microsoft.Network/virtualNetworks@2024-03-01' existing = { + name: split(subnetResourceId, '/')[8] + scope: resourceGroup(split(subnetResourceId, '/')[2], split(subnetResourceId, '/')[4]) + + resource subnet 'subnets@2024-03-01' existing = { + name: last(split(subnetResourceId, '/')) + } +} + +resource volume 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes@2024-07-01' = { + name: name + parent: netAppAccount::capacityPool + location: location + properties: { + coolAccess: coolAccess + coolAccessRetrievalPolicy: coolAccessRetrievalPolicy + coolnessPeriod: coolnessPeriod + encryptionKeySource: encryptionKeySource + ...(encryptionKeySource != 'Microsoft.NetApp' + ? { + keyVaultPrivateEndpointResourceId: keyVaultPrivateEndpoint.id + } + : {}) + ...(!empty(volumeType) + ? { + volumeType: volumeType + } + : {}) + dataProtection: !empty(dataProtection) + ? { + replication: !empty(dataProtection.?replication) + ? { + endpointType: dataProtection.?replication!.endpointType + remoteVolumeRegion: !empty(dataProtection.?replication.?remoteVolumeResourceId) + ? remoteNetAppAccount::remoteCapacityPool::remoteVolume.id + : null + remoteVolumeResourceId: dataProtection.?replication!.?remoteVolumeResourceId + replicationSchedule: dataProtection.?replication!.replicationSchedule + remotePath: dataProtection.?replication!.?remotePath + } + : {} + backup: !empty(dataProtection.?backup) + ? { + backupPolicyId: netAppAccount::backupPolicy.id + policyEnforced: dataProtection.?backup.policyEnforced ?? false + backupVaultId: netAppAccount::backupVault.id + } + : {} + snapshot: !empty(dataProtection.?snapshot) + ? { + snapshotPolicyId: netAppAccount::snapshotPolicy.id + } + : {} + } + : null + networkFeatures: networkFeatures + serviceLevel: serviceLevel + creationToken: creationToken + usageThreshold: usageThreshold + protocolTypes: protocolTypes + subnetId: vnet::subnet.id + exportPolicy: exportPolicy + smbContinuouslyAvailable: smbContinuouslyAvailable + smbEncryption: smbEncryption + smbNonBrowsable: smbNonBrowsable + kerberosEnabled: kerberosEnabled + } + zones: map(zones, zone => '${zone}') +} + +resource volume_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(volume.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: volume + } +] + +@description('The name of the Volume.') +output name string = volume.name + +@description('The Resource ID of the Volume.') +output resourceId string = volume.id + +@description('The name of the Resource Group the Volume was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = volume.location + +// ================ // +// Definitions // +// ================ // +@export() +@description('The type for the data protection properties.') +type dataProtectionType = { + @description('Optional. Replication properties.') + replication: replicationType? + + @description('Optional. Backup properties.') + backup: backupType? + + @description('Optional. Snapshot properties.') + snapshot: snapshotType? +} + +@description('The type for the replication properties.') +type replicationType = { + @description('Required. Indicates whether the local volume is the source or destination for the Volume Replication.') + endpointType: ('dst' | 'src') + + @description('Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes.') + remoteVolumeRegion: string? + + @description('Optional. The resource ID of the remote volume. Required for Data Protection volumes.') + remoteVolumeResourceId: string? + + @description('Required. The replication schedule for the volume.') + replicationSchedule: ('_10minutely' | 'daily' | 'hourly') + + @description('Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes.') + remotePath: { + @description('Required. The Path to a ONTAP Host.') + externalHostName: string + + @description('Required. The name of a server on the ONTAP Host.') + serverName: string + + @description('Required. The name of a volume on the server.') + volumeName: string + }? +} + +@description('The type for the backup properties.') +type backupType = { + @description('Required. The name of the backup policy to link.') + backupPolicyName: string + + @description('Required. Enable to enforce the policy.') + policyEnforced: bool + + @description('Required. The name of the Backup Vault.') + backupVaultName: string +} + +@description('The type for the snapshot properties.') +type snapshotType = { + @description('Required. The name of the snapshot policy to link.') + snapshotPolicyName: string +} + +@export() +@description('The type for export policy rules.') +type exportPolicyType = { + @description('Required. The Export policy rules.') + rules: { + @description('Required. Order index.') + ruleIndex: int + + @description('Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names.') + allowedClients: string? + + @description('Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own.') + chownMode: ('Restricted' | 'Unrestricted')? + + @description('Optional. Allows CIFS protocol.') + cifs: bool? + + @description('Optional. Has root access to volume.') + hasRootAccess: bool? + + @description('Required. Kerberos5 Read only access.') + kerberos5ReadOnly: bool + + @description('Required. Kerberos5 Read and write access.') + kerberos5ReadWrite: bool + + @description('Required. Kerberos5i Read only access.') + kerberos5iReadOnly: bool + + @description('Required. Kerberos5i Read and write access.') + kerberos5iReadWrite: bool + + @description('Required. Kerberos5p Read only access.') + kerberos5pReadOnly: bool + + @description('Required. Kerberos5p Read and write access.') + kerberos5pReadWrite: bool + + @description('Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes.') + nfsv3: bool + + @description('Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes.') + nfsv41: bool + + @description('Required. Read only access.') + unixReadOnly: bool + + @description('Required. Read and write access.') + unixReadWrite: bool + }[] +} diff --git a/avm/1.1.0/res/net-app/net-app-account/capacity-pool/volume/main.json b/avm/1.1.0/res/net-app/net-app-account/capacity-pool/volume/main.json new file mode 100644 index 000000000..677c51848 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/capacity-pool/volume/main.json @@ -0,0 +1,703 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "13717060947862126529" + }, + "name": "Azure NetApp Files Capacity Pool Volumes", + "description": "This module deploys an Azure NetApp Files Capacity Pool Volume." + }, + "definitions": { + "dataProtectionType": { + "type": "object", + "properties": { + "replication": { + "$ref": "#/definitions/replicationType", + "nullable": true, + "metadata": { + "description": "Optional. Replication properties." + } + }, + "backup": { + "$ref": "#/definitions/backupType", + "nullable": true, + "metadata": { + "description": "Optional. Backup properties." + } + }, + "snapshot": { + "$ref": "#/definitions/snapshotType", + "nullable": true, + "metadata": { + "description": "Optional. Snapshot properties." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data protection properties." + } + }, + "replicationType": { + "type": "object", + "properties": { + "endpointType": { + "type": "string", + "allowedValues": [ + "dst", + "src" + ], + "metadata": { + "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." + } + }, + "remoteVolumeRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." + } + }, + "remoteVolumeResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." + } + }, + "replicationSchedule": { + "type": "string", + "allowedValues": [ + "_10minutely", + "daily", + "hourly" + ], + "metadata": { + "description": "Required. The replication schedule for the volume." + } + }, + "remotePath": { + "type": "object", + "properties": { + "externalHostName": { + "type": "string", + "metadata": { + "description": "Required. The Path to a ONTAP Host." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Required. The name of a server on the ONTAP Host." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of a volume on the server." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." + } + } + }, + "metadata": { + "description": "The type for the replication properties." + } + }, + "backupType": { + "type": "object", + "properties": { + "backupPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the backup policy to link." + } + }, + "policyEnforced": { + "type": "bool", + "metadata": { + "description": "Required. Enable to enforce the policy." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Backup Vault." + } + } + }, + "metadata": { + "description": "The type for the backup properties." + } + }, + "snapshotType": { + "type": "object", + "properties": { + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy to link." + } + } + }, + "metadata": { + "description": "The type for the snapshot properties." + } + }, + "exportPolicyType": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleIndex": { + "type": "int", + "metadata": { + "description": "Required. Order index." + } + }, + "allowedClients": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." + } + }, + "chownMode": { + "type": "string", + "allowedValues": [ + "Restricted", + "Unrestricted" + ], + "nullable": true, + "metadata": { + "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." + } + }, + "cifs": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allows CIFS protocol." + } + }, + "hasRootAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Has root access to volume." + } + }, + "kerberos5ReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read only access." + } + }, + "kerberos5ReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read and write access." + } + }, + "kerberos5iReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read only access." + } + }, + "kerberos5iReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read and write access." + } + }, + "kerberos5pReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read only access." + } + }, + "kerberos5pReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read and write access." + } + }, + "nfsv3": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." + } + }, + "nfsv41": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." + } + }, + "unixReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Read only access." + } + }, + "unixReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Read and write access." + } + } + } + }, + "metadata": { + "description": "Required. The Export policy rules." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for export policy rules." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + } + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent capacity pool. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the pool volume." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "coolAccess": { + "type": "bool", + "metadata": { + "description": "Required. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "coolnessPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." + } + }, + "coolAccessRetrievalPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." + } + }, + "encryptionKeySource": { + "type": "string", + "metadata": { + "description": "Required. The source of the encryption key." + } + }, + "keyVaultPrivateEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the key vault private endpoint." + } + }, + "volumeType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of the volume. DataProtection volumes are used for replication." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. Zone where the volume will be placed." + } + }, + "serviceLevel": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "metadata": { + "description": "Optional. The pool service level. Must match the one of the parent capacity pool." + } + }, + "networkFeatures": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Basic_Standard", + "Standard", + "Standard_Basic" + ], + "metadata": { + "description": "Optional. Network feature for the volume." + } + }, + "creationToken": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." + } + }, + "usageThreshold": { + "type": "int", + "metadata": { + "description": "Required. Maximum storage quota allowed for a file system in bytes." + } + }, + "protocolTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Set of protocol types." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." + } + }, + "exportPolicy": { + "$ref": "#/definitions/exportPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. The export policy rules." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "dataProtection": { + "$ref": "#/definitions/dataProtectionType", + "nullable": true, + "metadata": { + "description": "Optional. DataProtection type volumes include an object containing details of the replication." + } + }, + "smbEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." + } + }, + "smbContinuouslyAvailable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." + } + }, + "smbNonBrowsable": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." + } + }, + "kerberosEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Define if a volume is KerberosEnabled." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "remoteCapacityPoolName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], '')]", + "remoteNetAppName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], '')]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "netAppAccount::capacityPool": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" + }, + "netAppAccount::backupVault": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))]" + }, + "netAppAccount::backupPolicy": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName'))]" + }, + "netAppAccount::snapshotPolicy": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'snapshot')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))]" + }, + "remoteNetAppAccount::remoteCapacityPool::remoteVolume": { + "condition": "[and(and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName'))))), not(empty(tryGet(parameters('dataProtection'), 'replication'))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}/{2}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/')))]" + }, + "remoteNetAppAccount::remoteCapacityPool": { + "condition": "[and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName')))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10])]" + }, + "vnet::subnet": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/')))]" + }, + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "keyVaultPrivateEndpoint": { + "condition": "[not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp'))]", + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/'))]" + }, + "remoteNetAppAccount": { + "condition": "[and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName'))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8]]" + }, + "vnet": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", + "name": "[split(parameters('subnetResourceId'), '/')[8]]" + }, + "volume": { + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": "[shallowMerge(createArray(createObject('coolAccess', parameters('coolAccess'), 'coolAccessRetrievalPolicy', parameters('coolAccessRetrievalPolicy'), 'coolnessPeriod', parameters('coolnessPeriod'), 'encryptionKeySource', parameters('encryptionKeySource')), if(not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp')), createObject('keyVaultPrivateEndpointResourceId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2], split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]), 'Microsoft.Network/privateEndpoints', last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/')))), createObject()), if(not(empty(parameters('volumeType'))), createObject('volumeType', parameters('volumeType')), createObject()), createObject('dataProtection', if(not(empty(parameters('dataProtection'))), createObject('replication', if(not(empty(tryGet(parameters('dataProtection'), 'replication'))), createObject('endpointType', tryGet(parameters('dataProtection'), 'replication', 'endpointType'), 'remoteVolumeRegion', if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]), 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/'))), null()), 'remoteVolumeResourceId', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'replicationSchedule', tryGet(parameters('dataProtection'), 'replication', 'replicationSchedule'), 'remotePath', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remotePath')), createObject()), 'backup', if(not(empty(tryGet(parameters('dataProtection'), 'backup'))), createObject('backupPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName')), 'policyEnforced', coalesce(tryGet(parameters('dataProtection'), 'backup', 'policyEnforced'), false()), 'backupVaultId', resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))), createObject()), 'snapshot', if(not(empty(tryGet(parameters('dataProtection'), 'snapshot'))), createObject('snapshotPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))), createObject())), null()), 'networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('subnetResourceId'), '/')[2], split(parameters('subnetResourceId'), '/')[4]), 'Microsoft.Network/virtualNetworks/subnets', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/'))), 'exportPolicy', parameters('exportPolicy'), 'smbContinuouslyAvailable', parameters('smbContinuouslyAvailable'), 'smbEncryption', parameters('smbEncryption'), 'smbNonBrowsable', parameters('smbNonBrowsable'), 'kerberosEnabled', parameters('kerberosEnabled'))))]", + "zones": "[map(parameters('zones'), lambda('zone', format('{0}', lambdaVariables('zone'))))]" + }, + "volume_roleAssignments": { + "copy": { + "name": "volume_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}/capacityPools/{1}/volumes/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "volume" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Volume." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the Volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Volume was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('volume', '2024-07-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/net-app/net-app-account/main.bicep b/avm/1.1.0/res/net-app/net-app-account/main.bicep new file mode 100644 index 000000000..0830edb90 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/main.bicep @@ -0,0 +1,429 @@ +metadata name = 'Azure NetApp Files' +metadata description = 'This module deploys an Azure NetApp File.' + +@description('Required. The name of the NetApp account.') +param name string + +@description('Optional. Name of the active directory host as part of Kerberos Realm used for Kerberos authentication.') +param adName string = '' + +@description('Optional. Enable AES encryption on the SMB Server.') +param aesEncryption bool = false + +import { customerManagedKeyType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' +@description('Optional. The customer managed key definition.') +param customerManagedKey customerManagedKeyType? + +@description('Optional. Fully Qualified Active Directory DNS Domain Name (e.g. \'contoso.com\').') +param domainName string = '' + +@description('Optional. Required if domainName is specified. Username of Active Directory domain administrator, with permissions to create SMB server machine account in the AD domain.') +param domainJoinUser string = '' + +@description('Optional. Required if domainName is specified. Password of the user specified in domainJoinUser parameter.') +@secure() +param domainJoinPassword string = '' + +@description('Optional. Used only if domainName is specified. LDAP Path for the Organization Unit (OU) where SMB Server machine accounts will be created (i.e. \'OU=SecondLevel,OU=FirstLevel\').') +param domainJoinOU string = '' + +@description('Optional. Required if domainName is specified. Comma separated list of DNS server IP addresses (IPv4 only) required for the Active Directory (AD) domain join and SMB authentication operations to succeed.') +param dnsServers string = '' + +@description('Optional. Specifies whether encryption should be used for communication between SMB server and domain controller (DC). SMB3 only.') +param encryptDCConnections bool = false + +@description('Optional. Required if domainName is specified. NetBIOS name of the SMB server. A computer account with this prefix will be registered in the AD and used to mount volumes.') +param smbServerNamePrefix string = '' + +@description('Optional. Capacity pools to create.') +param capacityPools capacityPoolType[]? + +import { managedIdentityOnlyUserAssignedType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentityOnlyUserAssignedType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Kerberos Key Distribution Center (KDC) as part of Kerberos Realm used for Kerberos authentication.') +param kdcIP string = '' + +@description('Optional. Specifies whether to use TLS when NFS (with/without Kerberos) and SMB volumes communicate with an LDAP server. A server root CA certificate must be uploaded if enabled (serverRootCACertificate).') +param ldapOverTLS bool = false + +@description('Optional. Specifies whether or not the LDAP traffic needs to be signed.') +param ldapSigning bool = false + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' +@description('Optional. The lock settings of the service.') +param lock lockType? + +@description('Optional. A server Root certificate is required of ldapOverTLS is enabled.') +param serverRootCACertificate string = '' + +@description('Optional. Tags for all resources.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. The netapp backup vault to create & configure.') +param backupVault backupVaultType? + +@description('Optional. The snapshot policies to create.') +param snapshotPolicies snapshotPolicyType[]? + +@description('Optional. The backup policies to create.') +param backupPolicies backupPolicyType[]? + +var activeDirectoryConnectionProperties = [ + { + adName: !empty(domainName) ? adName : null + aesEncryption: !empty(domainName) ? aesEncryption : false + username: !empty(domainName) ? domainJoinUser : null + password: !empty(domainName) ? domainJoinPassword : null + domain: !empty(domainName) ? domainName : null + dns: !empty(domainName) ? dnsServers : null + encryptDCConnections: !empty(domainName) ? encryptDCConnections : false + kdcIP: !empty(domainName) ? kdcIP : null + ldapOverTLS: !empty(domainName) ? ldapOverTLS : false + ldapSigning: !empty(domainName) ? ldapSigning : false + serverRootCACertificate: !empty(domainName) ? serverRootCACertificate : null + smbServerName: !empty(domainName) ? smbServerNamePrefix : null + organizationalUnit: !empty(domainJoinOU) ? domainJoinOU : null + } +] + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: !empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None' + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.res.netapp-netappaccount.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource cMKKeyVault 'Microsoft.KeyVault/vaults@2023-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId)) { + name: last(split((customerManagedKey.?keyVaultResourceId ?? 'dummyVault'), '/')) + scope: resourceGroup( + split((customerManagedKey.?keyVaultResourceId ?? '//'), '/')[2], + split((customerManagedKey.?keyVaultResourceId ?? '////'), '/')[4] + ) + + resource cMKKey 'keys@2023-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { + name: customerManagedKey.?keyName ?? 'dummyKey' + } +} + +resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = if (!empty(customerManagedKey.?userAssignedIdentityResourceId)) { + name: last(split(customerManagedKey.?userAssignedIdentityResourceId ?? 'dummyMsi', '/')) + scope: resourceGroup( + split((customerManagedKey.?userAssignedIdentityResourceId ?? '//'), '/')[2], + split((customerManagedKey.?userAssignedIdentityResourceId ?? '////'), '/')[4] + ) +} + +resource netAppAccount 'Microsoft.NetApp/netAppAccounts@2024-07-01' = { + name: name + tags: tags + identity: identity + location: location + properties: { + activeDirectories: !empty(domainName) ? activeDirectoryConnectionProperties : null + encryption: !empty(customerManagedKey) + ? { + identity: !empty(customerManagedKey.?userAssignedIdentityResourceId) + ? { + userAssignedIdentity: cMKUserAssignedIdentity.id + } + : null + keySource: 'Microsoft.KeyVault' + keyVaultProperties: { + keyName: customerManagedKey!.keyName + keyVaultResourceId: cMKKeyVault.id + keyVaultUri: cMKKeyVault.properties.vaultUri + } + } + : null + } +} + +resource netAppAccount_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: netAppAccount +} + +resource netAppAccount_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(netAppAccount.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: netAppAccount + } +] + +module netAppAccount_backupPolicies 'backup-policies/main.bicep' = [ + for (backupPolicy, index) in (backupPolicies ?? []): { + name: '${uniqueString(deployment().name, location)}-ANFAccount-backupPolicy-${index}' + params: { + netAppAccountName: netAppAccount.name + name: backupPolicy.?name + dailyBackupsToKeep: backupPolicy.?dailyBackupsToKeep + monthlyBackupsToKeep: backupPolicy.?monthlyBackupsToKeep + weeklyBackupsToKeep: backupPolicy.?weeklyBackupsToKeep + enabled: backupPolicy.?enabled + location: backupPolicy.?location ?? location + } + } +] + +module netAppAccount_snapshotPolicies 'snapshot-policies/main.bicep' = [ + for (snapshotPolicy, index) in (snapshotPolicies ?? []): { + name: '${uniqueString(deployment().name, location)}-ANFAccount-snapshotPolicy-${index}' + params: { + netAppAccountName: netAppAccount.name + name: snapshotPolicy.?name + location: snapshotPolicy.?location ?? location + snapEnabled: snapshotPolicy.?snapEnabled + dailySchedule: snapshotPolicy.?dailySchedule + hourlySchedule: snapshotPolicy.?hourlySchedule + monthlySchedule: snapshotPolicy.?monthlySchedule + weeklySchedule: snapshotPolicy.?weeklySchedule + } + } +] + +module netAppAccount_backupVault 'backup-vault/main.bicep' = if (!empty(backupVault)) { + name: '${uniqueString(deployment().name, location)}-ANFAccount-BackupVault' + params: { + netAppAccountName: netAppAccount.name + name: backupVault.?name + location: backupVault.?location ?? location + } +} + +module netAppAccount_capacityPools 'capacity-pool/main.bicep' = [ + for (capacityPool, index) in (capacityPools ?? []): { + name: '${uniqueString(deployment().name, location)}-ANFAccount-CapPool-${index}' + params: { + netAppAccountName: netAppAccount.name + name: capacityPool.name + size: capacityPool.size + location: capacityPool.?location ?? location + serviceLevel: capacityPool.?serviceLevel ?? 'Standard' + qosType: capacityPool.?qosType ?? 'Auto' + volumes: capacityPool.?volumes ?? [] + coolAccess: capacityPool.?coolAccess ?? false + roleAssignments: capacityPool.?roleAssignments ?? [] + encryptionType: capacityPool.?encryptionType ?? 'Single' + tags: capacityPool.?tags ?? tags + } + dependsOn: [ + netAppAccount_backupPolicies + netAppAccount_snapshotPolicies + netAppAccount_backupVault + ] + } +] + +module netAppAccount_backupVaultBackups 'backup-vault/main.bicep' = if (!empty(backupVault.?backups)) { + name: '${uniqueString(deployment().name, location)}-ANFAccount-BackupVault-Backups' + params: { + netAppAccountName: netAppAccount.name + name: backupVault.?name + backups: backupVault.?backups + location: backupVault.?location ?? location + } + dependsOn: [ + netAppAccount_capacityPools + ] +} + +@description('The name of the NetApp account.') +output name string = netAppAccount.name + +@description('The Resource ID of the NetApp account.') +output resourceId string = netAppAccount.id + +@description('The name of the Resource Group the NetApp account was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = netAppAccount.location + +@description('The resource IDs of the created capacity pools & their volumes.') +output capacityPoolResourceIds { + resourceId: string + volumeResourceIds: string[] +}[] = [ + for (capacityPools, index) in (capacityPools ?? []): { + resourceId: netAppAccount_capacityPools[index].outputs.resourceId + volumeResourceIds: netAppAccount_capacityPools[index].outputs.volumeResourceIds + } +] + +// ================ // +// Definitions // +// ================ // + +import { backupType } from 'backup-vault/main.bicep' +@export() +@description('The type for a backup vault.') +type backupVaultType = { + @description('Optional. The name of the backup vault.') + name: string? + + @description('Optional. The list of backups to create.') + backups: backupType[]? + + @description('Optional. Location of the backup vault.') + location: string? +} + +import { volumeType } from 'capacity-pool/main.bicep' +@export() +@description('The type for a capacity pool.') +type capacityPoolType = { + @description('Required. The name of the capacity pool.') + name: string + + @description('Optional. Location of the pool volume.') + location: string? + + @description('Optional. Tags for the capcity pool.') + tags: object? + + @description('Optional. The pool service level.') + serviceLevel: ('Premium' | 'Standard' | 'StandardZRS' | 'Ultra')? + + @description('Required. Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104).') + size: int + + @description('Optional. The qos type of the pool.') + qosType: ('Auto' | 'Manual')? + + @description('Optional. List of volumes to create in the capacity pool.') + volumes: volumeType[]? + + @description('Optional. If enabled (true) the pool can contain cool Access enabled volumes.') + coolAccess: bool? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType[]? + + @description('Optional. Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool.') + encryptionType: ('Single' | 'Double')? +} + +import { dailyScheduleType, hourlyScheduleType, monthlyScheduleType, weeklyScheduleType } from 'snapshot-policies/main.bicep' +@export() +@description('The type for a snapshot policy.') +type snapshotPolicyType = { + @description('Required. The name of the snapshot policy.') + name: string + + @description('Optional. Location of the snapshot policy.') + location: string? + + @description('Optional. Daily schedule for the snapshot policy.') + dailySchedule: dailyScheduleType? + + @description('Optional. Hourly schedule for the snapshot policy.') + hourlySchedule: hourlyScheduleType? + + @description('Optional. Monthly schedule for the snapshot policy.') + monthlySchedule: monthlyScheduleType? + + @description('Optional. Weekly schedule for the snapshot policy.') + weeklySchedule: weeklyScheduleType? +} + +@export() +@description('The type for a backup policy.') +type backupPolicyType = { + @description('Optional. The name of the backup policy.') + name: string? + + @description('Optional. The location of the backup policy.') + location: string? + + @description('Optional. The daily backups to keep.') + @minValue(2) + @maxValue(1019) + dailyBackupsToKeep: int? + + @description('Optional. The monthly backups to keep.') + monthlyBackupsToKeep: int? + + @description('Optional. The weekly backups to keep.') + weeklyBackupsToKeep: int? + + @description('Optional. Indicates whether the backup policy is enabled.') + enabled: bool? +} diff --git a/avm/1.1.0/res/net-app/net-app-account/main.json b/avm/1.1.0/res/net-app/net-app-account/main.json new file mode 100644 index 000000000..68b9f712e --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/main.json @@ -0,0 +1,4199 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "3612442392718175721" + }, + "name": "Azure NetApp Files", + "description": "This module deploys an Azure NetApp File." + }, + "definitions": { + "backupVaultType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "backups": { + "type": "array", + "items": { + "$ref": "#/definitions/backupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of backups to create." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the backup vault." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backup vault." + } + }, + "capacityPoolType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for the capcity pool." + } + }, + "serviceLevel": { + "type": "string", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "nullable": true, + "metadata": { + "description": "Optional. The pool service level." + } + }, + "size": { + "type": "int", + "metadata": { + "description": "Required. Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104)." + } + }, + "qosType": { + "type": "string", + "allowedValues": [ + "Auto", + "Manual" + ], + "nullable": true, + "metadata": { + "description": "Optional. The qos type of the pool." + } + }, + "volumes": { + "type": "array", + "items": { + "$ref": "#/definitions/volumeType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of volumes to create in the capacity pool." + } + }, + "coolAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "encryptionType": { + "type": "string", + "allowedValues": [ + "Double", + "Single" + ], + "nullable": true, + "metadata": { + "description": "Optional. Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a capacity pool." + } + }, + "snapshotPolicyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the snapshot policy." + } + }, + "dailySchedule": { + "$ref": "#/definitions/dailyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Daily schedule for the snapshot policy." + } + }, + "hourlySchedule": { + "$ref": "#/definitions/hourlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Hourly schedule for the snapshot policy." + } + }, + "monthlySchedule": { + "$ref": "#/definitions/monthlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Monthly schedule for the snapshot policy." + } + }, + "weeklySchedule": { + "$ref": "#/definitions/weeklyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Weekly schedule for the snapshot policy." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a snapshot policy." + } + }, + "backupPolicyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup policy." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location of the backup policy." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "nullable": true, + "minValue": 2, + "maxValue": 1019, + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backup policy." + } + }, + "_1.backupType": { + "type": "object", + "properties": { + "backupPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the backup policy to link." + } + }, + "policyEnforced": { + "type": "bool", + "metadata": { + "description": "Required. Enable to enforce the policy." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Backup Vault." + } + } + }, + "metadata": { + "description": "The type for the backup properties.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } + } + }, + "_1.dataProtectionType": { + "type": "object", + "properties": { + "replication": { + "$ref": "#/definitions/_1.replicationType", + "nullable": true, + "metadata": { + "description": "Optional. Replication properties." + } + }, + "backup": { + "$ref": "#/definitions/_1.backupType", + "nullable": true, + "metadata": { + "description": "Optional. Backup properties." + } + }, + "snapshot": { + "$ref": "#/definitions/_1.snapshotType", + "nullable": true, + "metadata": { + "description": "Optional. Snapshot properties." + } + } + }, + "metadata": { + "description": "The type for the data protection properties.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } + } + }, + "_1.exportPolicyType": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleIndex": { + "type": "int", + "metadata": { + "description": "Required. Order index." + } + }, + "allowedClients": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." + } + }, + "chownMode": { + "type": "string", + "allowedValues": [ + "Restricted", + "Unrestricted" + ], + "nullable": true, + "metadata": { + "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." + } + }, + "cifs": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allows CIFS protocol." + } + }, + "hasRootAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Has root access to volume." + } + }, + "kerberos5ReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read only access." + } + }, + "kerberos5ReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read and write access." + } + }, + "kerberos5iReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read only access." + } + }, + "kerberos5iReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read and write access." + } + }, + "kerberos5pReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read only access." + } + }, + "kerberos5pReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read and write access." + } + }, + "nfsv3": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." + } + }, + "nfsv41": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." + } + }, + "unixReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Read only access." + } + }, + "unixReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Read and write access." + } + } + } + }, + "metadata": { + "description": "Required. The Export policy rules." + } + } + }, + "metadata": { + "description": "The type for export policy rules.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } + } + }, + "_1.replicationType": { + "type": "object", + "properties": { + "endpointType": { + "type": "string", + "allowedValues": [ + "dst", + "src" + ], + "metadata": { + "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." + } + }, + "remoteVolumeRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." + } + }, + "remoteVolumeResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." + } + }, + "replicationSchedule": { + "type": "string", + "allowedValues": [ + "_10minutely", + "daily", + "hourly" + ], + "metadata": { + "description": "Required. The replication schedule for the volume." + } + }, + "remotePath": { + "type": "object", + "properties": { + "externalHostName": { + "type": "string", + "metadata": { + "description": "Required. The Path to a ONTAP Host." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Required. The name of a server on the ONTAP Host." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of a volume on the server." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." + } + } + }, + "metadata": { + "description": "The type for the replication properties.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } + } + }, + "_1.snapshotType": { + "type": "object", + "properties": { + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy to link." + } + } + }, + "metadata": { + "description": "The type for the snapshot properties.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } + } + }, + "backupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "metadata": { + "description": "The type for a backup.", + "__bicep_imported_from!": { + "sourceTemplate": "backup-vault/main.bicep" + } + } + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "dailyScheduleType": { + "type": "object", + "properties": { + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The daily snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The daily snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Daily snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "description": "The type for a daily schedule for the snapshot policy.", + "__bicep_imported_from!": { + "sourceTemplate": "snapshot-policies/main.bicep" + } + } + }, + "hourlyScheduleType": { + "type": "object", + "properties": { + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The hourly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Hourly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "description": "The type for an hourly schedule for the snapshot policy.", + "__bicep_imported_from!": { + "sourceTemplate": "snapshot-policies/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "managedIdentityOnlyUserAssignedType": { + "type": "object", + "properties": { + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "monthlyScheduleType": { + "type": "object", + "properties": { + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Required. Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The monthly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The monthly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Monthly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "description": "The type for a monthly schedule for the snapshot policy.", + "__bicep_imported_from!": { + "sourceTemplate": "snapshot-policies/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "volumeType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the pool volume." + } + }, + "coolAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "coolnessPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." + } + }, + "coolAccessRetrievalPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." + } + }, + "encryptionKeySource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source of the encryption key." + } + }, + "keyVaultPrivateEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the key vault private endpoint." + } + }, + "dataProtection": { + "$ref": "#/definitions/_1.dataProtectionType", + "nullable": true, + "metadata": { + "description": "Optional. DataProtection type volumes include an object containing details of the replication." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. Zone where the volume will be placed." + } + }, + "serviceLevel": { + "type": "string", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "nullable": true, + "metadata": { + "description": "Optional. The pool service level. Must match the one of the parent capacity pool." + } + }, + "networkFeatures": { + "type": "string", + "allowedValues": [ + "Basic", + "Basic_Standard", + "Standard", + "Standard_Basic" + ], + "nullable": true, + "metadata": { + "description": "Optional. Network feature for the volume." + } + }, + "creationToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." + } + }, + "usageThreshold": { + "type": "int", + "metadata": { + "description": "Required. Maximum storage quota allowed for a file system in bytes." + } + }, + "protocolTypes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Set of protocol types." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." + } + }, + "exportPolicy": { + "$ref": "#/definitions/_1.exportPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Export policy rules." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "smbEncryption": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." + } + }, + "smbContinuouslyAvailable": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." + } + }, + "smbNonBrowsable": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." + } + }, + "kerberosEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Define if a volume is KerberosEnabled." + } + }, + "volumeType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of the volume. DataProtection volumes are used for replication." + } + } + }, + "metadata": { + "description": "The type for a volume in the capacity pool.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/main.bicep" + } + } + }, + "weeklyScheduleType": { + "type": "object", + "properties": { + "day": { + "type": "string", + "allowedValues": [ + "Friday", + "Monday", + "Saturday", + "Sunday", + "Thursday", + "Tuesday", + "Wednesday" + ], + "metadata": { + "description": "Required. The weekly snapshot day." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The weekly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The weekly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Weekly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "description": "The type for a weekly schedule for the snapshot policy.", + "__bicep_imported_from!": { + "sourceTemplate": "snapshot-policies/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NetApp account." + } + }, + "adName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the active directory host as part of Kerberos Realm used for Kerberos authentication." + } + }, + "aesEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable AES encryption on the SMB Server." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "domainName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Fully Qualified Active Directory DNS Domain Name (e.g. 'contoso.com')." + } + }, + "domainJoinUser": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if domainName is specified. Username of Active Directory domain administrator, with permissions to create SMB server machine account in the AD domain." + } + }, + "domainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if domainName is specified. Password of the user specified in domainJoinUser parameter." + } + }, + "domainJoinOU": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Used only if domainName is specified. LDAP Path for the Organization Unit (OU) where SMB Server machine accounts will be created (i.e. 'OU=SecondLevel,OU=FirstLevel')." + } + }, + "dnsServers": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if domainName is specified. Comma separated list of DNS server IP addresses (IPv4 only) required for the Active Directory (AD) domain join and SMB authentication operations to succeed." + } + }, + "encryptDCConnections": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether encryption should be used for communication between SMB server and domain controller (DC). SMB3 only." + } + }, + "smbServerNamePrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if domainName is specified. NetBIOS name of the SMB server. A computer account with this prefix will be registered in the AD and used to mount volumes." + } + }, + "capacityPools": { + "type": "array", + "items": { + "$ref": "#/definitions/capacityPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Capacity pools to create." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlyUserAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "kdcIP": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Kerberos Key Distribution Center (KDC) as part of Kerberos Realm used for Kerberos authentication." + } + }, + "ldapOverTLS": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether to use TLS when NFS (with/without Kerberos) and SMB volumes communicate with an LDAP server. A server root CA certificate must be uploaded if enabled (serverRootCACertificate)." + } + }, + "ldapSigning": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether or not the LDAP traffic needs to be signed." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "serverRootCACertificate": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. A server Root certificate is required of ldapOverTLS is enabled." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "backupVault": { + "$ref": "#/definitions/backupVaultType", + "nullable": true, + "metadata": { + "description": "Optional. The netapp backup vault to create & configure." + } + }, + "snapshotPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/snapshotPolicyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The snapshot policies to create." + } + }, + "backupPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/backupPolicyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The backup policies to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "activeDirectoryConnectionProperties": [ + { + "adName": "[if(not(empty(parameters('domainName'))), parameters('adName'), null())]", + "aesEncryption": "[if(not(empty(parameters('domainName'))), parameters('aesEncryption'), false())]", + "username": "[if(not(empty(parameters('domainName'))), parameters('domainJoinUser'), null())]", + "password": "[if(not(empty(parameters('domainName'))), parameters('domainJoinPassword'), null())]", + "domain": "[if(not(empty(parameters('domainName'))), parameters('domainName'), null())]", + "dns": "[if(not(empty(parameters('domainName'))), parameters('dnsServers'), null())]", + "encryptDCConnections": "[if(not(empty(parameters('domainName'))), parameters('encryptDCConnections'), false())]", + "kdcIP": "[if(not(empty(parameters('domainName'))), parameters('kdcIP'), null())]", + "ldapOverTLS": "[if(not(empty(parameters('domainName'))), parameters('ldapOverTLS'), false())]", + "ldapSigning": "[if(not(empty(parameters('domainName'))), parameters('ldapSigning'), false())]", + "serverRootCACertificate": "[if(not(empty(parameters('domainName'))), parameters('serverRootCACertificate'), null())]", + "smbServerName": "[if(not(empty(parameters('domainName'))), parameters('smbServerNamePrefix'), null())]", + "organizationalUnit": "[if(not(empty(parameters('domainJoinOU'))), parameters('domainJoinOU'), null())]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None'), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.netapp-netappaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "netAppAccount": { + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "location": "[parameters('location')]", + "properties": { + "activeDirectories": "[if(not(empty(parameters('domainName'))), variables('activeDirectoryConnectionProperties'), null())]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('identity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), createObject('userAssignedIdentity', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/')))), null()), 'keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('keyName', parameters('customerManagedKey').keyName, 'keyVaultResourceId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]), 'Microsoft.KeyVault/vaults', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))), 'keyVaultUri', reference('cMKKeyVault').vaultUri)), null())]" + }, + "dependsOn": [ + "cMKKeyVault" + ] + }, + "netAppAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "netAppAccount" + ] + }, + "netAppAccount_roleAssignments": { + "copy": { + "name": "netAppAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "netAppAccount" + ] + }, + "netAppAccount_backupPolicies": { + "copy": { + "name": "netAppAccount_backupPolicies", + "count": "[length(coalesce(parameters('backupPolicies'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-backupPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'name')]" + }, + "dailyBackupsToKeep": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'dailyBackupsToKeep')]" + }, + "monthlyBackupsToKeep": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'monthlyBackupsToKeep')]" + }, + "weeklyBackupsToKeep": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'weeklyBackupsToKeep')]" + }, + "enabled": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'enabled')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'location'), parameters('location'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "7141176618644423280" + }, + "name": "Azure NetApp Files Backup Policy", + "description": "This module deploys a Backup Policy for Azure NetApp File." + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "backupPolicy", + "metadata": { + "description": "Optional. The name of the backup policy." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the backup policy." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "defaultValue": 2, + "minValue": 2, + "maxValue": 1019, + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "enabled": "[parameters('enabled')]", + "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", + "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]", + "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the backup Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Backup Policy was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "netAppAccount" + ] + }, + "netAppAccount_snapshotPolicies": { + "copy": { + "name": "netAppAccount_snapshotPolicies", + "count": "[length(coalesce(parameters('snapshotPolicies'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-snapshotPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "snapEnabled": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'snapEnabled')]" + }, + "dailySchedule": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'dailySchedule')]" + }, + "hourlySchedule": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'hourlySchedule')]" + }, + "monthlySchedule": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'monthlySchedule')]" + }, + "weeklySchedule": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'weeklySchedule')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "7486219490853787459" + }, + "name": "Azure NetApp Files Snapshot Policy", + "description": "This module deploys a Snapshot Policy for an Azure NetApp File." + }, + "definitions": { + "dailyScheduleType": { + "type": "object", + "properties": { + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The daily snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The daily snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Daily snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a daily schedule for the snapshot policy." + } + }, + "hourlyScheduleType": { + "type": "object", + "properties": { + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The hourly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Hourly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an hourly schedule for the snapshot policy." + } + }, + "weeklyScheduleType": { + "type": "object", + "properties": { + "day": { + "type": "string", + "allowedValues": [ + "Friday", + "Monday", + "Saturday", + "Sunday", + "Thursday", + "Tuesday", + "Wednesday" + ], + "metadata": { + "description": "Required. The weekly snapshot day." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The weekly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The weekly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Weekly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a weekly schedule for the snapshot policy." + } + }, + "monthlyScheduleType": { + "type": "object", + "properties": { + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Required. Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The monthly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The monthly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Monthly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a monthly schedule for the snapshot policy." + } + } + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "snapshotPolicy", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the snapshot policy." + } + }, + "hourlySchedule": { + "$ref": "#/definitions/hourlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for hourly snapshots." + } + }, + "dailySchedule": { + "$ref": "#/definitions/dailyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for daily snapshots." + } + }, + "monthlySchedule": { + "$ref": "#/definitions/monthlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for monthly snapshots." + } + }, + "weeklySchedule": { + "$ref": "#/definitions/weeklyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for weekly snapshots." + } + }, + "snapEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether the snapshot policy is enabled." + } + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "snapshotPolicies": { + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "enabled": "[parameters('snapEnabled')]", + "dailySchedule": "[parameters('dailySchedule')]", + "hourlySchedule": "[parameters('hourlySchedule')]", + "monthlySchedule": "[parameters('monthlySchedule')]", + "weeklySchedule": "[parameters('weeklySchedule')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the snapshot Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Snapshot was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "netAppAccount" + ] + }, + "netAppAccount_backupVault": { + "condition": "[not(empty(parameters('backupVault')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-BackupVault', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(parameters('backupVault'), 'name')]" + }, + "location": { + "value": "[coalesce(tryGet(parameters('backupVault'), 'location'), parameters('location'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "9738469557677047438" + }, + "name": "Azure NetApp Files Volume Backup Vault", + "description": "This module deploys a NetApp Files Backup Vault." + }, + "definitions": { + "backupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backup." + } + } + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "vault", + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the backup vault." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backups": { + "type": "array", + "items": { + "$ref": "#/definitions/backupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of backups to create." + } + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backupVault": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": {} + }, + "backupVault_backups": { + "copy": { + "name": "backupVault_backups", + "count": "[length(coalesce(parameters('backups'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANF-Backup-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "backupVaultName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'name')]" + }, + "label": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'label')]" + }, + "snapshotName": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'snapshotName')]" + }, + "volumeName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].volumeName]" + }, + "capacityPoolName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].capacityPoolName]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "3948084235912412629" + }, + "name": "Azure NetApp Files Volume Backup", + "description": "This module deploys a backup of a NetApp Files Volume." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "backup", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent backup vault. Required if the template is used in a standalone deployment." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "resources": { + "netAppAccount::remoteCapacityPool::volume": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + }, + "netAppAccount::backupVault": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupVaultName'))]" + }, + "netAppAccount::remoteCapacityPool": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" + }, + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backup": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults/backups", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]", + "properties": { + "label": "[parameters('label')]", + "snapshotName": "[parameters('snapshotName')]", + "volumeResourceId": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults/backups', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "backupVault" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup vault." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup vault." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup vault was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('backupVault', '2024-07-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "netAppAccount" + ] + }, + "netAppAccount_capacityPools": { + "copy": { + "name": "netAppAccount_capacityPools", + "count": "[length(coalesce(parameters('capacityPools'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-CapPool-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('capacityPools'), createArray())[copyIndex()].name]" + }, + "size": { + "value": "[coalesce(parameters('capacityPools'), createArray())[copyIndex()].size]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "serviceLevel": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'serviceLevel'), 'Standard')]" + }, + "qosType": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'qosType'), 'Auto')]" + }, + "volumes": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'volumes'), createArray())]" + }, + "coolAccess": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'coolAccess'), false())]" + }, + "roleAssignments": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'roleAssignments'), createArray())]" + }, + "encryptionType": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'encryptionType'), 'Single')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "9255104616647372037" + }, + "name": "Azure NetApp Files Capacity Pools", + "description": "This module deploys an Azure NetApp Files Capacity Pool." + }, + "definitions": { + "volumeType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the pool volume." + } + }, + "coolAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "coolnessPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." + } + }, + "coolAccessRetrievalPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." + } + }, + "encryptionKeySource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source of the encryption key." + } + }, + "keyVaultPrivateEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the key vault private endpoint." + } + }, + "dataProtection": { + "$ref": "#/definitions/dataProtectionType", + "nullable": true, + "metadata": { + "description": "Optional. DataProtection type volumes include an object containing details of the replication." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. Zone where the volume will be placed." + } + }, + "serviceLevel": { + "type": "string", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "nullable": true, + "metadata": { + "description": "Optional. The pool service level. Must match the one of the parent capacity pool." + } + }, + "networkFeatures": { + "type": "string", + "allowedValues": [ + "Basic", + "Basic_Standard", + "Standard", + "Standard_Basic" + ], + "nullable": true, + "metadata": { + "description": "Optional. Network feature for the volume." + } + }, + "creationToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." + } + }, + "usageThreshold": { + "type": "int", + "metadata": { + "description": "Required. Maximum storage quota allowed for a file system in bytes." + } + }, + "protocolTypes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Set of protocol types." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." + } + }, + "exportPolicy": { + "$ref": "#/definitions/exportPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Export policy rules." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "smbEncryption": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." + } + }, + "smbContinuouslyAvailable": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." + } + }, + "smbNonBrowsable": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." + } + }, + "kerberosEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Define if a volume is KerberosEnabled." + } + }, + "volumeType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of the volume. DataProtection volumes are used for replication." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a volume in the capacity pool." + } + }, + "_1.backupType": { + "type": "object", + "properties": { + "backupPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the backup policy to link." + } + }, + "policyEnforced": { + "type": "bool", + "metadata": { + "description": "Required. Enable to enforce the policy." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Backup Vault." + } + } + }, + "metadata": { + "description": "The type for the backup properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "_1.replicationType": { + "type": "object", + "properties": { + "endpointType": { + "type": "string", + "allowedValues": [ + "dst", + "src" + ], + "metadata": { + "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." + } + }, + "remoteVolumeRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." + } + }, + "remoteVolumeResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." + } + }, + "replicationSchedule": { + "type": "string", + "allowedValues": [ + "_10minutely", + "daily", + "hourly" + ], + "metadata": { + "description": "Required. The replication schedule for the volume." + } + }, + "remotePath": { + "type": "object", + "properties": { + "externalHostName": { + "type": "string", + "metadata": { + "description": "Required. The Path to a ONTAP Host." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Required. The name of a server on the ONTAP Host." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of a volume on the server." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." + } + } + }, + "metadata": { + "description": "The type for the replication properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "_1.snapshotType": { + "type": "object", + "properties": { + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy to link." + } + } + }, + "metadata": { + "description": "The type for the snapshot properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "dataProtectionType": { + "type": "object", + "properties": { + "replication": { + "$ref": "#/definitions/_1.replicationType", + "nullable": true, + "metadata": { + "description": "Optional. Replication properties." + } + }, + "backup": { + "$ref": "#/definitions/_1.backupType", + "nullable": true, + "metadata": { + "description": "Optional. Backup properties." + } + }, + "snapshot": { + "$ref": "#/definitions/_1.snapshotType", + "nullable": true, + "metadata": { + "description": "Optional. Snapshot properties." + } + } + }, + "metadata": { + "description": "The type for the data protection properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "exportPolicyType": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleIndex": { + "type": "int", + "metadata": { + "description": "Required. Order index." + } + }, + "allowedClients": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." + } + }, + "chownMode": { + "type": "string", + "allowedValues": [ + "Restricted", + "Unrestricted" + ], + "nullable": true, + "metadata": { + "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." + } + }, + "cifs": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allows CIFS protocol." + } + }, + "hasRootAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Has root access to volume." + } + }, + "kerberos5ReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read only access." + } + }, + "kerberos5ReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read and write access." + } + }, + "kerberos5iReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read only access." + } + }, + "kerberos5iReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read and write access." + } + }, + "kerberos5pReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read only access." + } + }, + "kerberos5pReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read and write access." + } + }, + "nfsv3": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." + } + }, + "nfsv41": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." + } + }, + "unixReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Read only access." + } + }, + "unixReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Read and write access." + } + } + } + }, + "metadata": { + "description": "Required. The Export policy rules." + } + } + }, + "metadata": { + "description": "The type for export policy rules.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + } + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for all resources." + } + }, + "serviceLevel": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "metadata": { + "description": "Optional. The pool service level." + } + }, + "size": { + "type": "int", + "metadata": { + "description": "Required. Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104)." + } + }, + "qosType": { + "type": "string", + "defaultValue": "Auto", + "allowedValues": [ + "Auto", + "Manual" + ], + "metadata": { + "description": "Optional. The qos type of the pool." + } + }, + "volumes": { + "type": "array", + "items": { + "$ref": "#/definitions/volumeType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of volumes to create in the capacity pool." + } + }, + "coolAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "encryptionType": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Double", + "Single" + ], + "metadata": { + "description": "Optional. Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "capacityPool": { + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "serviceLevel": "[parameters('serviceLevel')]", + "size": "[parameters('size')]", + "qosType": "[parameters('qosType')]", + "coolAccess": "[parameters('coolAccess')]", + "encryptionType": "[parameters('encryptionType')]" + } + }, + "capacityPool_roleAssignments": { + "copy": { + "name": "capacityPool_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}/capacityPools/{1}', parameters('netAppAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts/capacityPools', parameters('netAppAccountName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "capacityPool" + ] + }, + "capacityPool_volumes": { + "copy": { + "name": "capacityPool_volumes", + "count": "[length(coalesce(parameters('volumes'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Vol-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "capacityPoolName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "serviceLevel": { + "value": "[parameters('serviceLevel')]" + }, + "creationToken": { + "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'creationToken'), coalesce(parameters('volumes'), createArray())[copyIndex()].name)]" + }, + "usageThreshold": { + "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].usageThreshold]" + }, + "protocolTypes": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'protocolTypes')]" + }, + "subnetResourceId": { + "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].subnetResourceId]" + }, + "exportPolicy": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'exportPolicy')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "networkFeatures": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'networkFeatures')]" + }, + "zones": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'zones')]" + }, + "coolAccess": { + "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolAccess'), false())]" + }, + "coolAccessRetrievalPolicy": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolAccessRetrievalPolicy')]" + }, + "coolnessPeriod": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolnessPeriod')]" + }, + "encryptionKeySource": { + "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'encryptionKeySource'), 'Microsoft.NetApp')]" + }, + "keyVaultPrivateEndpointResourceId": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'keyVaultPrivateEndpointResourceId')]" + }, + "dataProtection": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'dataProtection')]" + }, + "kerberosEnabled": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'kerberosEnabled')]" + }, + "smbContinuouslyAvailable": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbContinuouslyAvailable')]" + }, + "smbEncryption": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbEncryption')]" + }, + "smbNonBrowsable": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbNonBrowsable')]" + }, + "volumeType": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'volumeType')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "13717060947862126529" + }, + "name": "Azure NetApp Files Capacity Pool Volumes", + "description": "This module deploys an Azure NetApp Files Capacity Pool Volume." + }, + "definitions": { + "dataProtectionType": { + "type": "object", + "properties": { + "replication": { + "$ref": "#/definitions/replicationType", + "nullable": true, + "metadata": { + "description": "Optional. Replication properties." + } + }, + "backup": { + "$ref": "#/definitions/backupType", + "nullable": true, + "metadata": { + "description": "Optional. Backup properties." + } + }, + "snapshot": { + "$ref": "#/definitions/snapshotType", + "nullable": true, + "metadata": { + "description": "Optional. Snapshot properties." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data protection properties." + } + }, + "replicationType": { + "type": "object", + "properties": { + "endpointType": { + "type": "string", + "allowedValues": [ + "dst", + "src" + ], + "metadata": { + "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." + } + }, + "remoteVolumeRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." + } + }, + "remoteVolumeResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." + } + }, + "replicationSchedule": { + "type": "string", + "allowedValues": [ + "_10minutely", + "daily", + "hourly" + ], + "metadata": { + "description": "Required. The replication schedule for the volume." + } + }, + "remotePath": { + "type": "object", + "properties": { + "externalHostName": { + "type": "string", + "metadata": { + "description": "Required. The Path to a ONTAP Host." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Required. The name of a server on the ONTAP Host." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of a volume on the server." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." + } + } + }, + "metadata": { + "description": "The type for the replication properties." + } + }, + "backupType": { + "type": "object", + "properties": { + "backupPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the backup policy to link." + } + }, + "policyEnforced": { + "type": "bool", + "metadata": { + "description": "Required. Enable to enforce the policy." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Backup Vault." + } + } + }, + "metadata": { + "description": "The type for the backup properties." + } + }, + "snapshotType": { + "type": "object", + "properties": { + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy to link." + } + } + }, + "metadata": { + "description": "The type for the snapshot properties." + } + }, + "exportPolicyType": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleIndex": { + "type": "int", + "metadata": { + "description": "Required. Order index." + } + }, + "allowedClients": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." + } + }, + "chownMode": { + "type": "string", + "allowedValues": [ + "Restricted", + "Unrestricted" + ], + "nullable": true, + "metadata": { + "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." + } + }, + "cifs": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allows CIFS protocol." + } + }, + "hasRootAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Has root access to volume." + } + }, + "kerberos5ReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read only access." + } + }, + "kerberos5ReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read and write access." + } + }, + "kerberos5iReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read only access." + } + }, + "kerberos5iReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read and write access." + } + }, + "kerberos5pReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read only access." + } + }, + "kerberos5pReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read and write access." + } + }, + "nfsv3": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." + } + }, + "nfsv41": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." + } + }, + "unixReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Read only access." + } + }, + "unixReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Read and write access." + } + } + } + }, + "metadata": { + "description": "Required. The Export policy rules." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for export policy rules." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + } + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent capacity pool. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the pool volume." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "coolAccess": { + "type": "bool", + "metadata": { + "description": "Required. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "coolnessPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." + } + }, + "coolAccessRetrievalPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." + } + }, + "encryptionKeySource": { + "type": "string", + "metadata": { + "description": "Required. The source of the encryption key." + } + }, + "keyVaultPrivateEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the key vault private endpoint." + } + }, + "volumeType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of the volume. DataProtection volumes are used for replication." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. Zone where the volume will be placed." + } + }, + "serviceLevel": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "metadata": { + "description": "Optional. The pool service level. Must match the one of the parent capacity pool." + } + }, + "networkFeatures": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Basic_Standard", + "Standard", + "Standard_Basic" + ], + "metadata": { + "description": "Optional. Network feature for the volume." + } + }, + "creationToken": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." + } + }, + "usageThreshold": { + "type": "int", + "metadata": { + "description": "Required. Maximum storage quota allowed for a file system in bytes." + } + }, + "protocolTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Set of protocol types." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." + } + }, + "exportPolicy": { + "$ref": "#/definitions/exportPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. The export policy rules." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "dataProtection": { + "$ref": "#/definitions/dataProtectionType", + "nullable": true, + "metadata": { + "description": "Optional. DataProtection type volumes include an object containing details of the replication." + } + }, + "smbEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." + } + }, + "smbContinuouslyAvailable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." + } + }, + "smbNonBrowsable": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." + } + }, + "kerberosEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Define if a volume is KerberosEnabled." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "remoteCapacityPoolName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], '')]", + "remoteNetAppName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], '')]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "netAppAccount::capacityPool": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" + }, + "netAppAccount::backupVault": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))]" + }, + "netAppAccount::backupPolicy": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName'))]" + }, + "netAppAccount::snapshotPolicy": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'snapshot')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))]" + }, + "remoteNetAppAccount::remoteCapacityPool::remoteVolume": { + "condition": "[and(and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName'))))), not(empty(tryGet(parameters('dataProtection'), 'replication'))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}/{2}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/')))]" + }, + "remoteNetAppAccount::remoteCapacityPool": { + "condition": "[and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName')))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10])]" + }, + "vnet::subnet": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/')))]" + }, + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "keyVaultPrivateEndpoint": { + "condition": "[not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp'))]", + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/'))]" + }, + "remoteNetAppAccount": { + "condition": "[and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName'))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8]]" + }, + "vnet": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", + "name": "[split(parameters('subnetResourceId'), '/')[8]]" + }, + "volume": { + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": "[shallowMerge(createArray(createObject('coolAccess', parameters('coolAccess'), 'coolAccessRetrievalPolicy', parameters('coolAccessRetrievalPolicy'), 'coolnessPeriod', parameters('coolnessPeriod'), 'encryptionKeySource', parameters('encryptionKeySource')), if(not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp')), createObject('keyVaultPrivateEndpointResourceId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2], split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]), 'Microsoft.Network/privateEndpoints', last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/')))), createObject()), if(not(empty(parameters('volumeType'))), createObject('volumeType', parameters('volumeType')), createObject()), createObject('dataProtection', if(not(empty(parameters('dataProtection'))), createObject('replication', if(not(empty(tryGet(parameters('dataProtection'), 'replication'))), createObject('endpointType', tryGet(parameters('dataProtection'), 'replication', 'endpointType'), 'remoteVolumeRegion', if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]), 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/'))), null()), 'remoteVolumeResourceId', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'replicationSchedule', tryGet(parameters('dataProtection'), 'replication', 'replicationSchedule'), 'remotePath', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remotePath')), createObject()), 'backup', if(not(empty(tryGet(parameters('dataProtection'), 'backup'))), createObject('backupPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName')), 'policyEnforced', coalesce(tryGet(parameters('dataProtection'), 'backup', 'policyEnforced'), false()), 'backupVaultId', resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))), createObject()), 'snapshot', if(not(empty(tryGet(parameters('dataProtection'), 'snapshot'))), createObject('snapshotPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))), createObject())), null()), 'networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('subnetResourceId'), '/')[2], split(parameters('subnetResourceId'), '/')[4]), 'Microsoft.Network/virtualNetworks/subnets', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/'))), 'exportPolicy', parameters('exportPolicy'), 'smbContinuouslyAvailable', parameters('smbContinuouslyAvailable'), 'smbEncryption', parameters('smbEncryption'), 'smbNonBrowsable', parameters('smbNonBrowsable'), 'kerberosEnabled', parameters('kerberosEnabled'))))]", + "zones": "[map(parameters('zones'), lambda('zone', format('{0}', lambdaVariables('zone'))))]" + }, + "volume_roleAssignments": { + "copy": { + "name": "volume_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}/capacityPools/{1}/volumes/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "volume" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Volume." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the Volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Volume was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('volume', '2024-07-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "capacityPool" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Capacity Pool." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Capacity Pool." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools', parameters('netAppAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Capacity Pool was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('capacityPool', '2024-07-01', 'full').location]" + }, + "volumeResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the volume created in the capacity pool." + }, + "copy": { + "count": "[length(coalesce(parameters('volumes'), createArray()))]", + "input": "[reference(format('capacityPool_volumes[{0}]', copyIndex())).outputs.resourceId.value]" + } + } + } + } + }, + "dependsOn": [ + "netAppAccount", + "netAppAccount_backupPolicies", + "netAppAccount_backupVault", + "netAppAccount_snapshotPolicies" + ] + }, + "netAppAccount_backupVaultBackups": { + "condition": "[not(empty(tryGet(parameters('backupVault'), 'backups')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-BackupVault-Backups', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(parameters('backupVault'), 'name')]" + }, + "backups": { + "value": "[tryGet(parameters('backupVault'), 'backups')]" + }, + "location": { + "value": "[coalesce(tryGet(parameters('backupVault'), 'location'), parameters('location'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "9738469557677047438" + }, + "name": "Azure NetApp Files Volume Backup Vault", + "description": "This module deploys a NetApp Files Backup Vault." + }, + "definitions": { + "backupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backup." + } + } + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "vault", + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the backup vault." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backups": { + "type": "array", + "items": { + "$ref": "#/definitions/backupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of backups to create." + } + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backupVault": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": {} + }, + "backupVault_backups": { + "copy": { + "name": "backupVault_backups", + "count": "[length(coalesce(parameters('backups'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANF-Backup-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "backupVaultName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'name')]" + }, + "label": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'label')]" + }, + "snapshotName": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'snapshotName')]" + }, + "volumeName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].volumeName]" + }, + "capacityPoolName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].capacityPoolName]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "3948084235912412629" + }, + "name": "Azure NetApp Files Volume Backup", + "description": "This module deploys a backup of a NetApp Files Volume." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "backup", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent backup vault. Required if the template is used in a standalone deployment." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "resources": { + "netAppAccount::remoteCapacityPool::volume": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + }, + "netAppAccount::backupVault": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupVaultName'))]" + }, + "netAppAccount::remoteCapacityPool": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" + }, + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backup": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults/backups", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]", + "properties": { + "label": "[parameters('label')]", + "snapshotName": "[parameters('snapshotName')]", + "volumeResourceId": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults/backups', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "backupVault" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup vault." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup vault." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup vault was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('backupVault', '2024-07-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "netAppAccount", + "netAppAccount_capacityPools" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the NetApp account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the NetApp account." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the NetApp account was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('netAppAccount', '2024-07-01', 'full').location]" + }, + "capacityPoolResourceIds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resourceId": { + "type": "string" + }, + "volumeResourceIds": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "metadata": { + "description": "The resource IDs of the created capacity pools & their volumes." + }, + "copy": { + "count": "[length(coalesce(parameters('capacityPools'), createArray()))]", + "input": { + "resourceId": "[reference(format('netAppAccount_capacityPools[{0}]', copyIndex())).outputs.resourceId.value]", + "volumeResourceIds": "[reference(format('netAppAccount_capacityPools[{0}]', copyIndex())).outputs.volumeResourceIds.value]" + } + } + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/net-app/net-app-account/snapshot-policies/README.md b/avm/1.1.0/res/net-app/net-app-account/snapshot-policies/README.md new file mode 100644 index 000000000..ca1f6c285 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/snapshot-policies/README.md @@ -0,0 +1,320 @@ +# Azure NetApp Files Snapshot Policy `[Microsoft.NetApp/netAppAccounts/snapshotPolicies]` + +This module deploys a Snapshot Policy for an Azure NetApp File. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.NetApp/netAppAccounts/snapshotPolicies` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-07-01/netAppAccounts/snapshotPolicies) | + +## Parameters + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`netAppAccountName`](#parameter-netappaccountname) | string | The name of the parent NetApp account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dailySchedule`](#parameter-dailyschedule) | object | Schedule for daily snapshots. | +| [`hourlySchedule`](#parameter-hourlyschedule) | object | Schedule for hourly snapshots. | +| [`location`](#parameter-location) | string | The location of the snapshot policy. | +| [`monthlySchedule`](#parameter-monthlyschedule) | object | Schedule for monthly snapshots. | +| [`name`](#parameter-name) | string | The name of the snapshot policy. | +| [`snapEnabled`](#parameter-snapenabled) | bool | Indicates whether the snapshot policy is enabled. | +| [`weeklySchedule`](#parameter-weeklyschedule) | object | Schedule for weekly snapshots. | + +### Parameter: `netAppAccountName` + +The name of the parent NetApp account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `dailySchedule` + +Schedule for daily snapshots. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`hour`](#parameter-dailyschedulehour) | int | The daily snapshot hour. | +| [`minute`](#parameter-dailyscheduleminute) | int | The daily snapshot minute. | +| [`snapshotsToKeep`](#parameter-dailyschedulesnapshotstokeep) | int | Daily snapshot count to keep. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`usedBytes`](#parameter-dailyscheduleusedbytes) | int | Resource size in bytes, current storage usage for the volume in bytes. | + +### Parameter: `dailySchedule.hour` + +The daily snapshot hour. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 23 + +### Parameter: `dailySchedule.minute` + +The daily snapshot minute. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 59 + +### Parameter: `dailySchedule.snapshotsToKeep` + +Daily snapshot count to keep. + +- Required: Yes +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `dailySchedule.usedBytes` + +Resource size in bytes, current storage usage for the volume in bytes. + +- Required: No +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `hourlySchedule` + +Schedule for hourly snapshots. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`minute`](#parameter-hourlyscheduleminute) | int | The hourly snapshot minute. | +| [`snapshotsToKeep`](#parameter-hourlyschedulesnapshotstokeep) | int | Hourly snapshot count to keep. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`usedBytes`](#parameter-hourlyscheduleusedbytes) | int | Resource size in bytes, current storage usage for the volume in bytes. | + +### Parameter: `hourlySchedule.minute` + +The hourly snapshot minute. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 59 + +### Parameter: `hourlySchedule.snapshotsToKeep` + +Hourly snapshot count to keep. + +- Required: Yes +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `hourlySchedule.usedBytes` + +Resource size in bytes, current storage usage for the volume in bytes. + +- Required: No +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `location` + +The location of the snapshot policy. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `monthlySchedule` + +Schedule for monthly snapshots. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`daysOfMonth`](#parameter-monthlyscheduledaysofmonth) | string | Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'. | +| [`hour`](#parameter-monthlyschedulehour) | int | The monthly snapshot hour. | +| [`minute`](#parameter-monthlyscheduleminute) | int | The monthly snapshot minute. | +| [`snapshotsToKeep`](#parameter-monthlyschedulesnapshotstokeep) | int | Monthly snapshot count to keep. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`usedBytes`](#parameter-monthlyscheduleusedbytes) | int | Resource size in bytes, current storage usage for the volume in bytes. | + +### Parameter: `monthlySchedule.daysOfMonth` + +Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'. + +- Required: Yes +- Type: string + +### Parameter: `monthlySchedule.hour` + +The monthly snapshot hour. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 23 + +### Parameter: `monthlySchedule.minute` + +The monthly snapshot minute. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 59 + +### Parameter: `monthlySchedule.snapshotsToKeep` + +Monthly snapshot count to keep. + +- Required: Yes +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `monthlySchedule.usedBytes` + +Resource size in bytes, current storage usage for the volume in bytes. + +- Required: No +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `name` + +The name of the snapshot policy. + +- Required: No +- Type: string +- Default: `'snapshotPolicy'` + +### Parameter: `snapEnabled` + +Indicates whether the snapshot policy is enabled. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `weeklySchedule` + +Schedule for weekly snapshots. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`day`](#parameter-weeklyscheduleday) | string | The weekly snapshot day. | +| [`hour`](#parameter-weeklyschedulehour) | int | The weekly snapshot hour. | +| [`minute`](#parameter-weeklyscheduleminute) | int | The weekly snapshot minute. | +| [`snapshotsToKeep`](#parameter-weeklyschedulesnapshotstokeep) | int | Weekly snapshot count to keep. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`usedBytes`](#parameter-weeklyscheduleusedbytes) | int | Resource size in bytes, current storage usage for the volume in bytes. | + +### Parameter: `weeklySchedule.day` + +The weekly snapshot day. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Friday' + 'Monday' + 'Saturday' + 'Sunday' + 'Thursday' + 'Tuesday' + 'Wednesday' + ] + ``` + +### Parameter: `weeklySchedule.hour` + +The weekly snapshot hour. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 23 + +### Parameter: `weeklySchedule.minute` + +The weekly snapshot minute. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 59 + +### Parameter: `weeklySchedule.snapshotsToKeep` + +Weekly snapshot count to keep. + +- Required: Yes +- Type: int +- MinValue: 1 +- MaxValue: 255 + +### Parameter: `weeklySchedule.usedBytes` + +Resource size in bytes, current storage usage for the volume in bytes. + +- Required: No +- Type: int +- MinValue: 1 +- MaxValue: 255 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the Backup Policy. | +| `resourceGroupName` | string | The name of the Resource Group the Snapshot was created in. | +| `resourceId` | string | The resource IDs of the snapshot Policy created within volume. | diff --git a/avm/1.1.0/res/net-app/net-app-account/snapshot-policies/main.bicep b/avm/1.1.0/res/net-app/net-app-account/snapshot-policies/main.bicep new file mode 100644 index 000000000..f92ae4f41 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/snapshot-policies/main.bicep @@ -0,0 +1,145 @@ +metadata name = 'Azure NetApp Files Snapshot Policy' +metadata description = 'This module deploys a Snapshot Policy for an Azure NetApp File.' + +@description('Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment.') +param netAppAccountName string + +@description('Optional. The name of the snapshot policy.') +param name string = 'snapshotPolicy' + +@description('Optional. The location of the snapshot policy.') +param location string = resourceGroup().location + +@description('Optional. Schedule for hourly snapshots.') +param hourlySchedule hourlyScheduleType? + +@description('Optional. Schedule for daily snapshots.') +param dailySchedule dailyScheduleType? + +@description('Optional. Schedule for monthly snapshots.') +param monthlySchedule monthlyScheduleType? + +@description('Optional. Schedule for weekly snapshots.') +param weeklySchedule weeklyScheduleType? + +@description('Optional. Indicates whether the snapshot policy is enabled.') +param snapEnabled bool = false + +resource netAppAccount 'Microsoft.NetApp/netAppAccounts@2024-07-01' existing = { + name: netAppAccountName +} + +resource snapshotPolicies 'Microsoft.NetApp/netAppAccounts/snapshotPolicies@2024-07-01' = { + name: name + parent: netAppAccount + location: location + properties: { + enabled: snapEnabled + dailySchedule: dailySchedule + hourlySchedule: hourlySchedule + monthlySchedule: monthlySchedule + weeklySchedule: weeklySchedule + } +} + +@description('The resource IDs of the snapshot Policy created within volume.') +output resourceId string = snapshotPolicies.id + +@description('The name of the Backup Policy.') +output name string = snapshotPolicies.name + +@description('The name of the Resource Group the Snapshot was created in.') +output resourceGroupName string = resourceGroup().name + +// ================ // +// Definitions // +// ================ // + +@export() +@description('The type for a daily schedule for the snapshot policy.') +type dailyScheduleType = { + @description('Required. The daily snapshot hour.') + @minValue(0) + @maxValue(23) + hour: int + + @description('Required. The daily snapshot minute.') + @minValue(0) + @maxValue(59) + minute: int + + @description('Required. Daily snapshot count to keep.') + @minValue(1) + @maxValue(255) + snapshotsToKeep: int + + @description('Optional. Resource size in bytes, current storage usage for the volume in bytes.') + usedBytes: int? +} + +@export() +@description('The type for an hourly schedule for the snapshot policy.') +type hourlyScheduleType = { + @description('Required. The hourly snapshot minute.') + @minValue(0) + @maxValue(59) + minute: int + + @description('Required. Hourly snapshot count to keep.') + @minValue(1) + @maxValue(255) + snapshotsToKeep: int + + @description('Optional. Resource size in bytes, current storage usage for the volume in bytes.') + usedBytes: int? +} + +@export() +@description('The type for a weekly schedule for the snapshot policy.') +type weeklyScheduleType = { + @description('Required. The weekly snapshot day.') + day: ('Sunday' | 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday' | 'Saturday') + + @description('Required. The weekly snapshot hour.') + @minValue(0) + @maxValue(23) + hour: int + + @description('Required. The weekly snapshot minute.') + @minValue(0) + @maxValue(59) + minute: int + + @description('Required. Weekly snapshot count to keep.') + @minValue(1) + @maxValue(255) + snapshotsToKeep: int + + @description('Optional. Resource size in bytes, current storage usage for the volume in bytes.') + usedBytes: int? +} + +@export() +@description('The type for a monthly schedule for the snapshot policy.') +type monthlyScheduleType = { + @description('Required. Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., \'10,11,12\'.') + daysOfMonth: string + + @description('Required. The monthly snapshot hour.') + @minValue(0) + @maxValue(23) + hour: int + + @description('Required. The monthly snapshot minute.') + @minValue(0) + @maxValue(59) + minute: int + + @description('Required. Monthly snapshot count to keep.') + @minValue(1) + @maxValue(255) + snapshotsToKeep: int + + @description('Optional. Resource size in bytes, current storage usage for the volume in bytes.') + usedBytes: int? +} diff --git a/avm/1.1.0/res/net-app/net-app-account/snapshot-policies/main.json b/avm/1.1.0/res/net-app/net-app-account/snapshot-policies/main.json new file mode 100644 index 000000000..114e98383 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/snapshot-policies/main.json @@ -0,0 +1,290 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "7486219490853787459" + }, + "name": "Azure NetApp Files Snapshot Policy", + "description": "This module deploys a Snapshot Policy for an Azure NetApp File." + }, + "definitions": { + "dailyScheduleType": { + "type": "object", + "properties": { + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The daily snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The daily snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Daily snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a daily schedule for the snapshot policy." + } + }, + "hourlyScheduleType": { + "type": "object", + "properties": { + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The hourly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Hourly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an hourly schedule for the snapshot policy." + } + }, + "weeklyScheduleType": { + "type": "object", + "properties": { + "day": { + "type": "string", + "allowedValues": [ + "Friday", + "Monday", + "Saturday", + "Sunday", + "Thursday", + "Tuesday", + "Wednesday" + ], + "metadata": { + "description": "Required. The weekly snapshot day." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The weekly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The weekly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Weekly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a weekly schedule for the snapshot policy." + } + }, + "monthlyScheduleType": { + "type": "object", + "properties": { + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Required. Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The monthly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The monthly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Monthly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a monthly schedule for the snapshot policy." + } + } + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "snapshotPolicy", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the snapshot policy." + } + }, + "hourlySchedule": { + "$ref": "#/definitions/hourlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for hourly snapshots." + } + }, + "dailySchedule": { + "$ref": "#/definitions/dailyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for daily snapshots." + } + }, + "monthlySchedule": { + "$ref": "#/definitions/monthlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for monthly snapshots." + } + }, + "weeklySchedule": { + "$ref": "#/definitions/weeklyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for weekly snapshots." + } + }, + "snapEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether the snapshot policy is enabled." + } + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "snapshotPolicies": { + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "enabled": "[parameters('snapEnabled')]", + "dailySchedule": "[parameters('dailySchedule')]", + "hourlySchedule": "[parameters('hourlySchedule')]", + "monthlySchedule": "[parameters('monthlySchedule')]", + "weeklySchedule": "[parameters('weeklySchedule')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the snapshot Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Snapshot was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/net-app/net-app-account/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/net-app/net-app-account/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..697b4d5e9 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,46 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-netapp.netappaccounts-${serviceShort}-rg' + +// enforcing location due to quote restrictions +#disable-next-line no-hardcoded-location +var enforcedLocation = 'australiaeast' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nanaamin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + } +} diff --git a/avm/1.1.0/res/net-app/net-app-account/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/net-app/net-app-account/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..b4dd5e457 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/tests/e2e/max/dependencies.bicep @@ -0,0 +1,52 @@ +@description('Required. The location to create the resources.') +param location string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + delegations: [ + { + name: 'netappDel' + properties: { + serviceName: 'Microsoft.Netapp/volumes' + } + } + ] + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/avm/1.1.0/res/net-app/net-app-account/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/net-app/net-app-account/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..920d492c0 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/tests/e2e/max/main.test.bicep @@ -0,0 +1,229 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-netapp.netappaccounts-${serviceShort}-rg' + +// enforcing location due to quote restrictions +#disable-next-line no-hardcoded-location +var enforcedLocation = 'australiaeast' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nanaamax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The source of the encryption key.') +param encryptionKeySource string = 'Microsoft.NetApp' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: enforcedLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + backupPolicies: [ + { + name: 'myBackupPolicy' + } + ] + snapshotPolicies: [ + { + name: 'mySnapshotPolicy' + dailySchedule: { + snapshotsToKeep: 1 + minute: 0 + hour: 0 + } + } + ] + capacityPools: [ + { + name: 'cp-001' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [ + { + name: 'vol-001' + dataProtection: { + backup: { + backupPolicyName: 'myBackupPolicy' + backupVaultName: 'myVault' + policyEnforced: false + } + snapshot: { + snapshotPolicyName: 'mySnapshotPolicy' + } + } + exportPolicy: { + rules: [ + { + allowedClients: '0.0.0.0/0' + nfsv3: false + nfsv41: true + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: true + kerberos5iReadOnly: false + kerberos5pReadOnly: false + kerberos5ReadOnly: false + kerberos5iReadWrite: false + kerberos5pReadWrite: false + kerberos5ReadWrite: false + } + ] + } + zones: [1] + networkFeatures: 'Standard' + encryptionKeySource: encryptionKeySource + protocolTypes: [ + 'NFSv4.1' + ] + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + subnetResourceId: nestedDependencies.outputs.subnetResourceId + usageThreshold: 107374182400 + } + { + kerberosEnabled: false + exportPolicy: { + rules: [ + { + allowedClients: '0.0.0.0/0' + nfsv3: false + nfsv41: true + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: false + kerberos5ReadOnly: false + kerberos5ReadWrite: false + kerberos5iReadOnly: false + kerberos5iReadWrite: false + kerberos5pReadOnly: false + kerberos5pReadWrite: false + } + ] + } + name: 'vol-002' + zones: [1] + networkFeatures: 'Standard' + encryptionKeySource: encryptionKeySource + protocolTypes: [ + 'NFSv4.1' + ] + subnetResourceId: nestedDependencies.outputs.subnetResourceId + usageThreshold: 107374182400 + smbEncryption: false + smbContinuouslyAvailable: false + smbNonBrowsable: 'Disabled' + } + ] + } + { + name: 'cp-002' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [] + } + ] + backupVault: { + name: 'myVault' + backups: [ + { + name: 'myBackup01' + capacityPoolName: 'cp-001' + volumeName: 'vol-001' + label: 'myLabel' + } + ] + } + roleAssignments: [ + { + name: '18051111-2a33-4f8e-8b24-441aac1e6562' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Contact: 'test.user@testcompany.com' + CostCenter: '7890' + Environment: 'Non-Prod' + PurchaseOrder: '1234' + Role: 'DeploymentValidation' + ServiceName: 'DeploymentValidation' + } + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + } +} diff --git a/avm/1.1.0/res/net-app/net-app-account/tests/e2e/nfs3/dependencies.bicep b/avm/1.1.0/res/net-app/net-app-account/tests/e2e/nfs3/dependencies.bicep new file mode 100644 index 000000000..3692fea51 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/tests/e2e/nfs3/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Required. The location to create the resources.') +param location string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + delegations: [ + { + name: 'netappDel' + properties: { + serviceName: 'Microsoft.Netapp/volumes' + } + } + ] + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/net-app/net-app-account/tests/e2e/nfs3/main.test.bicep b/avm/1.1.0/res/net-app/net-app-account/tests/e2e/nfs3/main.test.bicep new file mode 100644 index 000000000..8e366f3fa --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/tests/e2e/nfs3/main.test.bicep @@ -0,0 +1,168 @@ +targetScope = 'subscription' + +metadata name = 'Using nfs31 parameter set' +metadata description = 'This instance deploys the module with nfs31.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-netapp.netappaccounts-${serviceShort}-rg' + +// enforcing location due to quote restrictions +#disable-next-line no-hardcoded-location +var enforcedLocation = 'australiaeast' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nanaanfs3' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The source of the encryption key.') +param encryptionKeySource string = 'Microsoft.NetApp' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: enforcedLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + capacityPools: [ + { + name: '${namePrefix}-${serviceShort}-cp-001' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [ + { + exportPolicy: { + rules: [ + { + allowedClients: '0.0.0.0/0' + nfsv3: true + nfsv41: false + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: true + kerberos5iReadOnly: false + kerberos5pReadOnly: false + kerberos5ReadOnly: false + kerberos5iReadWrite: false + kerberos5pReadWrite: false + kerberos5ReadWrite: false + } + ] + } + name: '${namePrefix}-${serviceShort}-vol-001' + zones: [1] + networkFeatures: 'Standard' + encryptionKeySource: encryptionKeySource + protocolTypes: [ + 'NFSv3' + ] + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + subnetResourceId: nestedDependencies.outputs.subnetResourceId + usageThreshold: 107374182400 + } + { + name: '${namePrefix}-${serviceShort}-vol-002' + zones: [1] + networkFeatures: 'Standard' + encryptionKeySource: encryptionKeySource + protocolTypes: [ + 'NFSv3' + ] + subnetResourceId: nestedDependencies.outputs.subnetResourceId + usageThreshold: 107374182400 + } + ] + } + { + name: '${namePrefix}-${serviceShort}-cp-002' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [] + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Contact: 'test.user@testcompany.com' + CostCenter: '7890' + Environment: 'Non-Prod' + PurchaseOrder: '1234' + Role: 'DeploymentValidation' + ServiceName: 'DeploymentValidation' + } + } +} diff --git a/avm/1.1.0/res/net-app/net-app-account/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/net-app/net-app-account/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..9875a6875 --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,54 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +// e.g., for a module 'network/private-endpoint' you could use 'dep-dev-network.privateendpoints-${serviceShort}-rg' +param resourceGroupName string = 'dep-${namePrefix}-netapp.netappaccounts-${serviceShort}-rg' + +// enforcing location due to quote restrictions +#disable-next-line no-hardcoded-location +var enforcedLocation = 'australiaeast' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +// e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test +param serviceShort string = 'nanaawaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation + tags: { + service: 'netapp' + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + tags: { + service: 'netapp' + } + } +} diff --git a/avm/1.1.0/res/net-app/net-app-account/version.json b/avm/1.1.0/res/net-app/net-app-account/version.json new file mode 100644 index 000000000..35040975a --- /dev/null +++ b/avm/1.1.0/res/net-app/net-app-account/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.7", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/README.md b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/README.md new file mode 100644 index 000000000..48b9bf485 --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/README.md @@ -0,0 +1,495 @@ +# Application Gateway Web Application Firewall (WAF) Policies `[Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies]` + +This module deploys an Application Gateway Web Application Firewall (WAF) Policy. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-03-01/ApplicationGatewayWebApplicationFirewallPolicies) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/application-gateway-web-application-firewall-policy:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network/application-gateway-web-application-firewall-policy:' = { + name: 'applicationGatewayWebApplicationFirewallPolicyDeployment' + params: { + // Required parameters + managedRules: { + managedRuleSets: [ + { + ruleSetType: 'OWASP' + ruleSetVersion: '3.2' + } + ] + } + name: 'nagwafpmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "managedRules": { + "value": { + "managedRuleSets": [ + { + "ruleSetType": "OWASP", + "ruleSetVersion": "3.2" + } + ] + } + }, + "name": { + "value": "nagwafpmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-gateway-web-application-firewall-policy:' + +// Required parameters +param managedRules = { + managedRuleSets: [ + { + ruleSetType: 'OWASP' + ruleSetVersion: '3.2' + } + ] +} +param name = 'nagwafpmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network/application-gateway-web-application-firewall-policy:' = { + name: 'applicationGatewayWebApplicationFirewallPolicyDeployment' + params: { + // Required parameters + managedRules: { + managedRuleSets: [ + { + ruleGroupOverrides: [] + ruleSetType: 'OWASP' + ruleSetVersion: '3.2' + } + { + ruleGroupOverrides: [] + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '0.1' + } + ] + } + name: 'nagwafpmax001' + // Non-required parameters + location: '' + policySettings: { + customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==' + customBlockResponseStatusCode: 403 + fileUploadLimitInMb: 10 + jsChallengeCookieExpirationInMins: 60 + mode: 'Prevention' + state: 'Enabled' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "managedRules": { + "value": { + "managedRuleSets": [ + { + "ruleGroupOverrides": [], + "ruleSetType": "OWASP", + "ruleSetVersion": "3.2" + }, + { + "ruleGroupOverrides": [], + "ruleSetType": "Microsoft_BotManagerRuleSet", + "ruleSetVersion": "0.1" + } + ] + } + }, + "name": { + "value": "nagwafpmax001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "policySettings": { + "value": { + "customBlockResponseBody": "PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==", + "customBlockResponseStatusCode": 403, + "fileUploadLimitInMb": 10, + "jsChallengeCookieExpirationInMins": 60, + "mode": "Prevention", + "state": "Enabled" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-gateway-web-application-firewall-policy:' + +// Required parameters +param managedRules = { + managedRuleSets: [ + { + ruleGroupOverrides: [] + ruleSetType: 'OWASP' + ruleSetVersion: '3.2' + } + { + ruleGroupOverrides: [] + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '0.1' + } + ] +} +param name = 'nagwafpmax001' +// Non-required parameters +param location = '' +param policySettings = { + customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==' + customBlockResponseStatusCode: 403 + fileUploadLimitInMb: 10 + jsChallengeCookieExpirationInMins: 60 + mode: 'Prevention' + state: 'Enabled' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network/application-gateway-web-application-firewall-policy:' = { + name: 'applicationGatewayWebApplicationFirewallPolicyDeployment' + params: { + // Required parameters + managedRules: { + managedRuleSets: [ + { + ruleGroupOverrides: [] + ruleSetType: 'OWASP' + ruleSetVersion: '3.2' + } + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '0.1' + } + ] + } + name: 'nagwafpwaf001' + // Non-required parameters + location: '' + policySettings: { + fileUploadLimitInMb: 10 + jsChallengeCookieExpirationInMins: 60 + mode: 'Prevention' + state: 'Enabled' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "managedRules": { + "value": { + "managedRuleSets": [ + { + "ruleGroupOverrides": [], + "ruleSetType": "OWASP", + "ruleSetVersion": "3.2" + }, + { + "ruleSetType": "Microsoft_BotManagerRuleSet", + "ruleSetVersion": "0.1" + } + ] + } + }, + "name": { + "value": "nagwafpwaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "policySettings": { + "value": { + "fileUploadLimitInMb": 10, + "jsChallengeCookieExpirationInMins": 60, + "mode": "Prevention", + "state": "Enabled" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-gateway-web-application-firewall-policy:' + +// Required parameters +param managedRules = { + managedRuleSets: [ + { + ruleGroupOverrides: [] + ruleSetType: 'OWASP' + ruleSetVersion: '3.2' + } + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '0.1' + } + ] +} +param name = 'nagwafpwaf001' +// Non-required parameters +param location = '' +param policySettings = { + fileUploadLimitInMb: 10 + jsChallengeCookieExpirationInMins: 60 + mode: 'Prevention' + state: 'Enabled' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`managedRules`](#parameter-managedrules) | object | Describes the managedRules structure. | +| [`name`](#parameter-name) | string | Name of the Application Gateway WAF policy. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`customRules`](#parameter-customrules) | array | The custom rules inside the policy. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`policySettings`](#parameter-policysettings) | object | The PolicySettings for policy. | +| [`tags`](#parameter-tags) | object | Resource tags. | + +### Parameter: `managedRules` + +Describes the managedRules structure. + +- Required: Yes +- Type: object + +### Parameter: `name` + +Name of the Application Gateway WAF policy. + +- Required: Yes +- Type: string + +### Parameter: `customRules` + +The custom rules inside the policy. + +- Required: No +- Type: array + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `policySettings` + +The PolicySettings for policy. + +- Required: No +- Type: object + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the application gateway WAF policy. | +| `resourceGroupName` | string | The resource group the application gateway WAF policy was deployed into. | +| `resourceId` | string | The resource ID of the application gateway WAF policy. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/main.bicep b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/main.bicep new file mode 100644 index 000000000..916c7e066 --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/main.bicep @@ -0,0 +1,65 @@ +metadata name = 'Application Gateway Web Application Firewall (WAF) Policies' +metadata description = 'This module deploys an Application Gateway Web Application Firewall (WAF) Policy.' + +@description('Required. Name of the Application Gateway WAF policy.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Resource tags.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Required. Describes the managedRules structure.') +param managedRules object + +@description('Optional. The custom rules inside the policy.') +param customRules array? + +@description('Optional. The PolicySettings for policy.') +param policySettings object? + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-appgwwebappfirewallpolicy.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource applicationGatewayWAFPolicy 'Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies@2024-03-01' = { + name: name + location: location + tags: tags + properties: { + managedRules: managedRules ?? {} + customRules: customRules + policySettings: policySettings + } +} + +@description('The name of the application gateway WAF policy.') +output name string = applicationGatewayWAFPolicy.name + +@description('The resource ID of the application gateway WAF policy.') +output resourceId string = applicationGatewayWAFPolicy.id + +@description('The resource group the application gateway WAF policy was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = applicationGatewayWAFPolicy.location diff --git a/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/main.json b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/main.json new file mode 100644 index 000000000..cb50cab53 --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/main.json @@ -0,0 +1,127 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10739474921909261763" + }, + "name": "Application Gateway Web Application Firewall (WAF) Policies", + "description": "This module deploys an Application Gateway Web Application Firewall (WAF) Policy." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application Gateway WAF policy." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "managedRules": { + "type": "object", + "metadata": { + "description": "Required. Describes the managedRules structure." + } + }, + "customRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The custom rules inside the policy." + } + }, + "policySettings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The PolicySettings for policy." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-appgwwebappfirewallpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "applicationGatewayWAFPolicy": { + "type": "Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies", + "apiVersion": "2024-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "managedRules": "[coalesce(parameters('managedRules'), createObject())]", + "customRules": "[parameters('customRules')]", + "policySettings": "[parameters('policySettings')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the application gateway WAF policy." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application gateway WAF policy." + }, + "value": "[resourceId('Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application gateway WAF policy was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('applicationGatewayWAFPolicy', '2024-03-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..5963aaab6 --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,56 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.applicationGatewayWebApplicationFirewallPolicies-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nagwafpmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + managedRules: { + managedRuleSets: [ + { + ruleSetType: 'OWASP' + ruleSetVersion: '3.2' + } + ] + } + } + } +] diff --git a/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..6693746b8 --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/tests/e2e/max/main.test.bicep @@ -0,0 +1,75 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.applicationGatewayWebApplicationFirewallPolicies-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nagwafpmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + policySettings: { + fileUploadLimitInMb: 10 + state: 'Enabled' + mode: 'Prevention' + customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==' + customBlockResponseStatusCode: 403 + jsChallengeCookieExpirationInMins: 60 + } + managedRules: { + managedRuleSets: [ + { + ruleSetType: 'OWASP' + ruleSetVersion: '3.2' + ruleGroupOverrides: [] + } + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '0.1' + ruleGroupOverrides: [] + } + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..32732fb65 --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,72 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.applicationGatewayWebApplicationFirewallPolicies-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nagwafpwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + policySettings: { + fileUploadLimitInMb: 10 + state: 'Enabled' + mode: 'Prevention' + jsChallengeCookieExpirationInMins: 60 + } + managedRules: { + managedRuleSets: [ + { + ruleSetType: 'OWASP' + ruleSetVersion: '3.2' + ruleGroupOverrides: [] + } + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '0.1' + } + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/version.json b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/version.json new file mode 100644 index 000000000..1c035df49 --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway-web-application-firewall-policy/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.2", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/application-gateway/README.md b/avm/1.1.0/res/network/application-gateway/README.md new file mode 100644 index 000000000..09941011d --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway/README.md @@ -0,0 +1,4483 @@ +# Network Application Gateways `[Microsoft.Network/applicationGateways]` + +This module deploys a Network Application Gateway. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/applicationGateways` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/applicationGateways) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/application-gateway:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module applicationGateway 'br/public:avm/res/network/application-gateway:' = { + name: 'applicationGatewayDeployment' + params: { + // Required parameters + name: '' + // Non-required parameters + backendAddressPools: [ + { + name: 'backendAddressPool1' + } + ] + backendHttpSettingsCollection: [ + { + name: 'backendHttpSettings1' + properties: { + cookieBasedAffinity: 'Disabled' + port: 80 + protocol: 'Http' + } + } + ] + frontendIPConfigurations: [ + { + name: 'frontendIPConfig1' + properties: { + publicIPAddress: { + id: '' + } + } + } + ] + frontendPorts: [ + { + name: 'frontendPort1' + properties: { + port: 80 + } + } + ] + gatewayIPConfigurations: [ + { + name: 'publicIPConfig1' + properties: { + subnet: { + id: '' + } + } + } + ] + httpListeners: [ + { + name: 'httpListener1' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostName: 'www.contoso.com' + protocol: 'Http' + } + } + ] + location: '' + requestRoutingRules: [ + { + name: 'requestRoutingRule1' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 100 + ruleType: 'Basic' + } + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "" + }, + // Non-required parameters + "backendAddressPools": { + "value": [ + { + "name": "backendAddressPool1" + } + ] + }, + "backendHttpSettingsCollection": { + "value": [ + { + "name": "backendHttpSettings1", + "properties": { + "cookieBasedAffinity": "Disabled", + "port": 80, + "protocol": "Http" + } + } + ] + }, + "frontendIPConfigurations": { + "value": [ + { + "name": "frontendIPConfig1", + "properties": { + "publicIPAddress": { + "id": "" + } + } + } + ] + }, + "frontendPorts": { + "value": [ + { + "name": "frontendPort1", + "properties": { + "port": 80 + } + } + ] + }, + "gatewayIPConfigurations": { + "value": [ + { + "name": "publicIPConfig1", + "properties": { + "subnet": { + "id": "" + } + } + } + ] + }, + "httpListeners": { + "value": [ + { + "name": "httpListener1", + "properties": { + "frontendIPConfiguration": { + "id": "" + }, + "frontendPort": { + "id": "" + }, + "hostName": "www.contoso.com", + "protocol": "Http" + } + } + ] + }, + "location": { + "value": "" + }, + "requestRoutingRules": { + "value": [ + { + "name": "requestRoutingRule1", + "properties": { + "backendAddressPool": { + "id": "" + }, + "backendHttpSettings": { + "id": "" + }, + "httpListener": { + "id": "" + }, + "priority": 100, + "ruleType": "Basic" + } + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-gateway:' + +// Required parameters +param name = '' +// Non-required parameters +param backendAddressPools = [ + { + name: 'backendAddressPool1' + } +] +param backendHttpSettingsCollection = [ + { + name: 'backendHttpSettings1' + properties: { + cookieBasedAffinity: 'Disabled' + port: 80 + protocol: 'Http' + } + } +] +param frontendIPConfigurations = [ + { + name: 'frontendIPConfig1' + properties: { + publicIPAddress: { + id: '' + } + } + } +] +param frontendPorts = [ + { + name: 'frontendPort1' + properties: { + port: 80 + } + } +] +param gatewayIPConfigurations = [ + { + name: 'publicIPConfig1' + properties: { + subnet: { + id: '' + } + } + } +] +param httpListeners = [ + { + name: 'httpListener1' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostName: 'www.contoso.com' + protocol: 'Http' + } + } +] +param location = '' +param requestRoutingRules = [ + { + name: 'requestRoutingRule1' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 100 + ruleType: 'Basic' + } + } +] +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module applicationGateway 'br/public:avm/res/network/application-gateway:' = { + name: 'applicationGatewayDeployment' + params: { + // Required parameters + name: '' + // Non-required parameters + backendAddressPools: [ + { + name: 'appServiceBackendPool' + properties: { + backendAddresses: [ + { + fqdn: 'aghapp.azurewebsites.net' + } + ] + } + } + { + name: 'privateVmBackendPool' + properties: { + backendAddresses: [ + { + ipAddress: '10.0.0.4' + } + ] + } + } + ] + backendHttpSettingsCollection: [ + { + name: 'appServiceBackendHttpsSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: true + port: 443 + protocol: 'Https' + requestTimeout: 30 + } + } + { + name: 'privateVmHttpSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: false + port: 80 + probe: { + id: '' + } + protocol: 'Http' + requestTimeout: 30 + } + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + enableHttp2: true + enableTelemetry: '' + frontendIPConfigurations: [ + { + name: 'private' + properties: { + privateIPAddress: '10.0.0.20' + privateIPAllocationMethod: 'Static' + subnet: { + id: '' + } + } + } + { + name: 'public' + properties: { + privateIPAllocationMethod: 'Dynamic' + privateLinkConfiguration: { + id: '' + } + publicIPAddress: { + id: '' + } + } + } + ] + frontendPorts: [ + { + name: 'port443' + properties: { + port: 443 + } + } + { + name: 'port4433' + properties: { + port: 4433 + } + } + { + name: 'port80' + properties: { + port: 80 + } + } + { + name: 'port8080' + properties: { + port: 8080 + } + } + ] + gatewayIPConfigurations: [ + { + name: 'apw-ip-configuration' + properties: { + subnet: { + id: '' + } + } + } + ] + httpListeners: [ + { + name: 'public443' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '' + } + } + } + { + name: 'private4433' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '' + } + } + } + { + name: 'httpRedirect80' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } + { + name: 'httpRedirect8080' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'public' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + privateLinkConfigurations: [ + { + id: '' + name: 'pvtlink01' + properties: { + ipConfigurations: [ + { + id: '' + name: 'privateLinkIpConfig1' + properties: { + primary: false + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '' + } + } + } + ] + } + } + ] + probes: [ + { + name: 'privateVmHttpSettingProbe' + properties: { + host: '10.0.0.4' + interval: 60 + match: { + statusCodes: [ + '200' + '401' + ] + } + minServers: 3 + path: '/' + pickHostNameFromBackendHttpSettings: false + protocol: 'Http' + timeout: 15 + unhealthyThreshold: 5 + } + } + ] + redirectConfigurations: [ + { + name: 'httpRedirect80' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '' + } + ] + targetListener: { + id: '' + } + } + } + { + name: 'httpRedirect8080' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '' + } + ] + targetListener: { + id: '' + } + } + } + ] + requestRoutingRules: [ + { + name: 'public443-appServiceBackendHttpsSetting-appServiceBackendHttpsSetting' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 200 + ruleType: 'Basic' + } + } + { + name: 'private4433-privateVmHttpSetting-privateVmHttpSetting' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 250 + ruleType: 'Basic' + } + } + { + name: 'httpRedirect80-public443' + properties: { + httpListener: { + id: '' + } + priority: 300 + redirectConfiguration: { + id: '' + } + ruleType: 'Basic' + } + } + { + name: 'httpRedirect8080-private4433' + properties: { + httpListener: { + id: '' + } + priority: 350 + redirectConfiguration: { + id: '' + } + rewriteRuleSet: { + id: '' + } + ruleType: 'Basic' + } + } + ] + rewriteRuleSets: [ + { + id: '' + name: 'customRewrite' + properties: { + rewriteRules: [ + { + actionSet: { + requestHeaderConfigurations: [ + { + headerName: 'Content-Type' + headerValue: 'JSON' + } + { + headerName: 'someheader' + } + ] + responseHeaderConfigurations: [] + } + conditions: [] + name: 'NewRewrite' + ruleSequence: 100 + } + ] + } + } + ] + roleAssignments: [ + { + name: '97fc1da9-bfe4-409d-b17a-da9a82fad0d0' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + sku: 'WAF_v2' + sslCertificates: [ + { + name: 'az-apgw-x-001-ssl-certificate' + properties: { + keyVaultSecretId: '' + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + webApplicationFirewallConfiguration: { + disabledRuleGroups: [ + { + ruleGroupName: 'Known-CVEs' + } + { + ruleGroupName: 'REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION' + } + { + ruleGroupName: 'REQUEST-941-APPLICATION-ATTACK-XSS' + } + ] + enabled: true + exclusions: [ + { + matchVariable: 'RequestHeaderNames' + selector: 'hola' + selectorMatchOperator: 'StartsWith' + } + ] + fileUploadLimitInMb: 100 + firewallMode: 'Detection' + maxRequestBodySizeInKb: 128 + requestBodyCheck: true + ruleSetType: 'OWASP' + ruleSetVersion: '3.0' + } + zones: [ + '1' + '2' + '3' + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "" + }, + // Non-required parameters + "backendAddressPools": { + "value": [ + { + "name": "appServiceBackendPool", + "properties": { + "backendAddresses": [ + { + "fqdn": "aghapp.azurewebsites.net" + } + ] + } + }, + { + "name": "privateVmBackendPool", + "properties": { + "backendAddresses": [ + { + "ipAddress": "10.0.0.4" + } + ] + } + } + ] + }, + "backendHttpSettingsCollection": { + "value": [ + { + "name": "appServiceBackendHttpsSetting", + "properties": { + "cookieBasedAffinity": "Disabled", + "pickHostNameFromBackendAddress": true, + "port": 443, + "protocol": "Https", + "requestTimeout": 30 + } + }, + { + "name": "privateVmHttpSetting", + "properties": { + "cookieBasedAffinity": "Disabled", + "pickHostNameFromBackendAddress": false, + "port": 80, + "probe": { + "id": "" + }, + "protocol": "Http", + "requestTimeout": 30 + } + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "enableHttp2": { + "value": true + }, + "enableTelemetry": { + "value": "" + }, + "frontendIPConfigurations": { + "value": [ + { + "name": "private", + "properties": { + "privateIPAddress": "10.0.0.20", + "privateIPAllocationMethod": "Static", + "subnet": { + "id": "" + } + } + }, + { + "name": "public", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "privateLinkConfiguration": { + "id": "" + }, + "publicIPAddress": { + "id": "" + } + } + } + ] + }, + "frontendPorts": { + "value": [ + { + "name": "port443", + "properties": { + "port": 443 + } + }, + { + "name": "port4433", + "properties": { + "port": 4433 + } + }, + { + "name": "port80", + "properties": { + "port": 80 + } + }, + { + "name": "port8080", + "properties": { + "port": 8080 + } + } + ] + }, + "gatewayIPConfigurations": { + "value": [ + { + "name": "apw-ip-configuration", + "properties": { + "subnet": { + "id": "" + } + } + } + ] + }, + "httpListeners": { + "value": [ + { + "name": "public443", + "properties": { + "frontendIPConfiguration": { + "id": "" + }, + "frontendPort": { + "id": "" + }, + "hostNames": [], + "protocol": "https", + "requireServerNameIndication": false, + "sslCertificate": { + "id": "" + } + } + }, + { + "name": "private4433", + "properties": { + "frontendIPConfiguration": { + "id": "" + }, + "frontendPort": { + "id": "" + }, + "hostNames": [], + "protocol": "https", + "requireServerNameIndication": false, + "sslCertificate": { + "id": "" + } + } + }, + { + "name": "httpRedirect80", + "properties": { + "frontendIPConfiguration": { + "id": "" + }, + "frontendPort": { + "id": "" + }, + "hostNames": [], + "protocol": "Http", + "requireServerNameIndication": false + } + }, + { + "name": "httpRedirect8080", + "properties": { + "frontendIPConfiguration": { + "id": "" + }, + "frontendPort": { + "id": "" + }, + "hostNames": [], + "protocol": "Http", + "requireServerNameIndication": false + } + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "public", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "Role": "DeploymentValidation" + } + } + ] + }, + "privateLinkConfigurations": { + "value": [ + { + "id": "", + "name": "pvtlink01", + "properties": { + "ipConfigurations": [ + { + "id": "", + "name": "privateLinkIpConfig1", + "properties": { + "primary": false, + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "" + } + } + } + ] + } + } + ] + }, + "probes": { + "value": [ + { + "name": "privateVmHttpSettingProbe", + "properties": { + "host": "10.0.0.4", + "interval": 60, + "match": { + "statusCodes": [ + "200", + "401" + ] + }, + "minServers": 3, + "path": "/", + "pickHostNameFromBackendHttpSettings": false, + "protocol": "Http", + "timeout": 15, + "unhealthyThreshold": 5 + } + } + ] + }, + "redirectConfigurations": { + "value": [ + { + "name": "httpRedirect80", + "properties": { + "includePath": true, + "includeQueryString": true, + "redirectType": "Permanent", + "requestRoutingRules": [ + { + "id": "" + } + ], + "targetListener": { + "id": "" + } + } + }, + { + "name": "httpRedirect8080", + "properties": { + "includePath": true, + "includeQueryString": true, + "redirectType": "Permanent", + "requestRoutingRules": [ + { + "id": "" + } + ], + "targetListener": { + "id": "" + } + } + } + ] + }, + "requestRoutingRules": { + "value": [ + { + "name": "public443-appServiceBackendHttpsSetting-appServiceBackendHttpsSetting", + "properties": { + "backendAddressPool": { + "id": "" + }, + "backendHttpSettings": { + "id": "" + }, + "httpListener": { + "id": "" + }, + "priority": 200, + "ruleType": "Basic" + } + }, + { + "name": "private4433-privateVmHttpSetting-privateVmHttpSetting", + "properties": { + "backendAddressPool": { + "id": "" + }, + "backendHttpSettings": { + "id": "" + }, + "httpListener": { + "id": "" + }, + "priority": 250, + "ruleType": "Basic" + } + }, + { + "name": "httpRedirect80-public443", + "properties": { + "httpListener": { + "id": "" + }, + "priority": 300, + "redirectConfiguration": { + "id": "" + }, + "ruleType": "Basic" + } + }, + { + "name": "httpRedirect8080-private4433", + "properties": { + "httpListener": { + "id": "" + }, + "priority": 350, + "redirectConfiguration": { + "id": "" + }, + "rewriteRuleSet": { + "id": "" + }, + "ruleType": "Basic" + } + } + ] + }, + "rewriteRuleSets": { + "value": [ + { + "id": "", + "name": "customRewrite", + "properties": { + "rewriteRules": [ + { + "actionSet": { + "requestHeaderConfigurations": [ + { + "headerName": "Content-Type", + "headerValue": "JSON" + }, + { + "headerName": "someheader" + } + ], + "responseHeaderConfigurations": [] + }, + "conditions": [], + "name": "NewRewrite", + "ruleSequence": 100 + } + ] + } + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "97fc1da9-bfe4-409d-b17a-da9a82fad0d0", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "sku": { + "value": "WAF_v2" + }, + "sslCertificates": { + "value": [ + { + "name": "az-apgw-x-001-ssl-certificate", + "properties": { + "keyVaultSecretId": "" + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "webApplicationFirewallConfiguration": { + "value": { + "disabledRuleGroups": [ + { + "ruleGroupName": "Known-CVEs" + }, + { + "ruleGroupName": "REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION" + }, + { + "ruleGroupName": "REQUEST-941-APPLICATION-ATTACK-XSS" + } + ], + "enabled": true, + "exclusions": [ + { + "matchVariable": "RequestHeaderNames", + "selector": "hola", + "selectorMatchOperator": "StartsWith" + } + ], + "fileUploadLimitInMb": 100, + "firewallMode": "Detection", + "maxRequestBodySizeInKb": 128, + "requestBodyCheck": true, + "ruleSetType": "OWASP", + "ruleSetVersion": "3.0" + } + }, + "zones": { + "value": [ + "1", + "2", + "3" + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-gateway:' + +// Required parameters +param name = '' +// Non-required parameters +param backendAddressPools = [ + { + name: 'appServiceBackendPool' + properties: { + backendAddresses: [ + { + fqdn: 'aghapp.azurewebsites.net' + } + ] + } + } + { + name: 'privateVmBackendPool' + properties: { + backendAddresses: [ + { + ipAddress: '10.0.0.4' + } + ] + } + } +] +param backendHttpSettingsCollection = [ + { + name: 'appServiceBackendHttpsSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: true + port: 443 + protocol: 'Https' + requestTimeout: 30 + } + } + { + name: 'privateVmHttpSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: false + port: 80 + probe: { + id: '' + } + protocol: 'Http' + requestTimeout: 30 + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +enableHttp2: true +param enableTelemetry = '' +param frontendIPConfigurations = [ + { + name: 'private' + properties: { + privateIPAddress: '10.0.0.20' + privateIPAllocationMethod: 'Static' + subnet: { + id: '' + } + } + } + { + name: 'public' + properties: { + privateIPAllocationMethod: 'Dynamic' + privateLinkConfiguration: { + id: '' + } + publicIPAddress: { + id: '' + } + } + } +] +param frontendPorts = [ + { + name: 'port443' + properties: { + port: 443 + } + } + { + name: 'port4433' + properties: { + port: 4433 + } + } + { + name: 'port80' + properties: { + port: 80 + } + } + { + name: 'port8080' + properties: { + port: 8080 + } + } +] +param gatewayIPConfigurations = [ + { + name: 'apw-ip-configuration' + properties: { + subnet: { + id: '' + } + } + } +] +param httpListeners = [ + { + name: 'public443' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '' + } + } + } + { + name: 'private4433' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '' + } + } + } + { + name: 'httpRedirect80' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } + { + name: 'httpRedirect8080' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'public' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +] +param privateLinkConfigurations = [ + { + id: '' + name: 'pvtlink01' + properties: { + ipConfigurations: [ + { + id: '' + name: 'privateLinkIpConfig1' + properties: { + primary: false + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '' + } + } + } + ] + } + } +] +param probes = [ + { + name: 'privateVmHttpSettingProbe' + properties: { + host: '10.0.0.4' + interval: 60 + match: { + statusCodes: [ + '200' + '401' + ] + } + minServers: 3 + path: '/' + pickHostNameFromBackendHttpSettings: false + protocol: 'Http' + timeout: 15 + unhealthyThreshold: 5 + } + } +] +param redirectConfigurations = [ + { + name: 'httpRedirect80' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '' + } + ] + targetListener: { + id: '' + } + } + } + { + name: 'httpRedirect8080' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '' + } + ] + targetListener: { + id: '' + } + } + } +] +param requestRoutingRules = [ + { + name: 'public443-appServiceBackendHttpsSetting-appServiceBackendHttpsSetting' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 200 + ruleType: 'Basic' + } + } + { + name: 'private4433-privateVmHttpSetting-privateVmHttpSetting' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 250 + ruleType: 'Basic' + } + } + { + name: 'httpRedirect80-public443' + properties: { + httpListener: { + id: '' + } + priority: 300 + redirectConfiguration: { + id: '' + } + ruleType: 'Basic' + } + } + { + name: 'httpRedirect8080-private4433' + properties: { + httpListener: { + id: '' + } + priority: 350 + redirectConfiguration: { + id: '' + } + rewriteRuleSet: { + id: '' + } + ruleType: 'Basic' + } + } +] +param rewriteRuleSets = [ + { + id: '' + name: 'customRewrite' + properties: { + rewriteRules: [ + { + actionSet: { + requestHeaderConfigurations: [ + { + headerName: 'Content-Type' + headerValue: 'JSON' + } + { + headerName: 'someheader' + } + ] + responseHeaderConfigurations: [] + } + conditions: [] + name: 'NewRewrite' + ruleSequence: 100 + } + ] + } + } +] +param roleAssignments = [ + { + name: '97fc1da9-bfe4-409d-b17a-da9a82fad0d0' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sku = 'WAF_v2' +param sslCertificates = [ + { + name: 'az-apgw-x-001-ssl-certificate' + properties: { + keyVaultSecretId: '' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param webApplicationFirewallConfiguration = { + disabledRuleGroups: [ + { + ruleGroupName: 'Known-CVEs' + } + { + ruleGroupName: 'REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION' + } + { + ruleGroupName: 'REQUEST-941-APPLICATION-ATTACK-XSS' + } + ] + enabled: true + exclusions: [ + { + matchVariable: 'RequestHeaderNames' + selector: 'hola' + selectorMatchOperator: 'StartsWith' + } + ] + fileUploadLimitInMb: 100 + firewallMode: 'Detection' + maxRequestBodySizeInKb: 128 + requestBodyCheck: true + ruleSetType: 'OWASP' + ruleSetVersion: '3.0' +} +param zones = [ + '1' + '2' + '3' +] +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module applicationGateway 'br/public:avm/res/network/application-gateway:' = { + name: 'applicationGatewayDeployment' + params: { + // Required parameters + name: '' + // Non-required parameters + backendAddressPools: [ + { + name: 'appServiceBackendPool' + properties: { + backendAddresses: [ + { + fqdn: 'aghapp.azurewebsites.net' + } + ] + } + } + { + name: 'privateVmBackendPool' + properties: { + backendAddresses: [ + { + ipAddress: '10.0.0.4' + } + ] + } + } + ] + backendHttpSettingsCollection: [ + { + name: 'appServiceBackendHttpsSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: true + port: 443 + protocol: 'Https' + requestTimeout: 30 + } + } + { + name: 'privateVmHttpSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: false + port: 80 + probe: { + id: '' + } + protocol: 'Http' + requestTimeout: 30 + } + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + enableHttp2: true + enableTelemetry: '' + firewallPolicyResourceId: '' + frontendIPConfigurations: [ + { + name: 'private' + properties: { + privateIPAddress: '10.0.0.20' + privateIPAllocationMethod: 'Static' + subnet: { + id: '' + } + } + } + { + name: 'public' + properties: { + privateIPAllocationMethod: 'Dynamic' + privateLinkConfiguration: { + id: '' + } + publicIPAddress: { + id: '' + } + } + } + ] + frontendPorts: [ + { + name: 'port443' + properties: { + port: 443 + } + } + { + name: 'port4433' + properties: { + port: 4433 + } + } + { + name: 'port80' + properties: { + port: 80 + } + } + { + name: 'port8080' + properties: { + port: 8080 + } + } + ] + gatewayIPConfigurations: [ + { + name: 'apw-ip-configuration' + properties: { + subnet: { + id: '' + } + } + } + ] + httpListeners: [ + { + name: 'public443' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '' + } + } + } + { + name: 'private4433' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '' + } + } + } + { + name: 'httpRedirect80' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } + { + name: 'httpRedirect8080' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'public' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + privateLinkConfigurations: [ + { + id: '' + name: 'pvtlink01' + properties: { + ipConfigurations: [ + { + id: '' + name: 'privateLinkIpConfig1' + properties: { + primary: false + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '' + } + } + } + ] + } + } + ] + probes: [ + { + name: 'privateVmHttpSettingProbe' + properties: { + host: '10.0.0.4' + interval: 60 + match: { + statusCodes: [ + '200' + '401' + ] + } + minServers: 3 + path: '/' + pickHostNameFromBackendHttpSettings: false + protocol: 'Http' + timeout: 15 + unhealthyThreshold: 5 + } + } + ] + redirectConfigurations: [ + { + name: 'httpRedirect80' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '' + } + ] + targetListener: { + id: '' + } + } + } + { + name: 'httpRedirect8080' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '' + } + ] + targetListener: { + id: '' + } + } + } + ] + requestRoutingRules: [ + { + name: 'public443-appServiceBackendHttpsSetting-appServiceBackendHttpsSetting' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 200 + ruleType: 'Basic' + } + } + { + name: 'private4433-privateVmHttpSetting-privateVmHttpSetting' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 250 + ruleType: 'Basic' + } + } + { + name: 'httpRedirect80-public443' + properties: { + httpListener: { + id: '' + } + priority: 300 + redirectConfiguration: { + id: '' + } + ruleType: 'Basic' + } + } + { + name: 'httpRedirect8080-private4433' + properties: { + httpListener: { + id: '' + } + priority: 350 + redirectConfiguration: { + id: '' + } + rewriteRuleSet: { + id: '' + } + ruleType: 'Basic' + } + } + ] + rewriteRuleSets: [ + { + id: '' + name: 'customRewrite' + properties: { + rewriteRules: [ + { + actionSet: { + requestHeaderConfigurations: [ + { + headerName: 'Content-Type' + headerValue: 'JSON' + } + { + headerName: 'someheader' + } + ] + responseHeaderConfigurations: [] + } + conditions: [] + name: 'NewRewrite' + ruleSequence: 100 + } + ] + } + } + ] + sku: 'WAF_v2' + sslCertificates: [ + { + name: 'az-apgw-x-001-ssl-certificate' + properties: { + keyVaultSecretId: '' + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "" + }, + // Non-required parameters + "backendAddressPools": { + "value": [ + { + "name": "appServiceBackendPool", + "properties": { + "backendAddresses": [ + { + "fqdn": "aghapp.azurewebsites.net" + } + ] + } + }, + { + "name": "privateVmBackendPool", + "properties": { + "backendAddresses": [ + { + "ipAddress": "10.0.0.4" + } + ] + } + } + ] + }, + "backendHttpSettingsCollection": { + "value": [ + { + "name": "appServiceBackendHttpsSetting", + "properties": { + "cookieBasedAffinity": "Disabled", + "pickHostNameFromBackendAddress": true, + "port": 443, + "protocol": "Https", + "requestTimeout": 30 + } + }, + { + "name": "privateVmHttpSetting", + "properties": { + "cookieBasedAffinity": "Disabled", + "pickHostNameFromBackendAddress": false, + "port": 80, + "probe": { + "id": "" + }, + "protocol": "Http", + "requestTimeout": 30 + } + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "enableHttp2": { + "value": true + }, + "enableTelemetry": { + "value": "" + }, + "firewallPolicyResourceId": { + "value": "" + }, + "frontendIPConfigurations": { + "value": [ + { + "name": "private", + "properties": { + "privateIPAddress": "10.0.0.20", + "privateIPAllocationMethod": "Static", + "subnet": { + "id": "" + } + } + }, + { + "name": "public", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "privateLinkConfiguration": { + "id": "" + }, + "publicIPAddress": { + "id": "" + } + } + } + ] + }, + "frontendPorts": { + "value": [ + { + "name": "port443", + "properties": { + "port": 443 + } + }, + { + "name": "port4433", + "properties": { + "port": 4433 + } + }, + { + "name": "port80", + "properties": { + "port": 80 + } + }, + { + "name": "port8080", + "properties": { + "port": 8080 + } + } + ] + }, + "gatewayIPConfigurations": { + "value": [ + { + "name": "apw-ip-configuration", + "properties": { + "subnet": { + "id": "" + } + } + } + ] + }, + "httpListeners": { + "value": [ + { + "name": "public443", + "properties": { + "frontendIPConfiguration": { + "id": "" + }, + "frontendPort": { + "id": "" + }, + "hostNames": [], + "protocol": "https", + "requireServerNameIndication": false, + "sslCertificate": { + "id": "" + } + } + }, + { + "name": "private4433", + "properties": { + "frontendIPConfiguration": { + "id": "" + }, + "frontendPort": { + "id": "" + }, + "hostNames": [], + "protocol": "https", + "requireServerNameIndication": false, + "sslCertificate": { + "id": "" + } + } + }, + { + "name": "httpRedirect80", + "properties": { + "frontendIPConfiguration": { + "id": "" + }, + "frontendPort": { + "id": "" + }, + "hostNames": [], + "protocol": "Http", + "requireServerNameIndication": false + } + }, + { + "name": "httpRedirect8080", + "properties": { + "frontendIPConfiguration": { + "id": "" + }, + "frontendPort": { + "id": "" + }, + "hostNames": [], + "protocol": "Http", + "requireServerNameIndication": false + } + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "public", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "Role": "DeploymentValidation" + } + } + ] + }, + "privateLinkConfigurations": { + "value": [ + { + "id": "", + "name": "pvtlink01", + "properties": { + "ipConfigurations": [ + { + "id": "", + "name": "privateLinkIpConfig1", + "properties": { + "primary": false, + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "" + } + } + } + ] + } + } + ] + }, + "probes": { + "value": [ + { + "name": "privateVmHttpSettingProbe", + "properties": { + "host": "10.0.0.4", + "interval": 60, + "match": { + "statusCodes": [ + "200", + "401" + ] + }, + "minServers": 3, + "path": "/", + "pickHostNameFromBackendHttpSettings": false, + "protocol": "Http", + "timeout": 15, + "unhealthyThreshold": 5 + } + } + ] + }, + "redirectConfigurations": { + "value": [ + { + "name": "httpRedirect80", + "properties": { + "includePath": true, + "includeQueryString": true, + "redirectType": "Permanent", + "requestRoutingRules": [ + { + "id": "" + } + ], + "targetListener": { + "id": "" + } + } + }, + { + "name": "httpRedirect8080", + "properties": { + "includePath": true, + "includeQueryString": true, + "redirectType": "Permanent", + "requestRoutingRules": [ + { + "id": "" + } + ], + "targetListener": { + "id": "" + } + } + } + ] + }, + "requestRoutingRules": { + "value": [ + { + "name": "public443-appServiceBackendHttpsSetting-appServiceBackendHttpsSetting", + "properties": { + "backendAddressPool": { + "id": "" + }, + "backendHttpSettings": { + "id": "" + }, + "httpListener": { + "id": "" + }, + "priority": 200, + "ruleType": "Basic" + } + }, + { + "name": "private4433-privateVmHttpSetting-privateVmHttpSetting", + "properties": { + "backendAddressPool": { + "id": "" + }, + "backendHttpSettings": { + "id": "" + }, + "httpListener": { + "id": "" + }, + "priority": 250, + "ruleType": "Basic" + } + }, + { + "name": "httpRedirect80-public443", + "properties": { + "httpListener": { + "id": "" + }, + "priority": 300, + "redirectConfiguration": { + "id": "" + }, + "ruleType": "Basic" + } + }, + { + "name": "httpRedirect8080-private4433", + "properties": { + "httpListener": { + "id": "" + }, + "priority": 350, + "redirectConfiguration": { + "id": "" + }, + "rewriteRuleSet": { + "id": "" + }, + "ruleType": "Basic" + } + } + ] + }, + "rewriteRuleSets": { + "value": [ + { + "id": "", + "name": "customRewrite", + "properties": { + "rewriteRules": [ + { + "actionSet": { + "requestHeaderConfigurations": [ + { + "headerName": "Content-Type", + "headerValue": "JSON" + }, + { + "headerName": "someheader" + } + ], + "responseHeaderConfigurations": [] + }, + "conditions": [], + "name": "NewRewrite", + "ruleSequence": 100 + } + ] + } + } + ] + }, + "sku": { + "value": "WAF_v2" + }, + "sslCertificates": { + "value": [ + { + "name": "az-apgw-x-001-ssl-certificate", + "properties": { + "keyVaultSecretId": "" + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-gateway:' + +// Required parameters +param name = '' +// Non-required parameters +param backendAddressPools = [ + { + name: 'appServiceBackendPool' + properties: { + backendAddresses: [ + { + fqdn: 'aghapp.azurewebsites.net' + } + ] + } + } + { + name: 'privateVmBackendPool' + properties: { + backendAddresses: [ + { + ipAddress: '10.0.0.4' + } + ] + } + } +] +param backendHttpSettingsCollection = [ + { + name: 'appServiceBackendHttpsSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: true + port: 443 + protocol: 'Https' + requestTimeout: 30 + } + } + { + name: 'privateVmHttpSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: false + port: 80 + probe: { + id: '' + } + protocol: 'Http' + requestTimeout: 30 + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +enableHttp2: true +param enableTelemetry = '' +param firewallPolicyResourceId = '' +param frontendIPConfigurations = [ + { + name: 'private' + properties: { + privateIPAddress: '10.0.0.20' + privateIPAllocationMethod: 'Static' + subnet: { + id: '' + } + } + } + { + name: 'public' + properties: { + privateIPAllocationMethod: 'Dynamic' + privateLinkConfiguration: { + id: '' + } + publicIPAddress: { + id: '' + } + } + } +] +param frontendPorts = [ + { + name: 'port443' + properties: { + port: 443 + } + } + { + name: 'port4433' + properties: { + port: 4433 + } + } + { + name: 'port80' + properties: { + port: 80 + } + } + { + name: 'port8080' + properties: { + port: 8080 + } + } +] +param gatewayIPConfigurations = [ + { + name: 'apw-ip-configuration' + properties: { + subnet: { + id: '' + } + } + } +] +param httpListeners = [ + { + name: 'public443' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '' + } + } + } + { + name: 'private4433' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '' + } + } + } + { + name: 'httpRedirect80' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } + { + name: 'httpRedirect8080' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'public' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +] +param privateLinkConfigurations = [ + { + id: '' + name: 'pvtlink01' + properties: { + ipConfigurations: [ + { + id: '' + name: 'privateLinkIpConfig1' + properties: { + primary: false + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '' + } + } + } + ] + } + } +] +param probes = [ + { + name: 'privateVmHttpSettingProbe' + properties: { + host: '10.0.0.4' + interval: 60 + match: { + statusCodes: [ + '200' + '401' + ] + } + minServers: 3 + path: '/' + pickHostNameFromBackendHttpSettings: false + protocol: 'Http' + timeout: 15 + unhealthyThreshold: 5 + } + } +] +param redirectConfigurations = [ + { + name: 'httpRedirect80' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '' + } + ] + targetListener: { + id: '' + } + } + } + { + name: 'httpRedirect8080' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '' + } + ] + targetListener: { + id: '' + } + } + } +] +param requestRoutingRules = [ + { + name: 'public443-appServiceBackendHttpsSetting-appServiceBackendHttpsSetting' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 200 + ruleType: 'Basic' + } + } + { + name: 'private4433-privateVmHttpSetting-privateVmHttpSetting' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 250 + ruleType: 'Basic' + } + } + { + name: 'httpRedirect80-public443' + properties: { + httpListener: { + id: '' + } + priority: 300 + redirectConfiguration: { + id: '' + } + ruleType: 'Basic' + } + } + { + name: 'httpRedirect8080-private4433' + properties: { + httpListener: { + id: '' + } + priority: 350 + redirectConfiguration: { + id: '' + } + rewriteRuleSet: { + id: '' + } + ruleType: 'Basic' + } + } +] +param rewriteRuleSets = [ + { + id: '' + name: 'customRewrite' + properties: { + rewriteRules: [ + { + actionSet: { + requestHeaderConfigurations: [ + { + headerName: 'Content-Type' + headerValue: 'JSON' + } + { + headerName: 'someheader' + } + ] + responseHeaderConfigurations: [] + } + conditions: [] + name: 'NewRewrite' + ruleSequence: 100 + } + ] + } + } +] +param sku = 'WAF_v2' +param sslCertificates = [ + { + name: 'az-apgw-x-001-ssl-certificate' + properties: { + keyVaultSecretId: '' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Application Gateway. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`authenticationCertificates`](#parameter-authenticationcertificates) | array | Authentication certificates of the application gateway resource. | +| [`autoscaleMaxCapacity`](#parameter-autoscalemaxcapacity) | int | Upper bound on number of Application Gateway capacity. | +| [`autoscaleMinCapacity`](#parameter-autoscalemincapacity) | int | Lower bound on number of Application Gateway capacity. | +| [`backendAddressPools`](#parameter-backendaddresspools) | array | Backend address pool of the application gateway resource. | +| [`backendHttpSettingsCollection`](#parameter-backendhttpsettingscollection) | array | Backend http settings of the application gateway resource. | +| [`backendSettingsCollection`](#parameter-backendsettingscollection) | array | Backend settings of the application gateway resource. For default limits, see [Application Gateway limits](https://learn.microsoft.com/en-us/azure/azure-subscription-service-limits#application-gateway-limits). | +| [`capacity`](#parameter-capacity) | int | The number of Application instances to be configured. | +| [`customErrorConfigurations`](#parameter-customerrorconfigurations) | array | Custom error configurations of the application gateway resource. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableFips`](#parameter-enablefips) | bool | Whether FIPS is enabled on the application gateway resource. | +| [`enableHttp2`](#parameter-enablehttp2) | bool | Whether HTTP2 is enabled on the application gateway resource. | +| [`enableRequestBuffering`](#parameter-enablerequestbuffering) | bool | Enable request buffering. | +| [`enableResponseBuffering`](#parameter-enableresponsebuffering) | bool | Enable response buffering. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`firewallPolicyResourceId`](#parameter-firewallpolicyresourceid) | string | The resource ID of an associated firewall policy. Should be configured for security reasons. | +| [`frontendIPConfigurations`](#parameter-frontendipconfigurations) | array | Frontend IP addresses of the application gateway resource. | +| [`frontendPorts`](#parameter-frontendports) | array | Frontend ports of the application gateway resource. | +| [`gatewayIPConfigurations`](#parameter-gatewayipconfigurations) | array | Subnets of the application gateway resource. | +| [`httpListeners`](#parameter-httplisteners) | array | Http listeners of the application gateway resource. | +| [`listeners`](#parameter-listeners) | array | Listeners of the application gateway resource. For default limits, see [Application Gateway limits](https://learn.microsoft.com/en-us/azure/azure-subscription-service-limits#application-gateway-limits). | +| [`loadDistributionPolicies`](#parameter-loaddistributionpolicies) | array | Load distribution policies of the application gateway resource. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | +| [`privateLinkConfigurations`](#parameter-privatelinkconfigurations) | array | PrivateLink configurations on application gateway. | +| [`probes`](#parameter-probes) | array | Probes of the application gateway resource. | +| [`redirectConfigurations`](#parameter-redirectconfigurations) | array | Redirect configurations of the application gateway resource. | +| [`requestRoutingRules`](#parameter-requestroutingrules) | array | Request routing rules of the application gateway resource. | +| [`rewriteRuleSets`](#parameter-rewriterulesets) | array | Rewrite rules for the application gateway resource. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`routingRules`](#parameter-routingrules) | array | Routing rules of the application gateway resource. | +| [`sku`](#parameter-sku) | string | The name of the SKU for the Application Gateway. | +| [`sslCertificates`](#parameter-sslcertificates) | array | SSL certificates of the application gateway resource. | +| [`sslPolicyCipherSuites`](#parameter-sslpolicyciphersuites) | array | Ssl cipher suites to be enabled in the specified order to application gateway. | +| [`sslPolicyMinProtocolVersion`](#parameter-sslpolicyminprotocolversion) | string | Ssl protocol enums. | +| [`sslPolicyName`](#parameter-sslpolicyname) | string | Ssl predefined policy name enums. | +| [`sslPolicyType`](#parameter-sslpolicytype) | string | Type of Ssl Policy. | +| [`sslProfiles`](#parameter-sslprofiles) | array | SSL profiles of the application gateway resource. | +| [`tags`](#parameter-tags) | object | Resource tags. | +| [`trustedClientCertificates`](#parameter-trustedclientcertificates) | array | Trusted client certificates of the application gateway resource. | +| [`trustedRootCertificates`](#parameter-trustedrootcertificates) | array | Trusted Root certificates of the application gateway resource. | +| [`urlPathMaps`](#parameter-urlpathmaps) | array | URL path map of the application gateway resource. | +| [`webApplicationFirewallConfiguration`](#parameter-webapplicationfirewallconfiguration) | object | Application gateway web application firewall configuration. Should be configured for security reasons. | +| [`zones`](#parameter-zones) | array | A list of availability zones denoting where the resource needs to come from. | + +### Parameter: `name` + +Name of the Application Gateway. + +- Required: Yes +- Type: string + +### Parameter: `authenticationCertificates` + +Authentication certificates of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `autoscaleMaxCapacity` + +Upper bound on number of Application Gateway capacity. + +- Required: No +- Type: int +- Default: `-1` + +### Parameter: `autoscaleMinCapacity` + +Lower bound on number of Application Gateway capacity. + +- Required: No +- Type: int +- Default: `-1` + +### Parameter: `backendAddressPools` + +Backend address pool of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `backendHttpSettingsCollection` + +Backend http settings of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `backendSettingsCollection` + +Backend settings of the application gateway resource. For default limits, see [Application Gateway limits](https://learn.microsoft.com/en-us/azure/azure-subscription-service-limits#application-gateway-limits). + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `capacity` + +The number of Application instances to be configured. + +- Required: No +- Type: int +- Default: `2` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `customErrorConfigurations` + +Custom error configurations of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 10 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 10 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 10 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `enableFips` + +Whether FIPS is enabled on the application gateway resource. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `enableHttp2` + +Whether HTTP2 is enabled on the application gateway resource. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `enableRequestBuffering` + +Enable request buffering. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `enableResponseBuffering` + +Enable response buffering. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `firewallPolicyResourceId` + +The resource ID of an associated firewall policy. Should be configured for security reasons. + +- Required: No +- Type: string +- Default: `''` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `frontendIPConfigurations` + +Frontend IP addresses of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `frontendPorts` + +Frontend ports of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `gatewayIPConfigurations` + +Subnets of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `httpListeners` + +Http listeners of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `listeners` + +Listeners of the application gateway resource. For default limits, see [Application Gateway limits](https://learn.microsoft.com/en-us/azure/azure-subscription-service-limits#application-gateway-limits). + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `loadDistributionPolicies` + +Load distribution policies of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 10 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 10 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints` + +Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 10 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file". | +| [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationSecurityGroupResourceIds`](#parameter-privateendpointsapplicationsecuritygroupresourceids) | array | Application security groups in which the private endpoint IP configuration is included. | +| [`customDnsConfigs`](#parameter-privateendpointscustomdnsconfigs) | array | Custom DNS configurations. | +| [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | +| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | +| [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | +| [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | +| [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | +| [`privateDnsZoneGroup`](#parameter-privateendpointsprivatednszonegroup) | object | The private DNS zone group to configure for the private endpoint. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | +| [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | + +### Parameter: `privateEndpoints.service` + +The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file". + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.subnetResourceId` + +Resource ID of the subnet where the endpoint needs to be created. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.applicationSecurityGroupResourceIds` + +Application security groups in which the private endpoint IP configuration is included. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.customDnsConfigs` + +Custom DNS configurations. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 10 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | FQDN that resolves to private endpoint IP address. | + +### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +A list of private IP addresses of the private endpoint. + +- Required: Yes +- Type: array +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +FQDN that resolves to private endpoint IP address. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.customNetworkInterfaceName` + +The custom name of the network interface attached to the private endpoint. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.ipConfigurations` + +A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 10 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsipconfigurationsname) | string | The name of the resource that is unique within a resource group. | +| [`properties`](#parameter-privateendpointsipconfigurationsproperties) | object | Properties of private endpoint IP configurations. | + +### Parameter: `privateEndpoints.ipConfigurations.name` + +The name of the resource that is unique within a resource group. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.ipConfigurations.properties` + +Properties of private endpoint IP configurations. + +- Required: Yes +- Type: object +- MinValue: 0 +- MaxValue: 10 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private IP address obtained from the private endpoint's subnet. | + +### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` + +The ID of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.ipConfigurations.properties.memberName` + +The member name of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` + +A private IP address obtained from the private endpoint's subnet. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.location` + +The location to deploy the private endpoint to. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.lock` + +Specify the type of lock. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 10 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-privateendpointslockkind) | string | Specify the type of lock. | +| [`name`](#parameter-privateendpointslockname) | string | Specify the name of lock. | + +### Parameter: `privateEndpoints.lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.lock.name` + +Specify the name of lock. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.manualConnectionRequestMessage` + +A message passed to the owner of the remote resource with the manual connection request. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.name` + +The name of the private endpoint. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.privateDnsZoneGroup` + +The private DNS zone group to configure for the private endpoint. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 10 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneGroupConfigs`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigs) | array | The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the Private DNS Zone Group. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs` + +The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. + +- Required: Yes +- Type: array +- MinValue: 0 +- MaxValue: 10 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneResourceId`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsprivatednszoneresourceid) | string | The resource id of the private DNS zone. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsname) | string | The name of the private DNS zone group config. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.privateDnsZoneResourceId` + +The resource id of the private DNS zone. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.name` + +The name of the private DNS zone group config. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.privateDnsZoneGroup.name` + +The name of the Private DNS Zone Group. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.resourceGroupName` + +Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 10 +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-privateendpointsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-privateendpointsroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-privateendpointsroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-privateendpointsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-privateendpointsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-privateendpointsroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-privateendpointsroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-privateendpointsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `privateEndpoints.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.roleAssignments.condition` + +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". + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateEndpoints.tags` + +Tags to be applied on all resources/resource groups in this deployment. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `privateLinkConfigurations` + +PrivateLink configurations on application gateway. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `probes` + +Probes of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `redirectConfigurations` + +Redirect configurations of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `requestRoutingRules` + +Request routing rules of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `rewriteRuleSets` + +Rewrite rules for the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 10 +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `routingRules` + +Routing rules of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `sku` + +The name of the SKU for the Application Gateway. + +- Required: No +- Type: string +- Default: `'Standard_v2'` +- Allowed: + ```Bicep + [ + 'Standard_Large' + 'Standard_Medium' + 'Standard_Small' + 'Standard_v2' + 'WAF_Large' + 'WAF_Medium' + 'WAF_v2' + ] + ``` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `sslCertificates` + +SSL certificates of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `sslPolicyCipherSuites` + +Ssl cipher suites to be enabled in the specified order to application gateway. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256' + 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384' + ] + ``` +- Allowed: + ```Bicep + [ + 'TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA' + 'TLS_DHE_DSS_WITH_AES_128_CBC_SHA' + 'TLS_DHE_DSS_WITH_AES_128_CBC_SHA256' + 'TLS_DHE_DSS_WITH_AES_256_CBC_SHA' + 'TLS_DHE_DSS_WITH_AES_256_CBC_SHA256' + 'TLS_DHE_RSA_WITH_AES_128_CBC_SHA' + 'TLS_DHE_RSA_WITH_AES_128_GCM_SHA256' + 'TLS_DHE_RSA_WITH_AES_256_CBC_SHA' + 'TLS_DHE_RSA_WITH_AES_256_GCM_SHA384' + 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA' + 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256' + 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256' + 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA' + 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384' + 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384' + 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA' + 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256' + 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256' + 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA' + 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384' + 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384' + 'TLS_RSA_WITH_3DES_EDE_CBC_SHA' + 'TLS_RSA_WITH_AES_128_CBC_SHA' + 'TLS_RSA_WITH_AES_128_CBC_SHA256' + 'TLS_RSA_WITH_AES_128_GCM_SHA256' + 'TLS_RSA_WITH_AES_256_CBC_SHA' + 'TLS_RSA_WITH_AES_256_CBC_SHA256' + 'TLS_RSA_WITH_AES_256_GCM_SHA384' + ] + ``` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `sslPolicyMinProtocolVersion` + +Ssl protocol enums. + +- Required: No +- Type: string +- Default: `'TLSv1_2'` +- Allowed: + ```Bicep + [ + 'TLSv1_0' + 'TLSv1_1' + 'TLSv1_2' + 'TLSv1_3' + ] + ``` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `sslPolicyName` + +Ssl predefined policy name enums. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'AppGwSslPolicy20150501' + 'AppGwSslPolicy20170401' + 'AppGwSslPolicy20170401S' + 'AppGwSslPolicy20220101' + 'AppGwSslPolicy20220101S' + ] + ``` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `sslPolicyType` + +Type of Ssl Policy. + +- Required: No +- Type: string +- Default: `'Custom'` +- Allowed: + ```Bicep + [ + 'Custom' + 'CustomV2' + 'Predefined' + ] + ``` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `sslProfiles` + +SSL profiles of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `trustedClientCertificates` + +Trusted client certificates of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `trustedRootCertificates` + +Trusted Root certificates of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `urlPathMaps` + +URL path map of the application gateway resource. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `webApplicationFirewallConfiguration` + +Application gateway web application firewall configuration. Should be configured for security reasons. + +- Required: No +- Type: object +- Default: `{}` +- MinValue: 0 +- MaxValue: 10 + +### Parameter: `zones` + +A list of availability zones denoting where the resource needs to come from. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` +- MinValue: 0 +- MaxValue: 10 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the application gateway. | +| `privateEndpoints` | array | The private endpoints of the application gateway. | +| `resourceGroupName` | string | The resource group the application gateway was deployed into. | +| `resourceId` | string | The resource ID of the application gateway. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/private-endpoint:0.7.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/application-gateway/main.bicep b/avm/1.1.0/res/network/application-gateway/main.bicep new file mode 100644 index 000000000..586885786 --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway/main.bicep @@ -0,0 +1,651 @@ +metadata name = 'Network Application Gateways' +metadata description = 'This module deploys a Network Application Gateway.' + +@description('Required. Name of the Application Gateway.') +@maxLength(80) +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType + +@description('Optional. Authentication certificates of the application gateway resource.') +param authenticationCertificates array = [] + +@description('Optional. Upper bound on number of Application Gateway capacity.') +param autoscaleMaxCapacity int = -1 + +@description('Optional. Lower bound on number of Application Gateway capacity.') +param autoscaleMinCapacity int = -1 + +@description('Optional. Backend address pool of the application gateway resource.') +param backendAddressPools array = [] + +@description('Optional. Backend http settings of the application gateway resource.') +param backendHttpSettingsCollection array = [] + +@description('Optional. Custom error configurations of the application gateway resource.') +param customErrorConfigurations array = [] + +@description('Optional. Whether FIPS is enabled on the application gateway resource.') +param enableFips bool = false + +@description('Optional. Whether HTTP2 is enabled on the application gateway resource.') +param enableHttp2 bool = false + +@description('Optional. The resource ID of an associated firewall policy. Should be configured for security reasons.') +param firewallPolicyResourceId string = '' + +@description('Optional. Frontend IP addresses of the application gateway resource.') +param frontendIPConfigurations array = [] + +@description('Optional. Frontend ports of the application gateway resource.') +param frontendPorts array = [] + +@description('Optional. Subnets of the application gateway resource.') +param gatewayIPConfigurations array = [] + +@description('Optional. Enable request buffering.') +param enableRequestBuffering bool = false + +@description('Optional. Enable response buffering.') +param enableResponseBuffering bool = false + +@description('Optional. Http listeners of the application gateway resource.') +param httpListeners array = [] + +@description('Optional. Load distribution policies of the application gateway resource.') +param loadDistributionPolicies array = [] + +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointType + +@description('Optional. PrivateLink configurations on application gateway.') +param privateLinkConfigurations array = [] + +@description('Optional. Probes of the application gateway resource.') +param probes array = [] + +@description('Optional. Redirect configurations of the application gateway resource.') +param redirectConfigurations array = [] + +@description('Optional. Request routing rules of the application gateway resource.') +param requestRoutingRules array = [] + +@description('Optional. Rewrite rules for the application gateway resource.') +param rewriteRuleSets array = [] + +@description('Optional. The name of the SKU for the Application Gateway.') +@allowed([ + 'Standard_Small' + 'Standard_Medium' + 'Standard_Large' + 'WAF_Medium' + 'WAF_Large' + 'Standard_v2' + 'WAF_v2' +]) +param sku string = 'Standard_v2' + +@description('Optional. The number of Application instances to be configured.') +@minValue(0) +@maxValue(10) +param capacity int = 2 + +@description('Optional. SSL certificates of the application gateway resource.') +param sslCertificates array = [] + +@description('Optional. Ssl cipher suites to be enabled in the specified order to application gateway.') +@allowed([ + 'TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA' + 'TLS_DHE_DSS_WITH_AES_128_CBC_SHA' + 'TLS_DHE_DSS_WITH_AES_128_CBC_SHA256' + 'TLS_DHE_DSS_WITH_AES_256_CBC_SHA' + 'TLS_DHE_DSS_WITH_AES_256_CBC_SHA256' + 'TLS_DHE_RSA_WITH_AES_128_CBC_SHA' + 'TLS_DHE_RSA_WITH_AES_128_GCM_SHA256' + 'TLS_DHE_RSA_WITH_AES_256_CBC_SHA' + 'TLS_DHE_RSA_WITH_AES_256_GCM_SHA384' + 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA' + 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256' + 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256' + 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA' + 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384' + 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384' + 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA' + 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256' + 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256' + 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA' + 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384' + 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384' + 'TLS_RSA_WITH_3DES_EDE_CBC_SHA' + 'TLS_RSA_WITH_AES_128_CBC_SHA' + 'TLS_RSA_WITH_AES_128_CBC_SHA256' + 'TLS_RSA_WITH_AES_128_GCM_SHA256' + 'TLS_RSA_WITH_AES_256_CBC_SHA' + 'TLS_RSA_WITH_AES_256_CBC_SHA256' + 'TLS_RSA_WITH_AES_256_GCM_SHA384' +]) +param sslPolicyCipherSuites array = [ + 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384' + 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256' +] + +@description('Optional. Ssl protocol enums.') +@allowed([ + 'TLSv1_0' + 'TLSv1_1' + 'TLSv1_2' + 'TLSv1_3' +]) +param sslPolicyMinProtocolVersion string = 'TLSv1_2' + +@description('Optional. Ssl predefined policy name enums.') +@allowed([ + 'AppGwSslPolicy20150501' + 'AppGwSslPolicy20170401' + 'AppGwSslPolicy20170401S' + 'AppGwSslPolicy20220101' + 'AppGwSslPolicy20220101S' + '' +]) +param sslPolicyName string = '' + +@description('Optional. Type of Ssl Policy.') +@allowed([ + 'Custom' + 'CustomV2' + 'Predefined' +]) +param sslPolicyType string = 'Custom' + +@description('Optional. SSL profiles of the application gateway resource.') +param sslProfiles array = [] + +@description('Optional. Trusted client certificates of the application gateway resource.') +param trustedClientCertificates array = [] + +@description('Optional. Trusted Root certificates of the application gateway resource.') +param trustedRootCertificates array = [] + +@description('Optional. URL path map of the application gateway resource.') +param urlPathMaps array = [] + +@description('Optional. Application gateway web application firewall configuration. Should be configured for security reasons.') +param webApplicationFirewallConfiguration object = {} + +@description('Optional. A list of availability zones denoting where the resource needs to come from.') +param zones array = [ + 1 + 2 + 3 +] + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: !empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Resource tags.') +param tags object? + +@description('Optional. Backend settings of the application gateway resource. For default limits, see [Application Gateway limits](https://learn.microsoft.com/en-us/azure/azure-subscription-service-limits#application-gateway-limits).') +param backendSettingsCollection array = [] + +@description('Optional. Listeners of the application gateway resource. For default limits, see [Application Gateway limits](https://learn.microsoft.com/en-us/azure/azure-subscription-service-limits#application-gateway-limits).') +param listeners array = [] + +@description('Optional. Routing rules of the application gateway resource.') +param routingRules array = [] + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-appgw.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource applicationGateway 'Microsoft.Network/applicationGateways@2023-04-01' = { + name: name + location: location + tags: tags + identity: identity + properties: union( + { + authenticationCertificates: authenticationCertificates + autoscaleConfiguration: autoscaleMaxCapacity > 0 && autoscaleMinCapacity >= 0 + ? { + maxCapacity: autoscaleMaxCapacity + minCapacity: autoscaleMinCapacity + } + : null + backendAddressPools: backendAddressPools + backendHttpSettingsCollection: backendHttpSettingsCollection + backendSettingsCollection: backendSettingsCollection + customErrorConfigurations: customErrorConfigurations + enableHttp2: enableHttp2 + firewallPolicy: !empty(firewallPolicyResourceId) + ? { + id: firewallPolicyResourceId + } + : null + forceFirewallPolicyAssociation: !empty(firewallPolicyResourceId) + frontendIPConfigurations: frontendIPConfigurations + frontendPorts: frontendPorts + gatewayIPConfigurations: gatewayIPConfigurations + globalConfiguration: endsWith(sku, 'v2') + ? { + enableRequestBuffering: enableRequestBuffering + enableResponseBuffering: enableResponseBuffering + } + : null + httpListeners: httpListeners + loadDistributionPolicies: loadDistributionPolicies + listeners: listeners + privateLinkConfigurations: privateLinkConfigurations + probes: probes + redirectConfigurations: redirectConfigurations + requestRoutingRules: requestRoutingRules + routingRules: routingRules + rewriteRuleSets: rewriteRuleSets + sku: { + name: sku + tier: endsWith(sku, 'v2') ? sku : substring(sku, 0, indexOf(sku, '_')) + capacity: autoscaleMaxCapacity > 0 && autoscaleMinCapacity >= 0 ? null : capacity + } + sslCertificates: sslCertificates + sslPolicy: sslPolicyType != 'Predefined' + ? { + cipherSuites: sslPolicyCipherSuites + minProtocolVersion: sslPolicyMinProtocolVersion + policyName: empty(sslPolicyName) ? null : sslPolicyName + policyType: sslPolicyType + } + : { + policyName: empty(sslPolicyName) ? null : sslPolicyName + policyType: sslPolicyType + } + sslProfiles: sslProfiles + trustedClientCertificates: trustedClientCertificates + trustedRootCertificates: trustedRootCertificates + urlPathMaps: urlPathMaps + }, + (enableFips + ? { + enableFips: enableFips + } + : {}), + (!empty(webApplicationFirewallConfiguration) + ? { webApplicationFirewallConfiguration: webApplicationFirewallConfiguration } + : {}) + ) + zones: zones +} + +resource applicationGateway_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: applicationGateway +} + +resource applicationGateway_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: applicationGateway + } +] + +module applicationGateway_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.7.1' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-applicationGateway-PrivateEndpoint-${index}' + scope: resourceGroup(privateEndpoint.?resourceGroupName ?? '') + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(applicationGateway.id, '/'))}-${privateEndpoint.service}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(applicationGateway.id, '/'))}-${privateEndpoint.service}-${index}' + properties: { + privateLinkServiceId: applicationGateway.id + groupIds: [ + privateEndpoint.service + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(applicationGateway.id, '/'))}-${privateEndpoint.service}-${index}' + properties: { + privateLinkServiceId: applicationGateway.id + groupIds: [ + privateEndpoint.service + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] + : null + subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry + location: privateEndpoint.?location ?? reference( + split(privateEndpoint.subnetResourceId, '/subnets/')[0], + '2020-06-01', + 'Full' + ).location + lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } + } +] + +resource applicationGateway_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + applicationGateway.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: applicationGateway + } +] + +@description('The name of the application gateway.') +output name string = applicationGateway.name + +@description('The resource ID of the application gateway.') +output resourceId string = applicationGateway.id + +@description('The resource group the application gateway was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = applicationGateway.location + +@description('The private endpoints of the application gateway.') +output privateEndpoints array = [ + for (pe, i) in (!empty(privateEndpoints) ? array(privateEndpoints) : []): { + name: applicationGateway_privateEndpoints[i].outputs.name + resourceId: applicationGateway_privateEndpoints[i].outputs.resourceId + groupId: applicationGateway_privateEndpoints[i].outputs.groupId + customDnsConfig: applicationGateway_privateEndpoints[i].outputs.customDnsConfig + networkInterfaceIds: applicationGateway_privateEndpoints[i].outputs.networkInterfaceIds + } +] + +// =============== // +// Definitions // +// =============== // + +type managedIdentitiesType = { + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[]? +}? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type privateEndpointType = { + @description('Optional. The name of the private endpoint.') + name: string? + + @description('Optional. The location to deploy the private endpoint to.') + location: string? + + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + + @description('Required. The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file".') + service: string + + @description('Required. Resource ID of the subnet where the endpoint needs to be created.') + subnetResourceId: string + + @description('Optional. The private DNS zone group to configure for the private endpoint.') + privateDnsZoneGroup: { + @description('Optional. The name of the Private DNS Zone Group.') + name: string? + + @description('Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones.') + privateDnsZoneGroupConfigs: { + @description('Optional. The name of the private DNS zone group config.') + name: string? + + @description('Required. The resource id of the private DNS zone.') + privateDnsZoneResourceId: string + }[] + }? + + @description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + + @description('Optional. Custom DNS configurations.') + customDnsConfigs: { + @description('Optional. FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @description('Required. A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[]? + + @description('Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints.') + ipConfigurations: { + @description('Required. The name of the resource that is unique within a resource group.') + name: string + + @description('Required. Properties of private endpoint IP configurations.') + properties: { + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') + groupId: string + + @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') + memberName: string + + @description('Required. A private IP address obtained from the private endpoint\'s subnet.') + privateIPAddress: string + } + }[]? + + @description('Optional. Application security groups in which the private endpoint IP configuration is included.') + applicationSecurityGroupResourceIds: string[]? + + @description('Optional. The custom name of the network interface attached to the private endpoint.') + customNetworkInterfaceName: string? + + @description('Optional. Specify the type of lock.') + lock: lockType + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') + tags: object? + + @description('Optional. Enable/Disable usage telemetry for module.') + enableTelemetry: bool? + + @description('Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.') + resourceGroupName: string? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/application-gateway/main.json b/avm/1.1.0/res/network/application-gateway/main.json new file mode 100644 index 000000000..824e92d7b --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway/main.json @@ -0,0 +1,1794 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "5192277678912295849" + }, + "name": "Network Application Gateways", + "description": "This module deploys a Network Application Gateway." + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroup": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 80, + "metadata": { + "description": "Required. Name of the Application Gateway." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "authenticationCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Authentication certificates of the application gateway resource." + } + }, + "autoscaleMaxCapacity": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Upper bound on number of Application Gateway capacity." + } + }, + "autoscaleMinCapacity": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Lower bound on number of Application Gateway capacity." + } + }, + "backendAddressPools": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Backend address pool of the application gateway resource." + } + }, + "backendHttpSettingsCollection": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Backend http settings of the application gateway resource." + } + }, + "customErrorConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Custom error configurations of the application gateway resource." + } + }, + "enableFips": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether FIPS is enabled on the application gateway resource." + } + }, + "enableHttp2": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether HTTP2 is enabled on the application gateway resource." + } + }, + "firewallPolicyResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of an associated firewall policy. Should be configured for security reasons." + } + }, + "frontendIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Frontend IP addresses of the application gateway resource." + } + }, + "frontendPorts": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Frontend ports of the application gateway resource." + } + }, + "gatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Subnets of the application gateway resource." + } + }, + "enableRequestBuffering": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable request buffering." + } + }, + "enableResponseBuffering": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable response buffering." + } + }, + "httpListeners": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Http listeners of the application gateway resource." + } + }, + "loadDistributionPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Load distribution policies of the application gateway resource." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "privateLinkConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. PrivateLink configurations on application gateway." + } + }, + "probes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Probes of the application gateway resource." + } + }, + "redirectConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Redirect configurations of the application gateway resource." + } + }, + "requestRoutingRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Request routing rules of the application gateway resource." + } + }, + "rewriteRuleSets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Rewrite rules for the application gateway resource." + } + }, + "sku": { + "type": "string", + "defaultValue": "Standard_v2", + "allowedValues": [ + "Standard_Small", + "Standard_Medium", + "Standard_Large", + "WAF_Medium", + "WAF_Large", + "Standard_v2", + "WAF_v2" + ], + "metadata": { + "description": "Optional. The name of the SKU for the Application Gateway." + } + }, + "capacity": { + "type": "int", + "defaultValue": 2, + "minValue": 0, + "maxValue": 10, + "metadata": { + "description": "Optional. The number of Application instances to be configured." + } + }, + "sslCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. SSL certificates of the application gateway resource." + } + }, + "sslPolicyCipherSuites": { + "type": "array", + "defaultValue": [ + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" + ], + "allowedValues": [ + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384" + ], + "metadata": { + "description": "Optional. Ssl cipher suites to be enabled in the specified order to application gateway." + } + }, + "sslPolicyMinProtocolVersion": { + "type": "string", + "defaultValue": "TLSv1_2", + "allowedValues": [ + "TLSv1_0", + "TLSv1_1", + "TLSv1_2", + "TLSv1_3" + ], + "metadata": { + "description": "Optional. Ssl protocol enums." + } + }, + "sslPolicyName": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "AppGwSslPolicy20150501", + "AppGwSslPolicy20170401", + "AppGwSslPolicy20170401S", + "AppGwSslPolicy20220101", + "AppGwSslPolicy20220101S", + "" + ], + "metadata": { + "description": "Optional. Ssl predefined policy name enums." + } + }, + "sslPolicyType": { + "type": "string", + "defaultValue": "Custom", + "allowedValues": [ + "Custom", + "CustomV2", + "Predefined" + ], + "metadata": { + "description": "Optional. Type of Ssl Policy." + } + }, + "sslProfiles": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. SSL profiles of the application gateway resource." + } + }, + "trustedClientCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Trusted client certificates of the application gateway resource." + } + }, + "trustedRootCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Trusted Root certificates of the application gateway resource." + } + }, + "urlPathMaps": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. URL path map of the application gateway resource." + } + }, + "webApplicationFirewallConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Application gateway web application firewall configuration. Should be configured for security reasons." + } + }, + "zones": { + "type": "array", + "defaultValue": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting where the resource needs to come from." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "backendSettingsCollection": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Backend settings of the application gateway resource. For default limits, see [Application Gateway limits](https://learn.microsoft.com/en-us/azure/azure-subscription-service-limits#application-gateway-limits)." + } + }, + "listeners": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Listeners of the application gateway resource. For default limits, see [Application Gateway limits](https://learn.microsoft.com/en-us/azure/azure-subscription-service-limits#application-gateway-limits)." + } + }, + "routingRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Routing rules of the application gateway resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null()), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-appgw.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "applicationGateway": { + "type": "Microsoft.Network/applicationGateways", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[union(createObject('authenticationCertificates', parameters('authenticationCertificates'), 'autoscaleConfiguration', if(and(greater(parameters('autoscaleMaxCapacity'), 0), greaterOrEquals(parameters('autoscaleMinCapacity'), 0)), createObject('maxCapacity', parameters('autoscaleMaxCapacity'), 'minCapacity', parameters('autoscaleMinCapacity')), null()), 'backendAddressPools', parameters('backendAddressPools'), 'backendHttpSettingsCollection', parameters('backendHttpSettingsCollection'), 'backendSettingsCollection', parameters('backendSettingsCollection'), 'customErrorConfigurations', parameters('customErrorConfigurations'), 'enableHttp2', parameters('enableHttp2'), 'firewallPolicy', if(not(empty(parameters('firewallPolicyResourceId'))), createObject('id', parameters('firewallPolicyResourceId')), null()), 'forceFirewallPolicyAssociation', not(empty(parameters('firewallPolicyResourceId'))), 'frontendIPConfigurations', parameters('frontendIPConfigurations'), 'frontendPorts', parameters('frontendPorts'), 'gatewayIPConfigurations', parameters('gatewayIPConfigurations'), 'globalConfiguration', if(endsWith(parameters('sku'), 'v2'), createObject('enableRequestBuffering', parameters('enableRequestBuffering'), 'enableResponseBuffering', parameters('enableResponseBuffering')), null()), 'httpListeners', parameters('httpListeners'), 'loadDistributionPolicies', parameters('loadDistributionPolicies'), 'listeners', parameters('listeners'), 'privateLinkConfigurations', parameters('privateLinkConfigurations'), 'probes', parameters('probes'), 'redirectConfigurations', parameters('redirectConfigurations'), 'requestRoutingRules', parameters('requestRoutingRules'), 'routingRules', parameters('routingRules'), 'rewriteRuleSets', parameters('rewriteRuleSets'), 'sku', createObject('name', parameters('sku'), 'tier', if(endsWith(parameters('sku'), 'v2'), parameters('sku'), substring(parameters('sku'), 0, indexOf(parameters('sku'), '_'))), 'capacity', if(and(greater(parameters('autoscaleMaxCapacity'), 0), greaterOrEquals(parameters('autoscaleMinCapacity'), 0)), null(), parameters('capacity'))), 'sslCertificates', parameters('sslCertificates'), 'sslPolicy', if(not(equals(parameters('sslPolicyType'), 'Predefined')), createObject('cipherSuites', parameters('sslPolicyCipherSuites'), 'minProtocolVersion', parameters('sslPolicyMinProtocolVersion'), 'policyName', if(empty(parameters('sslPolicyName')), null(), parameters('sslPolicyName')), 'policyType', parameters('sslPolicyType')), createObject('policyName', if(empty(parameters('sslPolicyName')), null(), parameters('sslPolicyName')), 'policyType', parameters('sslPolicyType'))), 'sslProfiles', parameters('sslProfiles'), 'trustedClientCertificates', parameters('trustedClientCertificates'), 'trustedRootCertificates', parameters('trustedRootCertificates'), 'urlPathMaps', parameters('urlPathMaps')), if(parameters('enableFips'), createObject('enableFips', parameters('enableFips')), createObject()), if(not(empty(parameters('webApplicationFirewallConfiguration'))), createObject('webApplicationFirewallConfiguration', parameters('webApplicationFirewallConfiguration')), createObject()))]", + "zones": "[parameters('zones')]" + }, + "applicationGateway_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/applicationGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "applicationGateway" + ] + }, + "applicationGateway_diagnosticSettings": { + "copy": { + "name": "applicationGateway_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/applicationGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "applicationGateway" + ] + }, + "applicationGateway_roleAssignments": { + "copy": { + "name": "applicationGateway_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/applicationGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/applicationGateways', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "applicationGateway" + ] + }, + "applicationGateway_privateEndpoints": { + "copy": { + "name": "applicationGateway_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-applicationGateway-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Network/applicationGateways', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Network/applicationGateways', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Network/applicationGateways', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Network/applicationGateways', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Network/applicationGateways', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "1277254088602407590" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + } + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5805178546717255803" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" + }, + "customDnsConfig": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceIds": { + "type": "array", + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + }, + "value": "[reference('privateEndpoint').networkInterfaces]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(and(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds', 0), ''), if(and(not(empty(reference('privateEndpoint').privateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds', 0), ''), ''))]" + } + } + } + }, + "dependsOn": [ + "applicationGateway" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the application gateway." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application gateway." + }, + "value": "[resourceId('Microsoft.Network/applicationGateways', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application gateway was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('applicationGateway', '2023-04-01', 'full').location]" + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the application gateway." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", + "input": { + "name": "[reference(format('applicationGateway_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('applicationGateway_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('applicationGateway_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('applicationGateway_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('applicationGateway_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/application-gateway/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/application-gateway/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..4f1950dc6 --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,60 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource publicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + } + } + { + name: 'privateLinkSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 1) + privateLinkServiceNetworkPolicies: 'Disabled' + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network default subnet.') +output defaultSubnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id diff --git a/avm/1.1.0/res/network/application-gateway/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/application-gateway/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..8bb4990db --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,137 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.applicationgateway-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nagmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +var resourceName = '${namePrefix}${serviceShort}001' + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + // You parameters go here + name: resourceName + location: resourceLocation + gatewayIPConfigurations: [ + { + name: 'publicIPConfig1' + properties: { + subnet: { + id: nestedDependencies.outputs.defaultSubnetResourceId + } + } + } + ] + frontendIPConfigurations: [ + { + name: 'frontendIPConfig1' + properties: { + publicIPAddress: { + id: nestedDependencies.outputs.publicIPResourceId + } + } + } + ] + frontendPorts: [ + { + name: 'frontendPort1' + properties: { + port: 80 + } + } + ] + backendAddressPools: [ + { + name: 'backendAddressPool1' + } + ] + backendHttpSettingsCollection: [ + { + name: 'backendHttpSettings1' + properties: { + port: 80 + protocol: 'Http' + cookieBasedAffinity: 'Disabled' + } + } + ] + httpListeners: [ + { + name: 'httpListener1' + properties: { + hostName: 'www.contoso.com' + protocol: 'Http' + frontendIPConfiguration: { + id: '${resourceGroup.id}/providers/Microsoft.Network/applicationGateways/${resourceName}/frontendIPConfigurations/frontendIPConfig1' + } + frontendPort: { + id: '${resourceGroup.id}/providers/Microsoft.Network/applicationGateways/${resourceName}/frontendPorts/frontendPort1' + } + } + } + ] + requestRoutingRules: [ + { + name: 'requestRoutingRule1' + properties: { + ruleType: 'Basic' + priority: 100 + httpListener: { + id: '${resourceGroup.id}/providers/Microsoft.Network/applicationGateways/${resourceName}/httpListeners/httpListener1' + } + backendAddressPool: { + id: '${resourceGroup.id}/providers/Microsoft.Network/applicationGateways/${resourceName}/backendAddressPools/backendAddressPool1' + } + backendHttpSettings: { + id: '${resourceGroup.id}/providers/Microsoft.Network/applicationGateways/${resourceName}/backendHttpSettingsCollection/backendHttpSettings1' + } + } + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/application-gateway/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/application-gateway/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..294c1f4f7 --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway/tests/e2e/max/dependencies.bicep @@ -0,0 +1,154 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Deployment Script to create for the Certificate generation.') +param certDeploymentScriptName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + } + } + { + name: 'privateLinkSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 1) + privateLinkServiceNetworkPolicies: 'Disabled' + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.appgateway.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource publicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } +} + +resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${managedIdentity.name}-KeyVault-Admin-RoleAssignment') + scope: keyVault + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '00482a5a-887f-4fb3-b363-3b7fe8e74483' + ) // Key Vault Administrator + principalType: 'ServicePrincipal' + } +} + +resource certDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: certDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '8.0' + retentionInterval: 'P1D' + arguments: '-KeyVaultName "${keyVault.name}" -CertName "applicationGatewaySslCertificate"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Set-CertificateInKeyVault.ps1') + } +} + +@description('The resource ID of the created Virtual Network default subnet.') +output defaultSubnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Virtual Network private link subnet.') +output privateLinkSubnetResourceId string = virtualNetwork.properties.subnets[1].id + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The URL of the created certificate.') +output certificateSecretUrl string = certDeploymentScript.properties.outputs.secretUrl + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/1.1.0/res/network/application-gateway/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/application-gateway/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..deeab8e4a --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway/tests/e2e/max/main.test.bicep @@ -0,0 +1,530 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.applicationgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nagmax' + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableTelemetry bool = true + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + certDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +var appGWName = '${namePrefix}${serviceShort}001' +var appGWExpectedResourceID = '${resourceGroup.id}/providers/Microsoft.Network/applicationGateways/${appGWName}' +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + enableTelemetry: enableTelemetry + name: appGWName + zones: [ + '1' + '2' + '3' + ] + backendAddressPools: [ + { + name: 'appServiceBackendPool' + properties: { + backendAddresses: [ + { + fqdn: 'aghapp.azurewebsites.net' + } + ] + } + } + { + name: 'privateVmBackendPool' + properties: { + backendAddresses: [ + { + ipAddress: '10.0.0.4' + } + ] + } + } + ] + backendHttpSettingsCollection: [ + { + name: 'appServiceBackendHttpsSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: true + port: 443 + protocol: 'Https' + requestTimeout: 30 + } + } + { + name: 'privateVmHttpSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: false + port: 80 + probe: { + id: '${appGWExpectedResourceID}/probes/privateVmHttpSettingProbe' + } + protocol: 'Http' + requestTimeout: 30 + } + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + enableHttp2: true + privateLinkConfigurations: [ + { + name: 'pvtlink01' + id: '${appGWExpectedResourceID}/privateLinkConfigurations/pvtlink01' + properties: { + ipConfigurations: [ + { + name: 'privateLinkIpConfig1' + id: '${appGWExpectedResourceID}/privateLinkConfigurations/pvtlink01/ipConfigurations/privateLinkIpConfig1' + properties: { + privateIPAllocationMethod: 'Dynamic' + primary: false + subnet: { + id: nestedDependencies.outputs.privateLinkSubnetResourceId + } + } + } + ] + } + } + ] + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + service: 'public' + subnetResourceId: nestedDependencies.outputs.privateLinkSubnetResourceId + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + frontendIPConfigurations: [ + { + name: 'private' + properties: { + privateIPAddress: '10.0.0.20' + privateIPAllocationMethod: 'Static' + subnet: { + id: nestedDependencies.outputs.defaultSubnetResourceId + } + } + } + { + name: 'public' + properties: { + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: nestedDependencies.outputs.publicIPResourceId + } + privateLinkConfiguration: { + id: '${appGWExpectedResourceID}/privateLinkConfigurations/pvtlink01' + } + } + } + ] + frontendPorts: [ + { + name: 'port443' + properties: { + port: 443 + } + } + { + name: 'port4433' + properties: { + port: 4433 + } + } + { + name: 'port80' + properties: { + port: 80 + } + } + { + name: 'port8080' + properties: { + port: 8080 + } + } + ] + gatewayIPConfigurations: [ + { + name: 'apw-ip-configuration' + properties: { + subnet: { + id: nestedDependencies.outputs.defaultSubnetResourceId + } + } + } + ] + httpListeners: [ + { + name: 'public443' + properties: { + frontendIPConfiguration: { + id: '${appGWExpectedResourceID}/frontendIPConfigurations/public' + } + frontendPort: { + id: '${appGWExpectedResourceID}/frontendPorts/port443' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '${appGWExpectedResourceID}/sslCertificates/${namePrefix}-az-apgw-x-001-ssl-certificate' + } + } + } + { + name: 'private4433' + properties: { + frontendIPConfiguration: { + id: '${appGWExpectedResourceID}/frontendIPConfigurations/private' + } + frontendPort: { + id: '${appGWExpectedResourceID}/frontendPorts/port4433' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '${appGWExpectedResourceID}/sslCertificates/${namePrefix}-az-apgw-x-001-ssl-certificate' + } + } + } + { + name: 'httpRedirect80' + properties: { + frontendIPConfiguration: { + id: '${appGWExpectedResourceID}/frontendIPConfigurations/public' + } + frontendPort: { + id: '${appGWExpectedResourceID}/frontendPorts/port80' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } + { + name: 'httpRedirect8080' + properties: { + frontendIPConfiguration: { + id: '${appGWExpectedResourceID}/frontendIPConfigurations/private' + } + frontendPort: { + id: '${appGWExpectedResourceID}/frontendPorts/port8080' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + probes: [ + { + name: 'privateVmHttpSettingProbe' + properties: { + host: '10.0.0.4' + interval: 60 + match: { + statusCodes: [ + '200' + '401' + ] + } + minServers: 3 + path: '/' + pickHostNameFromBackendHttpSettings: false + protocol: 'Http' + timeout: 15 + unhealthyThreshold: 5 + } + } + ] + redirectConfigurations: [ + { + name: 'httpRedirect80' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '${appGWExpectedResourceID}/requestRoutingRules/httpRedirect80-public443' + } + ] + targetListener: { + id: '${appGWExpectedResourceID}/httpListeners/public443' + } + } + } + { + name: 'httpRedirect8080' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '${appGWExpectedResourceID}/requestRoutingRules/httpRedirect8080-private4433' + } + ] + targetListener: { + id: '${appGWExpectedResourceID}/httpListeners/private4433' + } + } + } + ] + requestRoutingRules: [ + { + name: 'public443-appServiceBackendHttpsSetting-appServiceBackendHttpsSetting' + properties: { + backendAddressPool: { + id: '${appGWExpectedResourceID}/backendAddressPools/appServiceBackendPool' + } + backendHttpSettings: { + id: '${appGWExpectedResourceID}/backendHttpSettingsCollection/appServiceBackendHttpsSetting' + } + httpListener: { + id: '${appGWExpectedResourceID}/httpListeners/public443' + } + priority: 200 + ruleType: 'Basic' + } + } + { + name: 'private4433-privateVmHttpSetting-privateVmHttpSetting' + properties: { + backendAddressPool: { + id: '${appGWExpectedResourceID}/backendAddressPools/privateVmBackendPool' + } + backendHttpSettings: { + id: '${appGWExpectedResourceID}/backendHttpSettingsCollection/privateVmHttpSetting' + } + httpListener: { + id: '${appGWExpectedResourceID}/httpListeners/private4433' + } + priority: 250 + ruleType: 'Basic' + } + } + { + name: 'httpRedirect80-public443' + properties: { + httpListener: { + id: '${appGWExpectedResourceID}/httpListeners/httpRedirect80' + } + priority: 300 + redirectConfiguration: { + id: '${appGWExpectedResourceID}/redirectConfigurations/httpRedirect80' + } + ruleType: 'Basic' + } + } + { + name: 'httpRedirect8080-private4433' + properties: { + httpListener: { + id: '${appGWExpectedResourceID}/httpListeners/httpRedirect8080' + } + priority: 350 + redirectConfiguration: { + id: '${appGWExpectedResourceID}/redirectConfigurations/httpRedirect8080' + } + ruleType: 'Basic' + rewriteRuleSet: { + id: '${appGWExpectedResourceID}/rewriteRuleSets/customRewrite' + } + } + } + ] + roleAssignments: [ + { + name: '97fc1da9-bfe4-409d-b17a-da9a82fad0d0' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + sku: 'WAF_v2' + sslCertificates: [ + { + name: '${namePrefix}-az-apgw-x-001-ssl-certificate' + properties: { + keyVaultSecretId: nestedDependencies.outputs.certificateSecretUrl + } + } + ] + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + rewriteRuleSets: [ + { + name: 'customRewrite' + id: '${appGWExpectedResourceID}/rewriteRuleSets/customRewrite' + properties: { + rewriteRules: [ + { + ruleSequence: 100 + conditions: [] + name: 'NewRewrite' + actionSet: { + requestHeaderConfigurations: [ + { + headerName: 'Content-Type' + headerValue: 'JSON' + } + { + headerName: 'someheader' + } + ] + responseHeaderConfigurations: [] + } + } + ] + } + } + ] + webApplicationFirewallConfiguration: { + enabled: true + fileUploadLimitInMb: 100 + firewallMode: 'Detection' + maxRequestBodySizeInKb: 128 + requestBodyCheck: true + ruleSetType: 'OWASP' + ruleSetVersion: '3.0' + disabledRuleGroups: [ + { + ruleGroupName: 'Known-CVEs' + } + { + ruleGroupName: 'REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION' + } + { + ruleGroupName: 'REQUEST-941-APPLICATION-ATTACK-XSS' + } + ] + exclusions: [ + { + matchVariable: 'RequestHeaderNames' + selectorMatchOperator: 'StartsWith' + selector: 'hola' + } + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/application-gateway/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/application-gateway/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..4900c0e7d --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,175 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +@description('Required. The name of the Firewall Policy to create.') +param fwPolicyName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Deployment Script to create for the Certificate generation.') +param certDeploymentScriptName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + } + } + { + name: 'privateLinkSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 1) + privateLinkServiceNetworkPolicies: 'Disabled' + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.appgateway.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource publicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } +} + +resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${managedIdentity.name}-KeyVault-Admin-RoleAssignment') + scope: keyVault + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '00482a5a-887f-4fb3-b363-3b7fe8e74483' + ) // Key Vault Administrator + principalType: 'ServicePrincipal' + } +} + +resource certDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: certDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '8.0' + retentionInterval: 'P1D' + arguments: '-KeyVaultName "${keyVault.name}" -CertName "applicationGatewaySslCertificate"' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Set-CertificateInKeyVault.ps1') + } +} + +resource applicationGatewayWAFPolicy 'Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies@2022-11-01' = { + name: fwPolicyName + location: location + properties: { + managedRules: { + managedRuleSets: [ + { + ruleSetType: 'OWASP' + ruleSetVersion: '3.2' + } + ] + } + } +} + +@description('The resource ID of the created Virtual Network default subnet.') +output defaultSubnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Virtual Network private link subnet.') +output privateLinkSubnetResourceId string = virtualNetwork.properties.subnets[1].id + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The URL of the created certificate.') +output certificateSecretUrl string = certDeploymentScript.properties.outputs.secretUrl + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The resource ID of the created Application Gateway Web Application Firewall Policy.') +output fwPolicyResourceId string = applicationGatewayWAFPolicy.id diff --git a/avm/1.1.0/res/network/application-gateway/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/application-gateway/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..85265d7cb --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,478 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.applicationgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nagwaf' + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableTelemetry bool = true + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + fwPolicyName: 'dep-${namePrefix}-fwp-${serviceShort}' + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + certDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +var appGWName = '${namePrefix}${serviceShort}001' +var appGWExpectedResourceID = '${resourceGroup.id}/providers/Microsoft.Network/applicationGateways/${appGWName}' +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + enableTelemetry: enableTelemetry + name: appGWName + backendAddressPools: [ + { + name: 'appServiceBackendPool' + properties: { + backendAddresses: [ + { + fqdn: 'aghapp.azurewebsites.net' + } + ] + } + } + { + name: 'privateVmBackendPool' + properties: { + backendAddresses: [ + { + ipAddress: '10.0.0.4' + } + ] + } + } + ] + backendHttpSettingsCollection: [ + { + name: 'appServiceBackendHttpsSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: true + port: 443 + protocol: 'Https' + requestTimeout: 30 + } + } + { + name: 'privateVmHttpSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: false + port: 80 + probe: { + id: '${appGWExpectedResourceID}/probes/privateVmHttpSettingProbe' + } + protocol: 'Http' + requestTimeout: 30 + } + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + enableHttp2: true + privateLinkConfigurations: [ + { + name: 'pvtlink01' + id: '${appGWExpectedResourceID}/privateLinkConfigurations/pvtlink01' + properties: { + ipConfigurations: [ + { + name: 'privateLinkIpConfig1' + id: '${appGWExpectedResourceID}/privateLinkConfigurations/pvtlink01/ipConfigurations/privateLinkIpConfig1' + properties: { + privateIPAllocationMethod: 'Dynamic' + primary: false + subnet: { + id: nestedDependencies.outputs.privateLinkSubnetResourceId + } + } + } + ] + } + } + ] + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + service: 'public' + subnetResourceId: nestedDependencies.outputs.privateLinkSubnetResourceId + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + frontendIPConfigurations: [ + { + name: 'private' + properties: { + privateIPAddress: '10.0.0.20' + privateIPAllocationMethod: 'Static' + subnet: { + id: nestedDependencies.outputs.defaultSubnetResourceId + } + } + } + { + name: 'public' + properties: { + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: nestedDependencies.outputs.publicIPResourceId + } + privateLinkConfiguration: { + id: '${appGWExpectedResourceID}/privateLinkConfigurations/pvtlink01' + } + } + } + ] + frontendPorts: [ + { + name: 'port443' + properties: { + port: 443 + } + } + { + name: 'port4433' + properties: { + port: 4433 + } + } + { + name: 'port80' + properties: { + port: 80 + } + } + { + name: 'port8080' + properties: { + port: 8080 + } + } + ] + gatewayIPConfigurations: [ + { + name: 'apw-ip-configuration' + properties: { + subnet: { + id: nestedDependencies.outputs.defaultSubnetResourceId + } + } + } + ] + httpListeners: [ + { + name: 'public443' + properties: { + frontendIPConfiguration: { + id: '${appGWExpectedResourceID}/frontendIPConfigurations/public' + } + frontendPort: { + id: '${appGWExpectedResourceID}/frontendPorts/port443' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '${appGWExpectedResourceID}/sslCertificates/${namePrefix}-az-apgw-x-001-ssl-certificate' + } + } + } + { + name: 'private4433' + properties: { + frontendIPConfiguration: { + id: '${appGWExpectedResourceID}/frontendIPConfigurations/private' + } + frontendPort: { + id: '${appGWExpectedResourceID}/frontendPorts/port4433' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '${appGWExpectedResourceID}/sslCertificates/${namePrefix}-az-apgw-x-001-ssl-certificate' + } + } + } + { + name: 'httpRedirect80' + properties: { + frontendIPConfiguration: { + id: '${appGWExpectedResourceID}/frontendIPConfigurations/public' + } + frontendPort: { + id: '${appGWExpectedResourceID}/frontendPorts/port80' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } + { + name: 'httpRedirect8080' + properties: { + frontendIPConfiguration: { + id: '${appGWExpectedResourceID}/frontendIPConfigurations/private' + } + frontendPort: { + id: '${appGWExpectedResourceID}/frontendPorts/port8080' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + probes: [ + { + name: 'privateVmHttpSettingProbe' + properties: { + host: '10.0.0.4' + interval: 60 + match: { + statusCodes: [ + '200' + '401' + ] + } + minServers: 3 + path: '/' + pickHostNameFromBackendHttpSettings: false + protocol: 'Http' + timeout: 15 + unhealthyThreshold: 5 + } + } + ] + redirectConfigurations: [ + { + name: 'httpRedirect80' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '${appGWExpectedResourceID}/requestRoutingRules/httpRedirect80-public443' + } + ] + targetListener: { + id: '${appGWExpectedResourceID}/httpListeners/public443' + } + } + } + { + name: 'httpRedirect8080' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '${appGWExpectedResourceID}/requestRoutingRules/httpRedirect8080-private4433' + } + ] + targetListener: { + id: '${appGWExpectedResourceID}/httpListeners/private4433' + } + } + } + ] + requestRoutingRules: [ + { + name: 'public443-appServiceBackendHttpsSetting-appServiceBackendHttpsSetting' + properties: { + backendAddressPool: { + id: '${appGWExpectedResourceID}/backendAddressPools/appServiceBackendPool' + } + backendHttpSettings: { + id: '${appGWExpectedResourceID}/backendHttpSettingsCollection/appServiceBackendHttpsSetting' + } + httpListener: { + id: '${appGWExpectedResourceID}/httpListeners/public443' + } + priority: 200 + ruleType: 'Basic' + } + } + { + name: 'private4433-privateVmHttpSetting-privateVmHttpSetting' + properties: { + backendAddressPool: { + id: '${appGWExpectedResourceID}/backendAddressPools/privateVmBackendPool' + } + backendHttpSettings: { + id: '${appGWExpectedResourceID}/backendHttpSettingsCollection/privateVmHttpSetting' + } + httpListener: { + id: '${appGWExpectedResourceID}/httpListeners/private4433' + } + priority: 250 + ruleType: 'Basic' + } + } + { + name: 'httpRedirect80-public443' + properties: { + httpListener: { + id: '${appGWExpectedResourceID}/httpListeners/httpRedirect80' + } + priority: 300 + redirectConfiguration: { + id: '${appGWExpectedResourceID}/redirectConfigurations/httpRedirect80' + } + ruleType: 'Basic' + } + } + { + name: 'httpRedirect8080-private4433' + properties: { + httpListener: { + id: '${appGWExpectedResourceID}/httpListeners/httpRedirect8080' + } + priority: 350 + redirectConfiguration: { + id: '${appGWExpectedResourceID}/redirectConfigurations/httpRedirect8080' + } + ruleType: 'Basic' + rewriteRuleSet: { + id: '${appGWExpectedResourceID}/rewriteRuleSets/customRewrite' + } + } + } + ] + sku: 'WAF_v2' + sslCertificates: [ + { + name: '${namePrefix}-az-apgw-x-001-ssl-certificate' + properties: { + keyVaultSecretId: nestedDependencies.outputs.certificateSecretUrl + } + } + ] + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + rewriteRuleSets: [ + { + name: 'customRewrite' + id: '${appGWExpectedResourceID}/rewriteRuleSets/customRewrite' + properties: { + rewriteRules: [ + { + ruleSequence: 100 + conditions: [] + name: 'NewRewrite' + actionSet: { + requestHeaderConfigurations: [ + { + headerName: 'Content-Type' + headerValue: 'JSON' + } + { + headerName: 'someheader' + } + ] + responseHeaderConfigurations: [] + } + } + ] + } + } + ] + firewallPolicyResourceId: nestedDependencies.outputs.fwPolicyResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/application-gateway/version.json b/avm/1.1.0/res/network/application-gateway/version.json new file mode 100644 index 000000000..a8eda3102 --- /dev/null +++ b/avm/1.1.0/res/network/application-gateway/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/application-security-group/README.md b/avm/1.1.0/res/network/application-security-group/README.md new file mode 100644 index 000000000..7ef8c039c --- /dev/null +++ b/avm/1.1.0/res/network/application-security-group/README.md @@ -0,0 +1,544 @@ +# Application Security Groups (ASG) `[Microsoft.Network/applicationSecurityGroups]` + +This module deploys an Application Security Group (ASG). + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/applicationSecurityGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/applicationSecurityGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/application-security-group:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module applicationSecurityGroup 'br/public:avm/res/network/application-security-group:' = { + name: 'applicationSecurityGroupDeployment' + params: { + // Required parameters + name: 'nasgmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nasgmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-security-group:' + +// Required parameters +param name = 'nasgmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module applicationSecurityGroup 'br/public:avm/res/network/application-security-group:' = { + name: 'applicationSecurityGroupDeployment' + params: { + // Required parameters + name: 'nasgmax001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'e9e73878-302e-4e67-a2f8-981ea073bdf7' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nasgmax001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "e9e73878-302e-4e67-a2f8-981ea073bdf7", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-security-group:' + +// Required parameters +param name = 'nasgmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'e9e73878-302e-4e67-a2f8-981ea073bdf7' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module applicationSecurityGroup 'br/public:avm/res/network/application-security-group:' = { + name: 'applicationSecurityGroupDeployment' + params: { + // Required parameters + name: 'nasgwaf001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nasgwaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-security-group:' + +// Required parameters +param name = 'nasgwaf001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Application Security Group. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `name` + +Name of the Application Security Group. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the application security group. | +| `resourceGroupName` | string | The resource group the application security group was deployed into. | +| `resourceId` | string | The resource ID of the application security group. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/application-security-group/main.bicep b/avm/1.1.0/res/network/application-security-group/main.bicep new file mode 100644 index 000000000..5836e6c9e --- /dev/null +++ b/avm/1.1.0/res/network/application-security-group/main.bicep @@ -0,0 +1,152 @@ +metadata name = 'Application Security Groups (ASG)' +metadata description = 'This module deploys an Application Security Group (ASG).' + +@description('Required. Name of the Application Security Group.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-applicationsecuritygroup.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource applicationSecurityGroup 'Microsoft.Network/applicationSecurityGroups@2023-04-01' = { + name: name + location: location + tags: tags + properties: {} +} + +resource applicationSecurityGroup_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: applicationSecurityGroup +} + +resource applicationSecurityGroup_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + applicationSecurityGroup.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: applicationSecurityGroup + } +] + +@description('The resource group the application security group was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the application security group.') +output resourceId string = applicationSecurityGroup.id + +@description('The name of the application security group.') +output name string = applicationSecurityGroup.name + +@description('The location the resource was deployed into.') +output location string = applicationSecurityGroup.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/application-security-group/main.json b/avm/1.1.0/res/network/application-security-group/main.json new file mode 100644 index 000000000..3a15653ac --- /dev/null +++ b/avm/1.1.0/res/network/application-security-group/main.json @@ -0,0 +1,267 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "14461226239540891268" + }, + "name": "Application Security Groups (ASG)", + "description": "This module deploys an Application Security Group (ASG)." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application Security Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-applicationsecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "applicationSecurityGroup": { + "type": "Microsoft.Network/applicationSecurityGroups", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + }, + "applicationSecurityGroup_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/applicationSecurityGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "applicationSecurityGroup" + ] + }, + "applicationSecurityGroup_roleAssignments": { + "copy": { + "name": "applicationSecurityGroup_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/applicationSecurityGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/applicationSecurityGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "applicationSecurityGroup" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application security group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application security group." + }, + "value": "[resourceId('Microsoft.Network/applicationSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the application security group." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('applicationSecurityGroup', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/application-security-group/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/application-security-group/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..1a8be9a7d --- /dev/null +++ b/avm/1.1.0/res/network/application-security-group/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.applicationsecuritygroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nasgmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/network/application-security-group/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/application-security-group/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/network/application-security-group/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/application-security-group/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/application-security-group/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..f3151ede4 --- /dev/null +++ b/avm/1.1.0/res/network/application-security-group/tests/e2e/max/main.test.bicep @@ -0,0 +1,88 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.applicationsecuritygroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nasgmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'e9e73878-302e-4e67-a2f8-981ea073bdf7' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/application-security-group/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/application-security-group/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..ba74bf982 --- /dev/null +++ b/avm/1.1.0/res/network/application-security-group/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,57 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.applicationsecuritygroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nasgwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/application-security-group/version.json b/avm/1.1.0/res/network/application-security-group/version.json new file mode 100644 index 000000000..1c035df49 --- /dev/null +++ b/avm/1.1.0/res/network/application-security-group/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.2", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/azure-firewall/README.md b/avm/1.1.0/res/network/azure-firewall/README.md new file mode 100644 index 000000000..f4ac900c4 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/README.md @@ -0,0 +1,2949 @@ +# Azure Firewalls `[Microsoft.Network/azureFirewalls]` + +This module deploys an Azure Firewall. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/azureFirewalls` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-01-01/azureFirewalls) | +| `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/azure-firewall:`. + +- [Add-PIP](#example-1-add-pip) +- [Basic SKU](#example-2-basic-sku) +- [Custom-PIP](#example-3-custom-pip) +- [Using only defaults](#example-4-using-only-defaults) +- [Hub-commom](#example-5-hub-commom) +- [Hub-min](#example-6-hub-min) +- [Using large parameter set](#example-7-using-large-parameter-set) +- [Public-IP-Prefix](#example-8-public-ip-prefix) +- [Forced tunneling](#example-9-forced-tunneling) +- [WAF-aligned](#example-10-waf-aligned) + +### Example 1: _Add-PIP_ + +This instance deploys the module and attaches an existing public IP address. + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'nafaddpip001' + // Non-required parameters + additionalPublicIpConfigurations: [ + { + name: 'ipConfig01' + publicIPAddressResourceId: '' + } + ] + azureSkuTier: 'Basic' + location: '' + managementIPAddressObject: { + publicIPAllocationMethod: 'Static' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + } + virtualNetworkResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nafaddpip001" + }, + // Non-required parameters + "additionalPublicIpConfigurations": { + "value": [ + { + "name": "ipConfig01", + "publicIPAddressResourceId": "" + } + ] + }, + "azureSkuTier": { + "value": "Basic" + }, + "location": { + "value": "" + }, + "managementIPAddressObject": { + "value": { + "publicIPAllocationMethod": "Static", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ] + } + }, + "virtualNetworkResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafaddpip001' +// Non-required parameters +param additionalPublicIpConfigurations = [ + { + name: 'ipConfig01' + publicIPAddressResourceId: '' + } +] +param azureSkuTier = 'Basic' +param location = '' +param managementIPAddressObject = { + publicIPAllocationMethod: 'Static' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] +} +param virtualNetworkResourceId = '' +``` + +
+

+ +### Example 2: _Basic SKU_ + +This instance deploys the module with the Basic SKU. + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'nafbasic001' + // Non-required parameters + azureSkuTier: 'Basic' + location: '' + networkRuleCollections: [] + threatIntelMode: 'Deny' + virtualNetworkResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nafbasic001" + }, + // Non-required parameters + "azureSkuTier": { + "value": "Basic" + }, + "location": { + "value": "" + }, + "networkRuleCollections": { + "value": [] + }, + "threatIntelMode": { + "value": "Deny" + }, + "virtualNetworkResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafbasic001' +// Non-required parameters +param azureSkuTier = 'Basic' +param location = '' +param networkRuleCollections = [] +param threatIntelMode = 'Deny' +param virtualNetworkResourceId = '' +``` + +
+

+ +### Example 3: _Custom-PIP_ + +This instance deploys the module and will create a public IP address. + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'nafcstpip001' + // Non-required parameters + location: '' + publicIPAddressObject: { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'new-pip-nafcstpip' + publicIPAllocationMethod: 'Static' + publicIPPrefixResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + skuName: 'Standard' + skuTier: 'Regional' + } + virtualNetworkResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nafcstpip001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "publicIPAddressObject": { + "value": { + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "name": "new-pip-nafcstpip", + "publicIPAllocationMethod": "Static", + "publicIPPrefixResourceId": "", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "skuName": "Standard", + "skuTier": "Regional" + } + }, + "virtualNetworkResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafcstpip001' +// Non-required parameters +param location = '' +param publicIPAddressObject = { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'new-pip-nafcstpip' + publicIPAllocationMethod: 'Static' + publicIPPrefixResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + skuName: 'Standard' + skuTier: 'Regional' +} +param virtualNetworkResourceId = '' +``` + +
+

+ +### Example 4: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'nafmin001' + // Non-required parameters + location: '' + virtualNetworkResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nafmin001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "virtualNetworkResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafmin001' +// Non-required parameters +param location = '' +param virtualNetworkResourceId = '' +``` + +
+

+ +### Example 5: _Hub-commom_ + +This instance deploys the module a vWAN in a typical hub setting. + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'nafhubcom001' + // Non-required parameters + firewallPolicyId: '' + hubIPAddresses: { + publicIPs: { + count: 1 + } + } + location: '' + virtualHubId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nafhubcom001" + }, + // Non-required parameters + "firewallPolicyId": { + "value": "" + }, + "hubIPAddresses": { + "value": { + "publicIPs": { + "count": 1 + } + } + }, + "location": { + "value": "" + }, + "virtualHubId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafhubcom001' +// Non-required parameters +param firewallPolicyId = '' +param hubIPAddresses = { + publicIPs: { + count: 1 + } +} +param location = '' +param virtualHubId = '' +``` + +
+

+ +### Example 6: _Hub-min_ + +This instance deploys the module a vWAN minimum hub setting. + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'nafhubmin001' + // Non-required parameters + hubIPAddresses: { + publicIPs: { + count: 1 + } + } + location: '' + virtualHubId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nafhubmin001" + }, + // Non-required parameters + "hubIPAddresses": { + "value": { + "publicIPs": { + "count": 1 + } + } + }, + "location": { + "value": "" + }, + "virtualHubId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafhubmin001' +// Non-required parameters +param hubIPAddresses = { + publicIPs: { + count: 1 + } +} +param location = '' +param virtualHubId = '' +``` + +
+

+ +### Example 7: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'nafmax001' + // Non-required parameters + applicationRuleCollections: [ + { + name: 'allow-app-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + fqdnTags: [ + 'AppServiceEnvironment' + 'WindowsUpdate' + ] + name: 'allow-ase-tags' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + } + { + name: 'allow-ase-management' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + targetFqdns: [ + 'bing.com' + ] + } + ] + } + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + networkRuleCollections: [ + { + name: 'allow-network-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationPorts: [ + '12000' + '123' + ] + name: 'allow-ntp' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + } + { + description: 'allow azure devops' + destinationAddresses: [ + 'AzureDevOps' + ] + destinationPorts: [ + '443' + ] + name: 'allow-azure-devops' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + } + ] + } + } + ] + publicIPResourceID: '' + roleAssignments: [ + { + name: '3a8da184-d6d8-4bea-b992-e27cc053ef21' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + virtualNetworkResourceId: '' + zones: [ + '1' + '2' + '3' + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nafmax001" + }, + // Non-required parameters + "applicationRuleCollections": { + "value": [ + { + "name": "allow-app-rules", + "properties": { + "action": { + "type": "Allow" + }, + "priority": 100, + "rules": [ + { + "fqdnTags": [ + "AppServiceEnvironment", + "WindowsUpdate" + ], + "name": "allow-ase-tags", + "protocols": [ + { + "port": 80, + "protocolType": "Http" + }, + { + "port": 443, + "protocolType": "Https" + } + ], + "sourceAddresses": [ + "*" + ] + }, + { + "name": "allow-ase-management", + "protocols": [ + { + "port": 80, + "protocolType": "Http" + }, + { + "port": 443, + "protocolType": "Https" + } + ], + "sourceAddresses": [ + "*" + ], + "targetFqdns": [ + "bing.com" + ] + } + ] + } + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "networkRuleCollections": { + "value": [ + { + "name": "allow-network-rules", + "properties": { + "action": { + "type": "Allow" + }, + "priority": 100, + "rules": [ + { + "destinationAddresses": [ + "*" + ], + "destinationPorts": [ + "12000", + "123" + ], + "name": "allow-ntp", + "protocols": [ + "Any" + ], + "sourceAddresses": [ + "*" + ] + }, + { + "description": "allow azure devops", + "destinationAddresses": [ + "AzureDevOps" + ], + "destinationPorts": [ + "443" + ], + "name": "allow-azure-devops", + "protocols": [ + "Any" + ], + "sourceAddresses": [ + "*" + ] + } + ] + } + } + ] + }, + "publicIPResourceID": { + "value": "" + }, + "roleAssignments": { + "value": [ + { + "name": "3a8da184-d6d8-4bea-b992-e27cc053ef21", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "virtualNetworkResourceId": { + "value": "" + }, + "zones": { + "value": [ + "1", + "2", + "3" + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafmax001' +// Non-required parameters +param applicationRuleCollections = [ + { + name: 'allow-app-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + fqdnTags: [ + 'AppServiceEnvironment' + 'WindowsUpdate' + ] + name: 'allow-ase-tags' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + } + { + name: 'allow-ase-management' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + targetFqdns: [ + 'bing.com' + ] + } + ] + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param networkRuleCollections = [ + { + name: 'allow-network-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationPorts: [ + '12000' + '123' + ] + name: 'allow-ntp' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + } + { + description: 'allow azure devops' + destinationAddresses: [ + 'AzureDevOps' + ] + destinationPorts: [ + '443' + ] + name: 'allow-azure-devops' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + } + ] + } + } +] +param publicIPResourceID = '' +param roleAssignments = [ + { + name: '3a8da184-d6d8-4bea-b992-e27cc053ef21' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param virtualNetworkResourceId = '' +param zones = [ + '1' + '2' + '3' +] +``` + +
+

+ +### Example 8: _Public-IP-Prefix_ + +This instance deploys the module and will use a public IP prefix. + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'nafpip001' + // Non-required parameters + azureSkuTier: 'Basic' + location: '' + managementIPAddressObject: { + managementIPAllocationMethod: 'Static' + managementIPPrefixResourceId: '' + name: 'managementIP01' + skuName: 'Standard' + skuTier: 'Regional' + } + publicIPAddressObject: { + name: 'publicIP01' + publicIPAllocationMethod: 'Static' + publicIPPrefixResourceId: '' + skuName: 'Standard' + skuTier: 'Regional' + } + virtualNetworkResourceId: '' + zones: [] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nafpip001" + }, + // Non-required parameters + "azureSkuTier": { + "value": "Basic" + }, + "location": { + "value": "" + }, + "managementIPAddressObject": { + "value": { + "managementIPAllocationMethod": "Static", + "managementIPPrefixResourceId": "", + "name": "managementIP01", + "skuName": "Standard", + "skuTier": "Regional" + } + }, + "publicIPAddressObject": { + "value": { + "name": "publicIP01", + "publicIPAllocationMethod": "Static", + "publicIPPrefixResourceId": "", + "skuName": "Standard", + "skuTier": "Regional" + } + }, + "virtualNetworkResourceId": { + "value": "" + }, + "zones": { + "value": [] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafpip001' +// Non-required parameters +param azureSkuTier = 'Basic' +param location = '' +param managementIPAddressObject = { + managementIPAllocationMethod: 'Static' + managementIPPrefixResourceId: '' + name: 'managementIP01' + skuName: 'Standard' + skuTier: 'Regional' +} +param publicIPAddressObject = { + name: 'publicIP01' + publicIPAllocationMethod: 'Static' + publicIPPrefixResourceId: '' + skuName: 'Standard' + skuTier: 'Regional' +} +param virtualNetworkResourceId = '' +param zones = [] +``` + +
+

+ +### Example 9: _Forced tunneling_ + +This instance deploys the module and sets up forced tunneling. + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'naftunn001' + // Non-required parameters + additionalPublicIpConfigurations: [ + { + name: 'ipConfig01' + publicIPAddressResourceId: '' + } + ] + azureSkuTier: 'Standard' + enableForcedTunneling: true + location: '' + managementIPAddressObject: { + publicIPAllocationMethod: 'Static' + } + virtualNetworkResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "naftunn001" + }, + // Non-required parameters + "additionalPublicIpConfigurations": { + "value": [ + { + "name": "ipConfig01", + "publicIPAddressResourceId": "" + } + ] + }, + "azureSkuTier": { + "value": "Standard" + }, + "enableForcedTunneling": { + "value": true + }, + "location": { + "value": "" + }, + "managementIPAddressObject": { + "value": { + "publicIPAllocationMethod": "Static" + } + }, + "virtualNetworkResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'naftunn001' +// Non-required parameters +param additionalPublicIpConfigurations = [ + { + name: 'ipConfig01' + publicIPAddressResourceId: '' + } +] +param azureSkuTier = 'Standard' +param enableForcedTunneling = true +param location = '' +param managementIPAddressObject = { + publicIPAllocationMethod: 'Static' +} +param virtualNetworkResourceId = '' +``` + +
+

+ +### Example 10: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'nafwaf001' + // Non-required parameters + applicationRuleCollections: [ + { + name: 'allow-app-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + fqdnTags: [ + 'AppServiceEnvironment' + 'WindowsUpdate' + ] + name: 'allow-ase-tags' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + } + { + name: 'allow-ase-management' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + targetFqdns: [ + 'bing.com' + ] + } + ] + } + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + networkRuleCollections: [ + { + name: 'allow-network-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationPorts: [ + '12000' + '123' + ] + name: 'allow-ntp' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + } + ] + } + } + ] + publicIPResourceID: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + virtualNetworkResourceId: '' + zones: [ + '1' + '2' + '3' + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nafwaf001" + }, + // Non-required parameters + "applicationRuleCollections": { + "value": [ + { + "name": "allow-app-rules", + "properties": { + "action": { + "type": "Allow" + }, + "priority": 100, + "rules": [ + { + "fqdnTags": [ + "AppServiceEnvironment", + "WindowsUpdate" + ], + "name": "allow-ase-tags", + "protocols": [ + { + "port": 80, + "protocolType": "Http" + }, + { + "port": 443, + "protocolType": "Https" + } + ], + "sourceAddresses": [ + "*" + ] + }, + { + "name": "allow-ase-management", + "protocols": [ + { + "port": 80, + "protocolType": "Http" + }, + { + "port": 443, + "protocolType": "Https" + } + ], + "sourceAddresses": [ + "*" + ], + "targetFqdns": [ + "bing.com" + ] + } + ] + } + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "networkRuleCollections": { + "value": [ + { + "name": "allow-network-rules", + "properties": { + "action": { + "type": "Allow" + }, + "priority": 100, + "rules": [ + { + "destinationAddresses": [ + "*" + ], + "destinationPorts": [ + "12000", + "123" + ], + "name": "allow-ntp", + "protocols": [ + "Any" + ], + "sourceAddresses": [ + "*" + ] + } + ] + } + } + ] + }, + "publicIPResourceID": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "virtualNetworkResourceId": { + "value": "" + }, + "zones": { + "value": [ + "1", + "2", + "3" + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafwaf001' +// Non-required parameters +param applicationRuleCollections = [ + { + name: 'allow-app-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + fqdnTags: [ + 'AppServiceEnvironment' + 'WindowsUpdate' + ] + name: 'allow-ase-tags' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + } + { + name: 'allow-ase-management' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + targetFqdns: [ + 'bing.com' + ] + } + ] + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param networkRuleCollections = [ + { + name: 'allow-network-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationPorts: [ + '12000' + '123' + ] + name: 'allow-ntp' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + } + ] + } + } +] +param publicIPResourceID = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param virtualNetworkResourceId = '' +param zones = [ + '1' + '2' + '3' +] +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Azure Firewall. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`hubIPAddresses`](#parameter-hubipaddresses) | object | IP addresses associated with AzureFirewall. Required if `virtualHubId` is supplied. | +| [`virtualHubId`](#parameter-virtualhubid) | string | The virtualHub resource ID to which the firewall belongs. Required if `virtualNetworkId` is empty. | +| [`virtualNetworkResourceId`](#parameter-virtualnetworkresourceid) | string | Shared services Virtual Network resource ID. The virtual network ID containing AzureFirewallSubnet. If a Public IP is not provided, then the Public IP that is created as part of this module will be applied with the subnet provided in this variable. Required if `virtualHubId` is empty. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`additionalPublicIpConfigurations`](#parameter-additionalpublicipconfigurations) | array | This is to add any additional Public IP configurations on top of the Public IP with subnet IP configuration. | +| [`applicationRuleCollections`](#parameter-applicationrulecollections) | array | Collection of application rule collections used by Azure Firewall. | +| [`azureSkuTier`](#parameter-azureskutier) | string | Tier of an Azure Firewall. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableForcedTunneling`](#parameter-enableforcedtunneling) | bool | Enable/Disable forced tunneling. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`firewallPolicyId`](#parameter-firewallpolicyid) | string | Resource ID of the Firewall Policy that should be attached. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managementIPAddressObject`](#parameter-managementipaddressobject) | object | Specifies the properties of the Management Public IP to create and be used by Azure Firewall. If it's not provided and managementIPResourceID is empty, a '-mip' suffix will be appended to the Firewall's name. | +| [`managementIPResourceID`](#parameter-managementipresourceid) | string | The Management Public IP resource ID to associate to the AzureFirewallManagementSubnet. If empty, then the Management Public IP that is created as part of this module will be applied to the AzureFirewallManagementSubnet. | +| [`natRuleCollections`](#parameter-natrulecollections) | array | Collection of NAT rule collections used by Azure Firewall. | +| [`networkRuleCollections`](#parameter-networkrulecollections) | array | Collection of network rule collections used by Azure Firewall. | +| [`publicIPAddressObject`](#parameter-publicipaddressobject) | object | Specifies the properties of the Public IP to create and be used by the Firewall, if no existing public IP was provided. | +| [`publicIPResourceID`](#parameter-publicipresourceid) | string | The Public IP resource ID to associate to the AzureFirewallSubnet. If empty, then the Public IP that is created as part of this module will be applied to the AzureFirewallSubnet. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the Azure Firewall resource. | +| [`threatIntelMode`](#parameter-threatintelmode) | string | The operation mode for Threat Intel. | +| [`zones`](#parameter-zones) | array | Zone numbers e.g. 1,2,3. | + +### Parameter: `name` + +Name of the Azure Firewall. + +- Required: Yes +- Type: string + +### Parameter: `hubIPAddresses` + +IP addresses associated with AzureFirewall. Required if `virtualHubId` is supplied. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateIPAddress`](#parameter-hubipaddressesprivateipaddress) | string | Private IP Address associated with AzureFirewall. | +| [`publicIPs`](#parameter-hubipaddressespublicips) | object | List of public IP addresses associated with AzureFirewall. | + +### Parameter: `hubIPAddresses.privateIPAddress` + +Private IP Address associated with AzureFirewall. + +- Required: No +- Type: string + +### Parameter: `hubIPAddresses.publicIPs` + +List of public IP addresses associated with AzureFirewall. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addresses`](#parameter-hubipaddressespublicipsaddresses) | array | The list of Public IP addresses associated with AzureFirewall or IP addresses to be retained. | +| [`count`](#parameter-hubipaddressespublicipscount) | int | Public IP address count. | + +### Parameter: `hubIPAddresses.publicIPs.addresses` + +The list of Public IP addresses associated with AzureFirewall or IP addresses to be retained. + +- Required: No +- Type: array + +### Parameter: `hubIPAddresses.publicIPs.count` + +Public IP address count. + +- Required: No +- Type: int + +### Parameter: `virtualHubId` + +The virtualHub resource ID to which the firewall belongs. Required if `virtualNetworkId` is empty. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `virtualNetworkResourceId` + +Shared services Virtual Network resource ID. The virtual network ID containing AzureFirewallSubnet. If a Public IP is not provided, then the Public IP that is created as part of this module will be applied with the subnet provided in this variable. Required if `virtualHubId` is empty. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `additionalPublicIpConfigurations` + +This is to add any additional Public IP configurations on top of the Public IP with subnet IP configuration. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `applicationRuleCollections` + +Collection of application rule collections used by Azure Firewall. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-applicationrulecollectionsname) | string | Name of the application rule collection. | +| [`properties`](#parameter-applicationrulecollectionsproperties) | object | Properties of the azure firewall application rule collection. | + +### Parameter: `applicationRuleCollections.name` + +Name of the application rule collection. + +- Required: Yes +- Type: string + +### Parameter: `applicationRuleCollections.properties` + +Properties of the azure firewall application rule collection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`action`](#parameter-applicationrulecollectionspropertiesaction) | object | The action type of a rule collection. | +| [`priority`](#parameter-applicationrulecollectionspropertiespriority) | int | Priority of the application rule collection. | +| [`rules`](#parameter-applicationrulecollectionspropertiesrules) | array | Collection of rules used by a application rule collection. | + +### Parameter: `applicationRuleCollections.properties.action` + +The action type of a rule collection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`type`](#parameter-applicationrulecollectionspropertiesactiontype) | string | The type of action. | + +### Parameter: `applicationRuleCollections.properties.action.type` + +The type of action. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Allow' + 'Deny' + ] + ``` + +### Parameter: `applicationRuleCollections.properties.priority` + +Priority of the application rule collection. + +- Required: Yes +- Type: int +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `applicationRuleCollections.properties.rules` + +Collection of rules used by a application rule collection. + +- Required: Yes +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-applicationrulecollectionspropertiesrulesname) | string | Name of the application rule. | +| [`protocols`](#parameter-applicationrulecollectionspropertiesrulesprotocols) | array | Array of ApplicationRuleProtocols. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-applicationrulecollectionspropertiesrulesdescription) | string | Description of the rule. | +| [`fqdnTags`](#parameter-applicationrulecollectionspropertiesrulesfqdntags) | array | List of FQDN Tags for this rule. | +| [`sourceAddresses`](#parameter-applicationrulecollectionspropertiesrulessourceaddresses) | array | List of source IP addresses for this rule. | +| [`sourceIpGroups`](#parameter-applicationrulecollectionspropertiesrulessourceipgroups) | array | List of source IpGroups for this rule. | +| [`targetFqdns`](#parameter-applicationrulecollectionspropertiesrulestargetfqdns) | array | List of FQDNs for this rule. | + +### Parameter: `applicationRuleCollections.properties.rules.name` + +Name of the application rule. + +- Required: Yes +- Type: string +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `applicationRuleCollections.properties.rules.protocols` + +Array of ApplicationRuleProtocols. + +- Required: Yes +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`protocolType`](#parameter-applicationrulecollectionspropertiesrulesprotocolsprotocoltype) | string | Protocol type. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`port`](#parameter-applicationrulecollectionspropertiesrulesprotocolsport) | int | Port number for the protocol. | + +### Parameter: `applicationRuleCollections.properties.rules.protocols.protocolType` + +Protocol type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Http' + 'Https' + 'Mssql' + ] + ``` +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `applicationRuleCollections.properties.rules.protocols.port` + +Port number for the protocol. + +- Required: No +- Type: int +- MinValue: 100 +- MaxValue: 64000 + +### Parameter: `applicationRuleCollections.properties.rules.description` + +Description of the rule. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `applicationRuleCollections.properties.rules.fqdnTags` + +List of FQDN Tags for this rule. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `applicationRuleCollections.properties.rules.sourceAddresses` + +List of source IP addresses for this rule. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `applicationRuleCollections.properties.rules.sourceIpGroups` + +List of source IpGroups for this rule. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `applicationRuleCollections.properties.rules.targetFqdns` + +List of FQDNs for this rule. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `azureSkuTier` + +Tier of an Azure Firewall. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Premium' + 'Standard' + ] + ``` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enableForcedTunneling` + +Enable/Disable forced tunneling. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `firewallPolicyId` + +Resource ID of the Firewall Policy that should be attached. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managementIPAddressObject` + +Specifies the properties of the Management Public IP to create and be used by Azure Firewall. If it's not provided and managementIPResourceID is empty, a '-mip' suffix will be appended to the Firewall's name. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `managementIPResourceID` + +The Management Public IP resource ID to associate to the AzureFirewallManagementSubnet. If empty, then the Management Public IP that is created as part of this module will be applied to the AzureFirewallManagementSubnet. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `natRuleCollections` + +Collection of NAT rule collections used by Azure Firewall. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-natrulecollectionsname) | string | Name of the NAT rule collection. | +| [`properties`](#parameter-natrulecollectionsproperties) | object | Properties of the azure firewall NAT rule collection. | + +### Parameter: `natRuleCollections.name` + +Name of the NAT rule collection. + +- Required: Yes +- Type: string + +### Parameter: `natRuleCollections.properties` + +Properties of the azure firewall NAT rule collection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`action`](#parameter-natrulecollectionspropertiesaction) | object | The action type of a NAT rule collection. | +| [`priority`](#parameter-natrulecollectionspropertiespriority) | int | Priority of the NAT rule collection. | +| [`rules`](#parameter-natrulecollectionspropertiesrules) | array | Collection of rules used by a NAT rule collection. | + +### Parameter: `natRuleCollections.properties.action` + +The action type of a NAT rule collection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`type`](#parameter-natrulecollectionspropertiesactiontype) | string | The type of action. | + +### Parameter: `natRuleCollections.properties.action.type` + +The type of action. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Dnat' + 'Snat' + ] + ``` + +### Parameter: `natRuleCollections.properties.priority` + +Priority of the NAT rule collection. + +- Required: Yes +- Type: int +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `natRuleCollections.properties.rules` + +Collection of rules used by a NAT rule collection. + +- Required: Yes +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-natrulecollectionspropertiesrulesname) | string | Name of the NAT rule. | +| [`protocols`](#parameter-natrulecollectionspropertiesrulesprotocols) | array | Array of AzureFirewallNetworkRuleProtocols applicable to this NAT rule. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-natrulecollectionspropertiesrulesdescription) | string | Description of the rule. | +| [`destinationAddresses`](#parameter-natrulecollectionspropertiesrulesdestinationaddresses) | array | List of destination IP addresses for this rule. Supports IP ranges, prefixes, and service tags. | +| [`destinationPorts`](#parameter-natrulecollectionspropertiesrulesdestinationports) | array | List of destination ports. | +| [`sourceAddresses`](#parameter-natrulecollectionspropertiesrulessourceaddresses) | array | List of source IP addresses for this rule. | +| [`sourceIpGroups`](#parameter-natrulecollectionspropertiesrulessourceipgroups) | array | List of source IpGroups for this rule. | +| [`translatedAddress`](#parameter-natrulecollectionspropertiesrulestranslatedaddress) | string | The translated address for this NAT rule. | +| [`translatedFqdn`](#parameter-natrulecollectionspropertiesrulestranslatedfqdn) | string | The translated FQDN for this NAT rule. | +| [`translatedPort`](#parameter-natrulecollectionspropertiesrulestranslatedport) | string | The translated port for this NAT rule. | + +### Parameter: `natRuleCollections.properties.rules.name` + +Name of the NAT rule. + +- Required: Yes +- Type: string +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `natRuleCollections.properties.rules.protocols` + +Array of AzureFirewallNetworkRuleProtocols applicable to this NAT rule. + +- Required: Yes +- Type: array +- Allowed: + ```Bicep + [ + 'Any' + 'ICMP' + 'TCP' + 'UDP' + ] + ``` +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `natRuleCollections.properties.rules.description` + +Description of the rule. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `natRuleCollections.properties.rules.destinationAddresses` + +List of destination IP addresses for this rule. Supports IP ranges, prefixes, and service tags. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `natRuleCollections.properties.rules.destinationPorts` + +List of destination ports. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `natRuleCollections.properties.rules.sourceAddresses` + +List of source IP addresses for this rule. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `natRuleCollections.properties.rules.sourceIpGroups` + +List of source IpGroups for this rule. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `natRuleCollections.properties.rules.translatedAddress` + +The translated address for this NAT rule. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `natRuleCollections.properties.rules.translatedFqdn` + +The translated FQDN for this NAT rule. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `natRuleCollections.properties.rules.translatedPort` + +The translated port for this NAT rule. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `networkRuleCollections` + +Collection of network rule collections used by Azure Firewall. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-networkrulecollectionsname) | string | Name of the network rule collection. | +| [`properties`](#parameter-networkrulecollectionsproperties) | object | Properties of the azure firewall network rule collection. | + +### Parameter: `networkRuleCollections.name` + +Name of the network rule collection. + +- Required: Yes +- Type: string + +### Parameter: `networkRuleCollections.properties` + +Properties of the azure firewall network rule collection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`action`](#parameter-networkrulecollectionspropertiesaction) | object | The action type of a rule collection. | +| [`priority`](#parameter-networkrulecollectionspropertiespriority) | int | Priority of the network rule collection. | +| [`rules`](#parameter-networkrulecollectionspropertiesrules) | array | Collection of rules used by a network rule collection. | + +### Parameter: `networkRuleCollections.properties.action` + +The action type of a rule collection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`type`](#parameter-networkrulecollectionspropertiesactiontype) | string | The type of action. | + +### Parameter: `networkRuleCollections.properties.action.type` + +The type of action. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Allow' + 'Deny' + ] + ``` + +### Parameter: `networkRuleCollections.properties.priority` + +Priority of the network rule collection. + +- Required: Yes +- Type: int +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `networkRuleCollections.properties.rules` + +Collection of rules used by a network rule collection. + +- Required: Yes +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-networkrulecollectionspropertiesrulesname) | string | Name of the network rule. | +| [`protocols`](#parameter-networkrulecollectionspropertiesrulesprotocols) | array | Array of AzureFirewallNetworkRuleProtocols. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-networkrulecollectionspropertiesrulesdescription) | string | Description of the rule. | +| [`destinationAddresses`](#parameter-networkrulecollectionspropertiesrulesdestinationaddresses) | array | List of destination IP addresses. | +| [`destinationFqdns`](#parameter-networkrulecollectionspropertiesrulesdestinationfqdns) | array | List of destination FQDNs. | +| [`destinationIpGroups`](#parameter-networkrulecollectionspropertiesrulesdestinationipgroups) | array | List of destination IP groups for this rule. | +| [`destinationPorts`](#parameter-networkrulecollectionspropertiesrulesdestinationports) | array | List of destination ports. | +| [`sourceAddresses`](#parameter-networkrulecollectionspropertiesrulessourceaddresses) | array | List of source IP addresses for this rule. | +| [`sourceIpGroups`](#parameter-networkrulecollectionspropertiesrulessourceipgroups) | array | List of source IpGroups for this rule. | + +### Parameter: `networkRuleCollections.properties.rules.name` + +Name of the network rule. + +- Required: Yes +- Type: string +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `networkRuleCollections.properties.rules.protocols` + +Array of AzureFirewallNetworkRuleProtocols. + +- Required: Yes +- Type: array +- Allowed: + ```Bicep + [ + 'Any' + 'ICMP' + 'TCP' + 'UDP' + ] + ``` +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `networkRuleCollections.properties.rules.description` + +Description of the rule. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `networkRuleCollections.properties.rules.destinationAddresses` + +List of destination IP addresses. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `networkRuleCollections.properties.rules.destinationFqdns` + +List of destination FQDNs. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `networkRuleCollections.properties.rules.destinationIpGroups` + +List of destination IP groups for this rule. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `networkRuleCollections.properties.rules.destinationPorts` + +List of destination ports. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `networkRuleCollections.properties.rules.sourceAddresses` + +List of source IP addresses for this rule. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `networkRuleCollections.properties.rules.sourceIpGroups` + +List of source IpGroups for this rule. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 65000 + +### Parameter: `publicIPAddressObject` + +Specifies the properties of the Public IP to create and be used by the Firewall, if no existing public IP was provided. + +- Required: No +- Type: object +- Default: + ```Bicep + { + name: '[format(\'{0}-pip\', parameters(\'name\'))]' + } + ``` + +### Parameter: `publicIPResourceID` + +The Public IP resource ID to associate to the AzureFirewallSubnet. If empty, then the Public IP that is created as part of this module will be applied to the AzureFirewallSubnet. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the Azure Firewall resource. + +- Required: No +- Type: object + +### Parameter: `threatIntelMode` + +The operation mode for Threat Intel. + +- Required: No +- Type: string +- Default: `'Deny'` +- Allowed: + ```Bicep + [ + 'Alert' + 'Deny' + 'Off' + ] + ``` + +### Parameter: `zones` + +Zone numbers e.g. 1,2,3. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `applicationRuleCollections` | array | List of Application Rule Collections used by Azure Firewall. | +| `ipConfAzureFirewallSubnet` | object | The Public IP configuration object for the Azure Firewall Subnet. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the Azure Firewall. | +| `natRuleCollections` | array | List of NAT rule collections used by Azure Firewall. | +| `networkRuleCollections` | array | List of Network Rule Collections used by Azure Firewall. | +| `privateIp` | string | The private IP of the Azure firewall. | +| `resourceGroupName` | string | The resource group the Azure firewall was deployed into. | +| `resourceId` | string | The resource ID of the Azure Firewall. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/public-ip-address:0.6.0` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/azure-firewall/main.bicep b/avm/1.1.0/res/network/azure-firewall/main.bicep new file mode 100644 index 000000000..f6f86143d --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/main.bicep @@ -0,0 +1,639 @@ +metadata name = 'Azure Firewalls' +metadata description = 'This module deploys an Azure Firewall.' + +@description('Required. Name of the Azure Firewall.') +param name string + +@description('Optional. Tier of an Azure Firewall.') +@allowed([ + 'Basic' + 'Standard' + 'Premium' +]) +param azureSkuTier string = 'Standard' + +@description('Conditional. Shared services Virtual Network resource ID. The virtual network ID containing AzureFirewallSubnet. If a Public IP is not provided, then the Public IP that is created as part of this module will be applied with the subnet provided in this variable. Required if `virtualHubId` is empty.') +param virtualNetworkResourceId string = '' + +@description('Optional. The Public IP resource ID to associate to the AzureFirewallSubnet. If empty, then the Public IP that is created as part of this module will be applied to the AzureFirewallSubnet.') +param publicIPResourceID string = '' + +@description('Optional. This is to add any additional Public IP configurations on top of the Public IP with subnet IP configuration.') +param additionalPublicIpConfigurations array = [] + +@description('Optional. Specifies the properties of the Public IP to create and be used by the Firewall, if no existing public IP was provided.') +param publicIPAddressObject object = { + name: '${name}-pip' +} + +@description('Optional. The Management Public IP resource ID to associate to the AzureFirewallManagementSubnet. If empty, then the Management Public IP that is created as part of this module will be applied to the AzureFirewallManagementSubnet.') +param managementIPResourceID string = '' + +@description('Optional. Specifies the properties of the Management Public IP to create and be used by Azure Firewall. If it\'s not provided and managementIPResourceID is empty, a \'-mip\' suffix will be appended to the Firewall\'s name.') +param managementIPAddressObject object = {} + +@description('Optional. Collection of application rule collections used by Azure Firewall.') +param applicationRuleCollections applicationRuleCollectionType + +@description('Optional. Collection of network rule collections used by Azure Firewall.') +param networkRuleCollections networkRuleCollectionType + +@description('Optional. Collection of NAT rule collections used by Azure Firewall.') +param natRuleCollections natRuleCollectionType + +@description('Optional. Resource ID of the Firewall Policy that should be attached.') +param firewallPolicyId string = '' + +@description('Conditional. IP addresses associated with AzureFirewall. Required if `virtualHubId` is supplied.') +param hubIPAddresses hubIPAddressesType? + +@description('Conditional. The virtualHub resource ID to which the firewall belongs. Required if `virtualNetworkId` is empty.') +param virtualHubId string = '' + +@allowed([ + 'Alert' + 'Deny' + 'Off' +]) +@description('Optional. The operation mode for Threat Intel.') +param threatIntelMode string = 'Deny' + +@description('Optional. Zone numbers e.g. 1,2,3.') +param zones array = [ + 1 + 2 + 3 +] + +@description('Optional. Enable/Disable forced tunneling.') +param enableForcedTunneling bool = false + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the Azure Firewall resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var azureSkuName = empty(virtualNetworkResourceId) ? 'AZFW_Hub' : 'AZFW_VNet' +var requiresManagementIp = (azureSkuTier == 'Basic' || enableForcedTunneling) ? true : false +var isCreateDefaultManagementIP = empty(managementIPResourceID) && requiresManagementIp + +// ---------------------------------------------------------------------------- +// Prep ipConfigurations object AzureFirewallSubnet for different uses cases: +// 1. Use existing Public IP +// 2. Use new Public IP created in this module +// 3. Do not use a Public IP if publicIPAddressObject is empty + +var additionalPublicIpConfigurationsVar = [ + for ipConfiguration in additionalPublicIpConfigurations: { + name: ipConfiguration.name + properties: { + publicIPAddress: contains(ipConfiguration, 'publicIPAddressResourceId') + ? { + id: ipConfiguration.publicIPAddressResourceId + } + : null + } + } +] +var ipConfigurations = concat( + [ + { + name: !empty(publicIPResourceID) ? last(split(publicIPResourceID, '/')) : publicIPAddress.outputs.name + properties: union( + { + subnet: { + id: '${virtualNetworkResourceId}/subnets/AzureFirewallSubnet' // The subnet name must be AzureFirewallSubnet + } + }, + (!empty(publicIPResourceID) || !empty(publicIPAddressObject)) + ? { + //Use existing Public IP, new Public IP created in this module, or none if neither + publicIPAddress: { + id: !empty(publicIPResourceID) ? publicIPResourceID : publicIPAddress.outputs.resourceId + } + } + : {} + ) + } + ], + additionalPublicIpConfigurationsVar +) + +// ---------------------------------------------------------------------------- +// Prep managementIPConfiguration object for different uses cases: +// 1. Use existing Management Public IP +// 2. Use new Management Public IP created in this module + +var managementIPConfiguration = { + name: !empty(managementIPResourceID) ? last(split(managementIPResourceID, '/')) : managementIPAddress.outputs.name + properties: { + subnet: { + id: '${virtualNetworkResourceId}/subnets/AzureFirewallManagementSubnet' // The subnet name must be AzureFirewallManagementSubnet for a 'Basic' SKU tier firewall + } + // Use existing Management Public IP, new Management Public IP created in this module, or none if neither + publicIPAddress: { + id: !empty(managementIPResourceID) ? managementIPResourceID : managementIPAddress.outputs.resourceId + } + } +} + +// ---------------------------------------------------------------------------- +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-azurefirewall.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.6.0' = if (empty(publicIPResourceID) && azureSkuName == 'AZFW_VNet') { + name: '${uniqueString(deployment().name, location)}-Firewall-PIP' + params: { + name: publicIPAddressObject.name + publicIpPrefixResourceId: contains(publicIPAddressObject, 'publicIPPrefixResourceId') + ? (!(empty(publicIPAddressObject.publicIPPrefixResourceId)) ? publicIPAddressObject.publicIPPrefixResourceId : '') + : '' + publicIPAllocationMethod: contains(publicIPAddressObject, 'publicIPAllocationMethod') + ? (!(empty(publicIPAddressObject.publicIPAllocationMethod)) + ? publicIPAddressObject.publicIPAllocationMethod + : 'Static') + : 'Static' + skuName: contains(publicIPAddressObject, 'skuName') + ? (!(empty(publicIPAddressObject.skuName)) ? publicIPAddressObject.skuName : 'Standard') + : 'Standard' + skuTier: contains(publicIPAddressObject, 'skuTier') + ? (!(empty(publicIPAddressObject.skuTier)) ? publicIPAddressObject.skuTier : 'Regional') + : 'Regional' + roleAssignments: contains(publicIPAddressObject, 'roleAssignments') + ? (!empty(publicIPAddressObject.roleAssignments) ? publicIPAddressObject.roleAssignments : []) + : [] + diagnosticSettings: publicIPAddressObject.?diagnosticSettings + location: location + lock: lock + tags: publicIPAddressObject.?tags ?? tags + zones: zones + enableTelemetry: publicIPAddressObject.?enableTelemetry ?? enableTelemetry + } +} + +// create a Management Public IP address if one is not provided and the flag is true +module managementIPAddress 'br/public:avm/res/network/public-ip-address:0.6.0' = if (isCreateDefaultManagementIP && azureSkuName == 'AZFW_VNet') { + name: '${uniqueString(deployment().name, location)}-Firewall-MIP' + params: { + name: contains(managementIPAddressObject, 'name') + ? (!(empty(managementIPAddressObject.name)) ? managementIPAddressObject.name : '${name}-mip') + : '${name}-mip' + publicIpPrefixResourceId: contains(managementIPAddressObject, 'managementIPPrefixResourceId') + ? (!(empty(managementIPAddressObject.managementIPPrefixResourceId)) + ? managementIPAddressObject.managementIPPrefixResourceId + : '') + : '' + publicIPAllocationMethod: contains(managementIPAddressObject, 'managementIPAllocationMethod') + ? (!(empty(managementIPAddressObject.managementIPAllocationMethod)) + ? managementIPAddressObject.managementIPAllocationMethod + : 'Static') + : 'Static' + skuName: contains(managementIPAddressObject, 'skuName') + ? (!(empty(managementIPAddressObject.skuName)) ? managementIPAddressObject.skuName : 'Standard') + : 'Standard' + skuTier: contains(managementIPAddressObject, 'skuTier') + ? (!(empty(managementIPAddressObject.skuTier)) ? managementIPAddressObject.skuTier : 'Regional') + : 'Regional' + roleAssignments: contains(managementIPAddressObject, 'roleAssignments') + ? (!empty(managementIPAddressObject.roleAssignments) ? managementIPAddressObject.roleAssignments : []) + : [] + diagnosticSettings: managementIPAddressObject.?diagnosticSettings + location: location + tags: managementIPAddressObject.?tags ?? tags + zones: zones + enableTelemetry: managementIPAddressObject.?enableTelemetry ?? enableTelemetry + } +} + +resource azureFirewall 'Microsoft.Network/azureFirewalls@2024-01-01' = { + name: name + location: location + zones: length(zones) == 0 ? null : zones + tags: tags + properties: azureSkuName == 'AZFW_VNet' + ? { + threatIntelMode: threatIntelMode + firewallPolicy: !empty(firewallPolicyId) + ? { + id: firewallPolicyId + } + : null + ipConfigurations: ipConfigurations + managementIpConfiguration: requiresManagementIp ? managementIPConfiguration : null + sku: { + name: azureSkuName + tier: azureSkuTier + } + applicationRuleCollections: applicationRuleCollections ?? [] + natRuleCollections: natRuleCollections ?? [] + networkRuleCollections: networkRuleCollections ?? [] + } + : { + firewallPolicy: !empty(firewallPolicyId) + ? { + id: firewallPolicyId + } + : null + sku: { + name: azureSkuName + tier: azureSkuTier + } + hubIPAddresses: !empty(hubIPAddresses) ? hubIPAddresses : null + virtualHub: !empty(virtualHubId) + ? { + id: virtualHubId + } + : null + } +} + +resource azureFirewall_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: azureFirewall +} + +resource azureFirewall_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: azureFirewall + } +] + +resource azureFirewall_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(azureFirewall.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: azureFirewall + } +] + +@description('The resource ID of the Azure Firewall.') +output resourceId string = azureFirewall.id + +@description('The name of the Azure Firewall.') +output name string = azureFirewall.name + +@description('The resource group the Azure firewall was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The private IP of the Azure firewall.') +output privateIp string = contains(azureFirewall.properties, 'ipConfigurations') + ? azureFirewall.properties.ipConfigurations[0].properties.privateIPAddress + : '' + +@description('The Public IP configuration object for the Azure Firewall Subnet.') +output ipConfAzureFirewallSubnet object = contains(azureFirewall.properties, 'ipConfigurations') + ? azureFirewall.properties.ipConfigurations[0] + : {} + +@description('List of Application Rule Collections used by Azure Firewall.') +output applicationRuleCollections array = applicationRuleCollections ?? [] + +@description('List of Network Rule Collections used by Azure Firewall.') +output networkRuleCollections array = networkRuleCollections ?? [] + +@description('List of NAT rule collections used by Azure Firewall.') +output natRuleCollections array = natRuleCollections ?? [] + +@description('The location the resource was deployed into.') +output location string = azureFirewall.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? + +type natRuleCollectionType = { + @description('Required. Name of the NAT rule collection.') + name: string + + @description('Required. Properties of the azure firewall NAT rule collection.') + properties: { + @description('Required. The action type of a NAT rule collection.') + action: { + @description('Required. The type of action.') + type: 'Dnat' | 'Snat' + } + + @description('Required. Priority of the NAT rule collection.') + @minValue(100) + @maxValue(65000) + priority: int + + @description('Required. Collection of rules used by a NAT rule collection.') + rules: { + @description('Required. Name of the NAT rule.') + name: string + + @description('Optional. Description of the rule.') + description: string? + + @description('Required. Array of AzureFirewallNetworkRuleProtocols applicable to this NAT rule.') + protocols: ('TCP' | 'UDP' | 'Any' | 'ICMP')[] + + @description('Optional. List of destination IP addresses for this rule. Supports IP ranges, prefixes, and service tags.') + destinationAddresses: string[]? + + @description('Optional. List of destination ports.') + destinationPorts: string[]? + + @description('Optional. List of source IP addresses for this rule.') + sourceAddresses: string[]? + + @description('Optional. List of source IpGroups for this rule.') + sourceIpGroups: string[]? + + @description('Optional. The translated address for this NAT rule.') + translatedAddress: string? + + @description('Optional. The translated FQDN for this NAT rule.') + translatedFqdn: string? + + @description('Optional. The translated port for this NAT rule.') + translatedPort: string? + }[] + } +}[]? + +type applicationRuleCollectionType = { + @description('Required. Name of the application rule collection.') + name: string + + @description('Required. Properties of the azure firewall application rule collection.') + properties: { + @description('Required. The action type of a rule collection.') + action: { + @description('Required. The type of action.') + type: 'Allow' | 'Deny' + } + + @description('Required. Priority of the application rule collection.') + @minValue(100) + @maxValue(65000) + priority: int + + @description('Required. Collection of rules used by a application rule collection.') + rules: { + @description('Required. Name of the application rule.') + name: string + + @description('Optional. Description of the rule.') + description: string? + + @description('Required. Array of ApplicationRuleProtocols.') + protocols: { + @description('Optional. Port number for the protocol.') + @maxValue(64000) + port: int? + + @description('Required. Protocol type.') + protocolType: 'Http' | 'Https' | 'Mssql' + }[] + + @description('Optional. List of FQDN Tags for this rule.') + fqdnTags: string[]? + + @description('Optional. List of FQDNs for this rule.') + targetFqdns: string[]? + + @description('Optional. List of source IP addresses for this rule.') + sourceAddresses: string[]? + + @description('Optional. List of source IpGroups for this rule.') + sourceIpGroups: string[]? + }[] + } +}[]? + +type networkRuleCollectionType = { + @description('Required. Name of the network rule collection.') + name: string + + @description('Required. Properties of the azure firewall network rule collection.') + properties: { + @description('Required. The action type of a rule collection.') + action: { + @description('Required. The type of action.') + type: 'Allow' | 'Deny' + } + + @description('Required. Priority of the network rule collection.') + @minValue(100) + @maxValue(65000) + priority: int + + @description('Required. Collection of rules used by a network rule collection.') + rules: { + @description('Required. Name of the network rule.') + name: string + + @description('Optional. Description of the rule.') + description: string? + + @description('Required. Array of AzureFirewallNetworkRuleProtocols.') + protocols: ('TCP' | 'UDP' | 'Any' | 'ICMP')[] + + @description('Optional. List of destination IP addresses.') + destinationAddresses: string[]? + + @description('Optional. List of destination FQDNs.') + destinationFqdns: string[]? + + @description('Optional. List of destination IP groups for this rule.') + destinationIpGroups: string[]? + + @description('Optional. List of destination ports.') + destinationPorts: string[]? + + @description('Optional. List of source IP addresses for this rule.') + sourceAddresses: string[]? + + @description('Optional. List of source IpGroups for this rule.') + sourceIpGroups: string[]? + }[] + } +}[]? + +type hubIPAddressesType = { + @description('Optional. Private IP Address associated with AzureFirewall.') + privateIPAddress: string? + @description('Optional. List of public IP addresses associated with AzureFirewall.') + publicIPs: { + @description('Optional. The list of Public IP addresses associated with AzureFirewall or IP addresses to be retained.') + addresses: [ + { + @description('Optional. Public IP.') + address: string? + } + ]? + @description('Optional. Public IP address count.') + count: int? + }? +} diff --git a/avm/1.1.0/res/network/azure-firewall/main.json b/avm/1.1.0/res/network/azure-firewall/main.json new file mode 100644 index 000000000..d2fe782ed --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/main.json @@ -0,0 +1,2407 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "8237462610300553734" + }, + "name": "Azure Firewalls", + "description": "This module deploys an Azure Firewall." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "natRuleCollectionType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the NAT rule collection." + } + }, + "properties": { + "type": "object", + "properties": { + "action": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "Dnat", + "Snat" + ], + "metadata": { + "description": "Required. The type of action." + } + } + }, + "metadata": { + "description": "Required. The action type of a NAT rule collection." + } + }, + "priority": { + "type": "int", + "minValue": 100, + "maxValue": 65000, + "metadata": { + "description": "Required. Priority of the NAT rule collection." + } + }, + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the NAT rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the rule." + } + }, + "protocols": { + "type": "array", + "allowedValues": [ + "Any", + "ICMP", + "TCP", + "UDP" + ], + "metadata": { + "description": "Required. Array of AzureFirewallNetworkRuleProtocols applicable to this NAT rule." + } + }, + "destinationAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination IP addresses for this rule. Supports IP ranges, prefixes, and service tags." + } + }, + "destinationPorts": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination ports." + } + }, + "sourceAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of source IP addresses for this rule." + } + }, + "sourceIpGroups": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of source IpGroups for this rule." + } + }, + "translatedAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The translated address for this NAT rule." + } + }, + "translatedFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The translated FQDN for this NAT rule." + } + }, + "translatedPort": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The translated port for this NAT rule." + } + } + } + }, + "metadata": { + "description": "Required. Collection of rules used by a NAT rule collection." + } + } + }, + "metadata": { + "description": "Required. Properties of the azure firewall NAT rule collection." + } + } + } + }, + "nullable": true + }, + "applicationRuleCollectionType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the application rule collection." + } + }, + "properties": { + "type": "object", + "properties": { + "action": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Required. The type of action." + } + } + }, + "metadata": { + "description": "Required. The action type of a rule collection." + } + }, + "priority": { + "type": "int", + "minValue": 100, + "maxValue": 65000, + "metadata": { + "description": "Required. Priority of the application rule collection." + } + }, + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the application rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the rule." + } + }, + "protocols": { + "type": "array", + "items": { + "type": "object", + "properties": { + "port": { + "type": "int", + "nullable": true, + "maxValue": 64000, + "metadata": { + "description": "Optional. Port number for the protocol." + } + }, + "protocolType": { + "type": "string", + "allowedValues": [ + "Http", + "Https", + "Mssql" + ], + "metadata": { + "description": "Required. Protocol type." + } + } + } + }, + "metadata": { + "description": "Required. Array of ApplicationRuleProtocols." + } + }, + "fqdnTags": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of FQDN Tags for this rule." + } + }, + "targetFqdns": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of FQDNs for this rule." + } + }, + "sourceAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of source IP addresses for this rule." + } + }, + "sourceIpGroups": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of source IpGroups for this rule." + } + } + } + }, + "metadata": { + "description": "Required. Collection of rules used by a application rule collection." + } + } + }, + "metadata": { + "description": "Required. Properties of the azure firewall application rule collection." + } + } + } + }, + "nullable": true + }, + "networkRuleCollectionType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the network rule collection." + } + }, + "properties": { + "type": "object", + "properties": { + "action": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Required. The type of action." + } + } + }, + "metadata": { + "description": "Required. The action type of a rule collection." + } + }, + "priority": { + "type": "int", + "minValue": 100, + "maxValue": 65000, + "metadata": { + "description": "Required. Priority of the network rule collection." + } + }, + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the network rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the rule." + } + }, + "protocols": { + "type": "array", + "allowedValues": [ + "Any", + "ICMP", + "TCP", + "UDP" + ], + "metadata": { + "description": "Required. Array of AzureFirewallNetworkRuleProtocols." + } + }, + "destinationAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination IP addresses." + } + }, + "destinationFqdns": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination FQDNs." + } + }, + "destinationIpGroups": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination IP groups for this rule." + } + }, + "destinationPorts": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination ports." + } + }, + "sourceAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of source IP addresses for this rule." + } + }, + "sourceIpGroups": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of source IpGroups for this rule." + } + } + } + }, + "metadata": { + "description": "Required. Collection of rules used by a network rule collection." + } + } + }, + "metadata": { + "description": "Required. Properties of the azure firewall network rule collection." + } + } + } + }, + "nullable": true + }, + "hubIPAddressesType": { + "type": "object", + "properties": { + "privateIPAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Private IP Address associated with AzureFirewall." + } + }, + "publicIPs": { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "prefixItems": [ + { + "type": "object", + "properties": { + "address": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Public IP." + } + } + } + } + ], + "items": false, + "nullable": true, + "metadata": { + "description": "Optional. The list of Public IP addresses associated with AzureFirewall or IP addresses to be retained." + } + }, + "count": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Public IP address count." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. List of public IP addresses associated with AzureFirewall." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure Firewall." + } + }, + "azureSkuTier": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Tier of an Azure Firewall." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. Shared services Virtual Network resource ID. The virtual network ID containing AzureFirewallSubnet. If a Public IP is not provided, then the Public IP that is created as part of this module will be applied with the subnet provided in this variable. Required if `virtualHubId` is empty." + } + }, + "publicIPResourceID": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Public IP resource ID to associate to the AzureFirewallSubnet. If empty, then the Public IP that is created as part of this module will be applied to the AzureFirewallSubnet." + } + }, + "additionalPublicIpConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. This is to add any additional Public IP configurations on top of the Public IP with subnet IP configuration." + } + }, + "publicIPAddressObject": { + "type": "object", + "defaultValue": { + "name": "[format('{0}-pip', parameters('name'))]" + }, + "metadata": { + "description": "Optional. Specifies the properties of the Public IP to create and be used by the Firewall, if no existing public IP was provided." + } + }, + "managementIPResourceID": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Management Public IP resource ID to associate to the AzureFirewallManagementSubnet. If empty, then the Management Public IP that is created as part of this module will be applied to the AzureFirewallManagementSubnet." + } + }, + "managementIPAddressObject": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Specifies the properties of the Management Public IP to create and be used by Azure Firewall. If it's not provided and managementIPResourceID is empty, a '-mip' suffix will be appended to the Firewall's name." + } + }, + "applicationRuleCollections": { + "$ref": "#/definitions/applicationRuleCollectionType", + "metadata": { + "description": "Optional. Collection of application rule collections used by Azure Firewall." + } + }, + "networkRuleCollections": { + "$ref": "#/definitions/networkRuleCollectionType", + "metadata": { + "description": "Optional. Collection of network rule collections used by Azure Firewall." + } + }, + "natRuleCollections": { + "$ref": "#/definitions/natRuleCollectionType", + "metadata": { + "description": "Optional. Collection of NAT rule collections used by Azure Firewall." + } + }, + "firewallPolicyId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the Firewall Policy that should be attached." + } + }, + "hubIPAddresses": { + "$ref": "#/definitions/hubIPAddressesType", + "nullable": true, + "metadata": { + "description": "Conditional. IP addresses associated with AzureFirewall. Required if `virtualHubId` is supplied." + } + }, + "virtualHubId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. The virtualHub resource ID to which the firewall belongs. Required if `virtualNetworkId` is empty." + } + }, + "threatIntelMode": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Alert", + "Deny", + "Off" + ], + "metadata": { + "description": "Optional. The operation mode for Threat Intel." + } + }, + "zones": { + "type": "array", + "defaultValue": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. Zone numbers e.g. 1,2,3." + } + }, + "enableForcedTunneling": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable/Disable forced tunneling." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the Azure Firewall resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "additionalPublicIpConfigurationsVar", + "count": "[length(parameters('additionalPublicIpConfigurations'))]", + "input": { + "name": "[parameters('additionalPublicIpConfigurations')[copyIndex('additionalPublicIpConfigurationsVar')].name]", + "properties": { + "publicIPAddress": "[if(contains(parameters('additionalPublicIpConfigurations')[copyIndex('additionalPublicIpConfigurationsVar')], 'publicIPAddressResourceId'), createObject('id', parameters('additionalPublicIpConfigurations')[copyIndex('additionalPublicIpConfigurationsVar')].publicIPAddressResourceId), null())]" + } + } + }, + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "azureSkuName": "[if(empty(parameters('virtualNetworkResourceId')), 'AZFW_Hub', 'AZFW_VNet')]", + "requiresManagementIp": "[if(or(equals(parameters('azureSkuTier'), 'Basic'), parameters('enableForcedTunneling')), true(), false())]", + "isCreateDefaultManagementIP": "[and(empty(parameters('managementIPResourceID')), variables('requiresManagementIp'))]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-azurefirewall.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "azureFirewall": { + "type": "Microsoft.Network/azureFirewalls", + "apiVersion": "2024-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "zones": "[if(equals(length(parameters('zones')), 0), null(), parameters('zones'))]", + "tags": "[parameters('tags')]", + "properties": "[if(equals(variables('azureSkuName'), 'AZFW_VNet'), createObject('threatIntelMode', parameters('threatIntelMode'), 'firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'ipConfigurations', concat(createArray(createObject('name', if(not(empty(parameters('publicIPResourceID'))), last(split(parameters('publicIPResourceID'), '/')), reference('publicIPAddress').outputs.name.value), 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallSubnet', parameters('virtualNetworkResourceId')))), if(or(not(empty(parameters('publicIPResourceID'))), not(empty(parameters('publicIPAddressObject')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('publicIPResourceID'))), parameters('publicIPResourceID'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))), variables('additionalPublicIpConfigurationsVar')), 'managementIpConfiguration', if(variables('requiresManagementIp'), createObject('name', if(not(empty(parameters('managementIPResourceID'))), last(split(parameters('managementIPResourceID'), '/')), reference('managementIPAddress').outputs.name.value), 'properties', createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallManagementSubnet', parameters('virtualNetworkResourceId'))), 'publicIPAddress', createObject('id', if(not(empty(parameters('managementIPResourceID'))), parameters('managementIPResourceID'), reference('managementIPAddress').outputs.resourceId.value)))), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'applicationRuleCollections', coalesce(parameters('applicationRuleCollections'), createArray()), 'natRuleCollections', coalesce(parameters('natRuleCollections'), createArray()), 'networkRuleCollections', coalesce(parameters('networkRuleCollections'), createArray())), createObject('firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'hubIPAddresses', if(not(empty(parameters('hubIPAddresses'))), parameters('hubIPAddresses'), null()), 'virtualHub', if(not(empty(parameters('virtualHubId'))), createObject('id', parameters('virtualHubId')), null())))]", + "dependsOn": [ + "managementIPAddress", + "publicIPAddress" + ] + }, + "azureFirewall_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/azureFirewalls/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "azureFirewall" + ] + }, + "azureFirewall_diagnosticSettings": { + "copy": { + "name": "azureFirewall_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/azureFirewalls/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "azureFirewall" + ] + }, + "azureFirewall_roleAssignments": { + "copy": { + "name": "azureFirewall_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/azureFirewalls/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/azureFirewalls', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "azureFirewall" + ] + }, + "publicIPAddress": { + "condition": "[and(empty(parameters('publicIPResourceID')), equals(variables('azureSkuName'), 'AZFW_VNet'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Firewall-PIP', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('publicIPAddressObject').name]" + }, + "publicIpPrefixResourceId": "[if(contains(parameters('publicIPAddressObject'), 'publicIPPrefixResourceId'), if(not(empty(parameters('publicIPAddressObject').publicIPPrefixResourceId)), createObject('value', parameters('publicIPAddressObject').publicIPPrefixResourceId), createObject('value', '')), createObject('value', ''))]", + "publicIPAllocationMethod": "[if(contains(parameters('publicIPAddressObject'), 'publicIPAllocationMethod'), if(not(empty(parameters('publicIPAddressObject').publicIPAllocationMethod)), createObject('value', parameters('publicIPAddressObject').publicIPAllocationMethod), createObject('value', 'Static')), createObject('value', 'Static'))]", + "skuName": "[if(contains(parameters('publicIPAddressObject'), 'skuName'), if(not(empty(parameters('publicIPAddressObject').skuName)), createObject('value', parameters('publicIPAddressObject').skuName), createObject('value', 'Standard')), createObject('value', 'Standard'))]", + "skuTier": "[if(contains(parameters('publicIPAddressObject'), 'skuTier'), if(not(empty(parameters('publicIPAddressObject').skuTier)), createObject('value', parameters('publicIPAddressObject').skuTier), createObject('value', 'Regional')), createObject('value', 'Regional'))]", + "roleAssignments": "[if(contains(parameters('publicIPAddressObject'), 'roleAssignments'), if(not(empty(parameters('publicIPAddressObject').roleAssignments)), createObject('value', parameters('publicIPAddressObject').roleAssignments), createObject('value', createArray())), createObject('value', createArray()))]", + "diagnosticSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" + }, + "zones": { + "value": "[parameters('zones')]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "16693645977675862540" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "", + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "metadata": { + "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + } + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.6.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": null + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" + } + } + } + } + }, + "managementIPAddress": { + "condition": "[and(variables('isCreateDefaultManagementIP'), equals(variables('azureSkuName'), 'AZFW_VNet'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Firewall-MIP', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": "[if(contains(parameters('managementIPAddressObject'), 'name'), if(not(empty(parameters('managementIPAddressObject').name)), createObject('value', parameters('managementIPAddressObject').name), createObject('value', format('{0}-mip', parameters('name')))), createObject('value', format('{0}-mip', parameters('name'))))]", + "publicIpPrefixResourceId": "[if(contains(parameters('managementIPAddressObject'), 'managementIPPrefixResourceId'), if(not(empty(parameters('managementIPAddressObject').managementIPPrefixResourceId)), createObject('value', parameters('managementIPAddressObject').managementIPPrefixResourceId), createObject('value', '')), createObject('value', ''))]", + "publicIPAllocationMethod": "[if(contains(parameters('managementIPAddressObject'), 'managementIPAllocationMethod'), if(not(empty(parameters('managementIPAddressObject').managementIPAllocationMethod)), createObject('value', parameters('managementIPAddressObject').managementIPAllocationMethod), createObject('value', 'Static')), createObject('value', 'Static'))]", + "skuName": "[if(contains(parameters('managementIPAddressObject'), 'skuName'), if(not(empty(parameters('managementIPAddressObject').skuName)), createObject('value', parameters('managementIPAddressObject').skuName), createObject('value', 'Standard')), createObject('value', 'Standard'))]", + "skuTier": "[if(contains(parameters('managementIPAddressObject'), 'skuTier'), if(not(empty(parameters('managementIPAddressObject').skuTier)), createObject('value', parameters('managementIPAddressObject').skuTier), createObject('value', 'Regional')), createObject('value', 'Regional'))]", + "roleAssignments": "[if(contains(parameters('managementIPAddressObject'), 'roleAssignments'), if(not(empty(parameters('managementIPAddressObject').roleAssignments)), createObject('value', parameters('managementIPAddressObject').roleAssignments), createObject('value', createArray())), createObject('value', createArray()))]", + "diagnosticSettings": { + "value": "[tryGet(parameters('managementIPAddressObject'), 'diagnosticSettings')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('managementIPAddressObject'), 'tags'), parameters('tags'))]" + }, + "zones": { + "value": "[parameters('zones')]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('managementIPAddressObject'), 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "16693645977675862540" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "", + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "metadata": { + "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + } + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.6.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": null + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" + } + } + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure Firewall." + }, + "value": "[resourceId('Microsoft.Network/azureFirewalls', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Azure Firewall." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Azure firewall was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "privateIp": { + "type": "string", + "metadata": { + "description": "The private IP of the Azure firewall." + }, + "value": "[if(contains(reference('azureFirewall'), 'ipConfigurations'), reference('azureFirewall').ipConfigurations[0].properties.privateIPAddress, '')]" + }, + "ipConfAzureFirewallSubnet": { + "type": "object", + "metadata": { + "description": "The Public IP configuration object for the Azure Firewall Subnet." + }, + "value": "[if(contains(reference('azureFirewall'), 'ipConfigurations'), reference('azureFirewall').ipConfigurations[0], createObject())]" + }, + "applicationRuleCollections": { + "type": "array", + "metadata": { + "description": "List of Application Rule Collections used by Azure Firewall." + }, + "value": "[coalesce(parameters('applicationRuleCollections'), createArray())]" + }, + "networkRuleCollections": { + "type": "array", + "metadata": { + "description": "List of Network Rule Collections used by Azure Firewall." + }, + "value": "[coalesce(parameters('networkRuleCollections'), createArray())]" + }, + "natRuleCollections": { + "type": "array", + "metadata": { + "description": "List of NAT rule collections used by Azure Firewall." + }, + "value": "[coalesce(parameters('natRuleCollections'), createArray())]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('azureFirewall', '2024-01-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/addpip/dependencies.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/addpip/dependencies.bicep new file mode 100644 index 000000000..7e2090e89 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/addpip/dependencies.bicep @@ -0,0 +1,70 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureFirewallSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + } + { + name: 'AzureFirewallManagementSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 1) + } + } + ] + } +} + +resource publicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/addpip/main.test.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/addpip/main.test.bicep new file mode 100644 index 000000000..d63e79f92 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/addpip/main.test.bicep @@ -0,0 +1,77 @@ +targetScope = 'subscription' + +metadata name = 'Add-PIP' +metadata description = 'This instance deploys the module and attaches an existing public IP address.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.azurefirewalls-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nafaddpip' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + additionalPublicIpConfigurations: [ + { + name: 'ipConfig01' + publicIPAddressResourceId: nestedDependencies.outputs.publicIPResourceId + } + ] + azureSkuTier: 'Basic' + managementIPAddressObject: { + publicIPAllocationMethod: 'Static' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + } + } +] diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/basic/dependencies.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/basic/dependencies.bicep new file mode 100644 index 000000000..5fcd99bfb --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/basic/dependencies.bicep @@ -0,0 +1,35 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureFirewallSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + } + { + name: 'AzureFirewallManagementSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 1) + } + } + ] + } +} +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/basic/main.test.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/basic/main.test.bicep new file mode 100644 index 000000000..30fd9d9e4 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/basic/main.test.bicep @@ -0,0 +1,61 @@ +targetScope = 'subscription' + +metadata name = 'Basic SKU' +metadata description = 'This instance deploys the module with the Basic SKU.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.azurefirewalls-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nafbasic' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + azureSkuTier: 'Basic' + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + location: resourceLocation + threatIntelMode: 'Deny' + networkRuleCollections: [] + } + } +] diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/custompip/dependencies.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/custompip/dependencies.bicep new file mode 100644 index 000000000..b2b179a6c --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/custompip/dependencies.bicep @@ -0,0 +1,41 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureFirewallSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/custompip/main.test.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/custompip/main.test.bicep new file mode 100644 index 000000000..733fcc2ea --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/custompip/main.test.bicep @@ -0,0 +1,101 @@ +targetScope = 'subscription' + +metadata name = 'Custom-PIP' +metadata description = 'This instance deploys the module and will create a public IP address.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.azurefirewalls-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nafcstpip' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}03' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + publicIPAddressObject: { + name: 'new-${namePrefix}-pip-${serviceShort}' + publicIPAllocationMethod: 'Static' + publicIPPrefixResourceId: '' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + skuName: 'Standard' + skuTier: 'Regional' + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + } + } +] diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..fed44e2c9 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,29 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureFirewallSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + } + ] + } +} +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..86ad404ca --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,58 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.azurefirewalls-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nafmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/hubcommon/dependencies.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/hubcommon/dependencies.bicep new file mode 100644 index 000000000..0dc2f1d9a --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/hubcommon/dependencies.bicep @@ -0,0 +1,46 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual WAN to create.') +param virtualWanName string + +@description('Required. The name of the Virtual Hub to create.') +param virtualHubName string + +@description('Required. The name of the Firewall Policy to create.') +param firewallPolicyName string + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWanName + location: location + properties: { + disableVpnEncryption: false + allowBranchToBranchTraffic: true + type: 'Standard' + } +} + +resource virtualHub 'Microsoft.Network/virtualHubs@2021-08-01' = { + name: virtualHubName + location: location + properties: { + addressPrefix: '10.1.0.0/16' + virtualWan: { + id: virtualWan.id + } + } +} + +resource policy 'Microsoft.Network/firewallPolicies@2023-04-01' = { + name: firewallPolicyName + location: location + properties: { + threatIntelMode: 'Alert' + } +} + +@description('The resource ID of the created Virtual Hub.') +output virtualHubResourceId string = virtualHub.id + +@description('The resource ID of the created Firewall Policy.') +output firewallPolicyResourceId string = policy.id diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/hubcommon/main.test.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/hubcommon/main.test.bicep new file mode 100644 index 000000000..b40d7d6f1 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/hubcommon/main.test.bicep @@ -0,0 +1,66 @@ +targetScope = 'subscription' + +metadata name = 'Hub-commom' +metadata description = 'This instance deploys the module a vWAN in a typical hub setting.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.azurefirewalls-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nafhubcom' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualWanName: 'dep-${namePrefix}-vwan-${serviceShort}' + virtualHubName: 'dep-${namePrefix}-vhub-${serviceShort}' + firewallPolicyName: 'dep-${namePrefix}-afwp-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + firewallPolicyId: nestedDependencies.outputs.firewallPolicyResourceId + virtualHubId: nestedDependencies.outputs.virtualHubResourceId + hubIPAddresses: { + publicIPs: { + count: 1 + } + } + } + } +] diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/hubmin/dependencies.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/hubmin/dependencies.bicep new file mode 100644 index 000000000..eceb77c39 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/hubmin/dependencies.bicep @@ -0,0 +1,32 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual WAN to create.') +param virtualWanName string + +@description('Required. The name of the Virtual Hub to create.') +param virtualHubName string + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWanName + location: location + properties: { + disableVpnEncryption: false + allowBranchToBranchTraffic: true + type: 'Standard' + } +} + +resource virtualHub 'Microsoft.Network/virtualHubs@2021-08-01' = { + name: virtualHubName + location: location + properties: { + addressPrefix: '10.1.0.0/16' + virtualWan: { + id: virtualWan.id + } + } +} + +@description('The resource ID of the created Virtual Hub.') +output virtualHubResourceId string = virtualHub.id diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/hubmin/main.test.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/hubmin/main.test.bicep new file mode 100644 index 000000000..5787d1302 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/hubmin/main.test.bicep @@ -0,0 +1,64 @@ +targetScope = 'subscription' + +metadata name = 'Hub-min' +metadata description = 'This instance deploys the module a vWAN minimum hub setting.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.azurefirewalls-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nafhubmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWanName: 'dep-${namePrefix}-vwan-${serviceShort}' + virtualHubName: 'dep-${namePrefix}-vhub-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualHubId: nestedDependencies.outputs.virtualHubResourceId + hubIPAddresses: { + publicIPs: { + count: 1 + } + } + } + } +] diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..4f274af14 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/max/dependencies.bicep @@ -0,0 +1,64 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureFirewallSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + } + ] + } +} + +resource publicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..a0feaee26 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/max/main.test.bicep @@ -0,0 +1,222 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.azurefirewalls-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nafmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + applicationRuleCollections: [ + { + name: 'allow-app-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + fqdnTags: [ + 'AppServiceEnvironment' + 'WindowsUpdate' + ] + name: 'allow-ase-tags' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + } + { + name: 'allow-ase-management' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + targetFqdns: [ + 'bing.com' + ] + } + ] + } + } + ] + publicIPResourceID: nestedDependencies.outputs.publicIPResourceId + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + networkRuleCollections: [ + { + name: 'allow-network-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationPorts: [ + '12000' + '123' + ] + name: 'allow-ntp' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + } + { + name: 'allow-azure-devops' + protocols: [ + 'Any' + ] + description: 'allow azure devops' + sourceAddresses: [ + '*' + ] + destinationAddresses: [ + 'AzureDevOps' + ] + destinationPorts: [ + '443' + ] + } + ] + } + } + ] + roleAssignments: [ + { + name: '3a8da184-d6d8-4bea-b992-e27cc053ef21' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + zones: [ + '1' + '2' + '3' + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/publicipprefix/dependencies.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/publicipprefix/dependencies.bicep new file mode 100644 index 000000000..596fcd125 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/publicipprefix/dependencies.bicep @@ -0,0 +1,56 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Public IP Prefix to create.') +param publicIPPrefixName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureFirewallSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + } + { + name: 'AzureFirewallManagementSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 1) + } + } + ] + } +} + +resource publicIPPrefix 'Microsoft.Network/publicIPPrefixes@2023-11-01' = { + name: publicIPPrefixName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + prefixLength: 30 + publicIPAddressVersion: 'IPv4' + } + zones: [] +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Public IP Prefix') +output publicIPPrefixResourceId string = publicIPPrefix.id diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/publicipprefix/main.test.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/publicipprefix/main.test.bicep new file mode 100644 index 000000000..b047e5199 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/publicipprefix/main.test.bicep @@ -0,0 +1,75 @@ +targetScope = 'subscription' + +metadata name = 'Public-IP-Prefix' +metadata description = 'This instance deploys the module and will use a public IP prefix.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.azurefirewalls-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nafpip' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + publicIPPrefixName: 'dep-${namePrefix}-pip-prefix-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + publicIPAddressObject: { + name: 'publicIP01' + publicIPAllocationMethod: 'Static' + publicIPPrefixResourceId: nestedDependencies.outputs.publicIPPrefixResourceId + skuName: 'Standard' + skuTier: 'Regional' + } + azureSkuTier: 'Basic' + managementIPAddressObject: { + name: 'managementIP01' + managementIPAllocationMethod: 'Static' + managementIPPrefixResourceId: nestedDependencies.outputs.publicIPPrefixResourceId + skuName: 'Standard' + skuTier: 'Regional' + } + zones: [] + } + } +] diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep new file mode 100644 index 000000000..8497ceafc --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep @@ -0,0 +1,59 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureFirewallSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + } + { + name: 'AzureFirewallManagementSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 1) + } + } + ] + } +} + +resource publicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep new file mode 100644 index 000000000..8f70451dc --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep @@ -0,0 +1,70 @@ +targetScope = 'subscription' + +metadata name = 'Forced tunneling' +metadata description = 'This instance deploys the module and sets up forced tunneling.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.azurefirewalls-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'naftunn' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + additionalPublicIpConfigurations: [ + { + name: 'ipConfig01' + publicIPAddressResourceId: nestedDependencies.outputs.publicIPResourceId + } + ] + azureSkuTier: 'Standard' + enableForcedTunneling: true + managementIPAddressObject: { + publicIPAllocationMethod: 'Static' + } + } + } +] diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..b545a6b72 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,67 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureFirewallSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + } + ] + } +} + +resource publicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id + +@description('The public IP Address of the created Public IP.') +output publicIPAddress string = publicIP.properties.ipAddress + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/azure-firewall/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/azure-firewall/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..ea9f1bc19 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,180 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.azurefirewalls-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nafwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + applicationRuleCollections: [ + { + name: 'allow-app-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + fqdnTags: [ + 'AppServiceEnvironment' + 'WindowsUpdate' + ] + name: 'allow-ase-tags' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + } + { + name: 'allow-ase-management' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + targetFqdns: [ + 'bing.com' + ] + } + ] + } + } + ] + publicIPResourceID: nestedDependencies.outputs.publicIPResourceId + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + networkRuleCollections: [ + { + name: 'allow-network-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationPorts: [ + '12000' + '123' + ] + name: 'allow-ntp' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + } + ] + } + } + ] + zones: [ + '1' + '2' + '3' + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/azure-firewall/version.json b/avm/1.1.0/res/network/azure-firewall/version.json new file mode 100644 index 000000000..a8eda3102 --- /dev/null +++ b/avm/1.1.0/res/network/azure-firewall/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/bastion-host/README.md b/avm/1.1.0/res/network/bastion-host/README.md new file mode 100644 index 000000000..5f23a61e2 --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/README.md @@ -0,0 +1,1300 @@ +# Bastion Hosts `[Microsoft.Network/bastionHosts]` + +This module deploys a Bastion Host. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/bastionHosts` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/bastionHosts) | +| `Microsoft.Network/publicIPAddresses` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/publicIPAddresses) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/bastion-host:`. + +- [With a custom public IP address deployed by the module](#example-1-with-a-custom-public-ip-address-deployed-by-the-module) +- [Using only defaults](#example-2-using-only-defaults) +- [Using Developer SKU](#example-3-using-developer-sku) +- [Using large parameter set](#example-4-using-large-parameter-set) +- [Private-only deployment](#example-5-private-only-deployment) +- [WAF-aligned](#example-6-waf-aligned) + +### Example 1: _With a custom public IP address deployed by the module_ + +This instance does not require a pre-deployed public IP but includes its deployment as part of the Bastion module deployment. + + +

+ +via Bicep module + +```bicep +module bastionHost 'br/public:avm/res/network/bastion-host:' = { + name: 'bastionHostDeployment' + params: { + // Required parameters + name: 'nbhctmpip001' + virtualNetworkResourceId: '' + // Non-required parameters + location: '' + publicIPAddressObject: { + allocationMethod: 'Static' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'nbhctmpip001-pip' + publicIPPrefixResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + skuName: 'Standard' + skuTier: 'Regional' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + zones: [ + 1 + 2 + 3 + ] + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nbhctmpip001" + }, + "virtualNetworkResourceId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + }, + "publicIPAddressObject": { + "value": { + "allocationMethod": "Static", + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "name": "nbhctmpip001-pip", + "publicIPPrefixResourceId": "", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "skuName": "Standard", + "skuTier": "Regional", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + }, + "zones": [ + 1, + 2, + 3 + ] + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/bastion-host:' + +// Required parameters +param name = 'nbhctmpip001' +param virtualNetworkResourceId = '' +// Non-required parameters +param location = '' +param publicIPAddressObject = { + allocationMethod: 'Static' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'nbhctmpip001-pip' + publicIPPrefixResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + skuName: 'Standard' + skuTier: 'Regional' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + zones: [ + 1 + 2 + 3 + ] +} +``` + +
+

+ +### Example 2: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module bastionHost 'br/public:avm/res/network/bastion-host:' = { + name: 'bastionHostDeployment' + params: { + // Required parameters + name: 'nbhmin001' + virtualNetworkResourceId: '' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nbhmin001" + }, + "virtualNetworkResourceId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/bastion-host:' + +// Required parameters +param name = 'nbhmin001' +param virtualNetworkResourceId = '' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 3: _Using Developer SKU_ + +This instance deploys the module with the Developer SKU. + + +

+ +via Bicep module + +```bicep +module bastionHost 'br/public:avm/res/network/bastion-host:' = { + name: 'bastionHostDeployment' + params: { + // Required parameters + name: 'nbhdev001' + virtualNetworkResourceId: '' + // Non-required parameters + location: '' + skuName: 'Developer' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nbhdev001" + }, + "virtualNetworkResourceId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + }, + "skuName": { + "value": "Developer" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/bastion-host:' + +// Required parameters +param name = 'nbhdev001' +param virtualNetworkResourceId = '' +// Non-required parameters +param location = '' +param skuName = 'Developer' +``` + +
+

+ +### Example 4: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module bastionHost 'br/public:avm/res/network/bastion-host:' = { + name: 'bastionHostDeployment' + params: { + // Required parameters + name: 'nbhmax001' + virtualNetworkResourceId: '' + // Non-required parameters + bastionSubnetPublicIpResourceId: '' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'a9329bd8-d7c8-4915-9dfe-04197fa5bf45' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + scaleUnits: 4 + skuName: 'Standard' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + zones: [ + 1 + 2 + 3 + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nbhmax001" + }, + "virtualNetworkResourceId": { + "value": "" + }, + // Non-required parameters + "bastionSubnetPublicIpResourceId": { + "value": "" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "disableCopyPaste": { + "value": true + }, + "enableFileCopy": { + "value": false + }, + "enableIpConnect": { + "value": false + }, + "enableShareableLink": { + "value": false + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "a9329bd8-d7c8-4915-9dfe-04197fa5bf45", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "scaleUnits": { + "value": 4 + }, + "skuName": { + "value": "Standard" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "zones": { + "value": [ + 1, + 2, + 3 + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/bastion-host:' + +// Required parameters +param name = 'nbhmax001' +param virtualNetworkResourceId = '' +// Non-required parameters +param bastionSubnetPublicIpResourceId = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableCopyPaste = true +param enableFileCopy = false +param enableIpConnect = false +param enableShareableLink = false +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'a9329bd8-d7c8-4915-9dfe-04197fa5bf45' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scaleUnits = 4 +param skuName = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zones = [ + 1 + 2 + 3 +] +``` + +
+

+ +### Example 5: _Private-only deployment_ + +This instance deploys the module as private-only Bastion deployment. + + +

+ +via Bicep module + +```bicep +module bastionHost 'br/public:avm/res/network/bastion-host:' = { + name: 'bastionHostDeployment' + params: { + // Required parameters + name: 'nbhprv001' + virtualNetworkResourceId: '' + // Non-required parameters + enablePrivateOnlyBastion: true + enableSessionRecording: true + location: '' + skuName: 'Premium' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nbhprv001" + }, + "virtualNetworkResourceId": { + "value": "" + }, + // Non-required parameters + "enablePrivateOnlyBastion": { + "value": true + }, + "enableSessionRecording": { + "value": true + }, + "location": { + "value": "" + }, + "skuName": { + "value": "Premium" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/bastion-host:' + +// Required parameters +param name = 'nbhprv001' +param virtualNetworkResourceId = '' +// Non-required parameters +param enablePrivateOnlyBastion = true +param enableSessionRecording = true +param location = '' +param skuName = 'Premium' +``` + +
+

+ +### Example 6: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module bastionHost 'br/public:avm/res/network/bastion-host:' = { + name: 'bastionHostDeployment' + params: { + // Required parameters + name: 'nbhwaf001' + virtualNetworkResourceId: '' + // Non-required parameters + bastionSubnetPublicIpResourceId: '' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + location: '' + scaleUnits: 4 + skuName: 'Standard' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nbhwaf001" + }, + "virtualNetworkResourceId": { + "value": "" + }, + // Non-required parameters + "bastionSubnetPublicIpResourceId": { + "value": "" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "disableCopyPaste": { + "value": true + }, + "enableFileCopy": { + "value": false + }, + "enableIpConnect": { + "value": false + }, + "enableShareableLink": { + "value": false + }, + "location": { + "value": "" + }, + "scaleUnits": { + "value": 4 + }, + "skuName": { + "value": "Standard" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/bastion-host:' + +// Required parameters +param name = 'nbhwaf001' +param virtualNetworkResourceId = '' +// Non-required parameters +param bastionSubnetPublicIpResourceId = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableCopyPaste = true +param enableFileCopy = false +param enableIpConnect = false +param enableShareableLink = false +param location = '' +param scaleUnits = 4 +param skuName = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Azure Bastion resource. | +| [`virtualNetworkResourceId`](#parameter-virtualnetworkresourceid) | string | Shared services Virtual Network resource Id. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`bastionSubnetPublicIpResourceId`](#parameter-bastionsubnetpublicipresourceid) | string | The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`disableCopyPaste`](#parameter-disablecopypaste) | bool | Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled. | +| [`enableFileCopy`](#parameter-enablefilecopy) | bool | Choose to disable or enable File Copy. Not supported for Basic and Developer SKU. | +| [`enableIpConnect`](#parameter-enableipconnect) | bool | Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU. | +| [`enableKerberos`](#parameter-enablekerberos) | bool | Choose to disable or enable Kerberos authentication. Not supported for Developer SKU. | +| [`enablePrivateOnlyBastion`](#parameter-enableprivateonlybastion) | bool | Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature. | +| [`enableSessionRecording`](#parameter-enablesessionrecording) | bool | Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled. | +| [`enableShareableLink`](#parameter-enableshareablelink) | bool | Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`publicIPAddressObject`](#parameter-publicipaddressobject) | object | Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`scaleUnits`](#parameter-scaleunits) | int | The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units. | +| [`skuName`](#parameter-skuname) | string | The SKU of this Bastion Host. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`zones`](#parameter-zones) | array | A list of availability zones denoting where the Bastion Host resource needs to come from. This is not supported for the Developer SKU. | + +### Parameter: `name` + +Name of the Azure Bastion resource. + +- Required: Yes +- Type: string + +### Parameter: `virtualNetworkResourceId` + +Shared services Virtual Network resource Id. + +- Required: Yes +- Type: string + +### Parameter: `bastionSubnetPublicIpResourceId` + +The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `disableCopyPaste` + +Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableFileCopy` + +Choose to disable or enable File Copy. Not supported for Basic and Developer SKU. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableIpConnect` + +Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableKerberos` + +Choose to disable or enable Kerberos authentication. Not supported for Developer SKU. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enablePrivateOnlyBastion` + +Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableSessionRecording` + +Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableShareableLink` + +Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `publicIPAddressObject` + +Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true. + +- Required: No +- Type: object +- Default: + ```Bicep + { + name: '[format(\'{0}-pip\', parameters(\'name\'))]' + } + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `scaleUnits` + +The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units. + +- Required: No +- Type: int +- Default: `2` + +### Parameter: `skuName` + +The SKU of this Bastion Host. + +- Required: No +- Type: string +- Default: `'Basic'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Developer' + 'Premium' + 'Standard' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `zones` + +A list of availability zones denoting where the Bastion Host resource needs to come from. This is not supported for the Developer SKU. + +- Required: No +- Type: array +- Default: `[]` +- Allowed: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `ipConfAzureBastionSubnet` | object | The Public IPconfiguration object for the AzureBastionSubnet. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name the Azure Bastion. | +| `resourceGroupName` | string | The resource group the Azure Bastion was deployed into. | +| `resourceId` | string | The resource ID the Azure Bastion. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/public-ip-address:0.8.0` | Remote reference | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/bastion-host/main.bicep b/avm/1.1.0/res/network/bastion-host/main.bicep new file mode 100644 index 000000000..70c415b18 --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/main.bicep @@ -0,0 +1,282 @@ +metadata name = 'Bastion Hosts' +metadata description = 'This module deploys a Bastion Host.' + +@description('Required. Name of the Azure Bastion resource.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Required. Shared services Virtual Network resource Id.') +param virtualNetworkResourceId string + +@description('Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true.') +param bastionSubnetPublicIpResourceId string = '' + +@description('Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true.') +param publicIPAddressObject object = { + name: '${name}-pip' +} + +import { diagnosticSettingLogsOnlyType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingLogsOnlyType[]? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +@allowed([ + 'Basic' + 'Developer' + 'Premium' + 'Standard' +]) +@description('Optional. The SKU of this Bastion Host.') +param skuName string = 'Basic' + +@description('Optional. Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled.') +param disableCopyPaste bool = false + +@description('Optional. Choose to disable or enable File Copy. Not supported for Basic and Developer SKU.') +param enableFileCopy bool = true + +@description('Optional. Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU.') +param enableIpConnect bool = false + +@description('Optional. Choose to disable or enable Kerberos authentication. Not supported for Developer SKU.') +param enableKerberos bool = false + +@description('Optional. Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU.') +param enableShareableLink bool = false + +@description('Optional. Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled.') +param enableSessionRecording bool = false + +@description('Optional. Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature.') +param enablePrivateOnlyBastion bool = false + +@description('Optional. The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units.') +param scaleUnits int = 2 + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. A list of availability zones denoting where the Bastion Host resource needs to come from. This is not supported for the Developer SKU.') +@allowed([ + 1 + 2 + 3 +]) +param zones int[] = [] // Availability Zones are currently in preview and only available in certain regions, therefore the default is an empty array. + +// ---------------------------------------------------------------------------- +// Prep ipConfigurations object AzureBastionSubnet for different uses cases: +// 1. Use existing Public IP +// 2. Use new Public IP created in this module +// (skuName == 'Developer' is a special case where ipConfigurations is empty) +var ipConfigurations = skuName == 'Developer' + ? [] + : [ + { + name: 'IpConfAzureBastionSubnet' + properties: union( + { + subnet: { + id: '${virtualNetworkResourceId}/subnets/AzureBastionSubnet' // The subnet name must be AzureBastionSubnet + } + }, + (!enablePrivateOnlyBastion + ? { + //Use existing Public IP, new Public IP created in this module + publicIPAddress: { + id: !empty(bastionSubnetPublicIpResourceId) + ? bastionSubnetPublicIpResourceId + : publicIPAddress.outputs.resourceId + } + } + : {}) + ) + } + ] + +// ---------------------------------------------------------------------------- + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-bastionhost.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.8.0' = if (empty(bastionSubnetPublicIpResourceId) && (skuName != 'Developer') && (!enablePrivateOnlyBastion)) { + name: '${uniqueString(deployment().name, location)}-Bastion-PIP' + params: { + name: publicIPAddressObject.name + enableTelemetry: enableTelemetry + location: location + lock: lock + diagnosticSettings: publicIPAddressObject.?diagnosticSettings + publicIPAddressVersion: publicIPAddressObject.?publicIPAddressVersion + publicIPAllocationMethod: publicIPAddressObject.?publicIPAllocationMethod + publicIpPrefixResourceId: publicIPAddressObject.?publicIPPrefixResourceId + roleAssignments: publicIPAddressObject.?roleAssignments + skuName: publicIPAddressObject.?skuName + skuTier: publicIPAddressObject.?skuTier + tags: publicIPAddressObject.?tags ?? tags + zones: publicIPAddressObject.?zones ?? (length(zones) > 0 ? zones : null) // if zones of the Public IP is empty, use the zones from the bastion host only if not empty (if empty, the default of the public IP will be used) + } +} + +var bastionpropertiesVar = union( + { + scaleUnits: (skuName == 'Basic' || skuName == 'Developer') ? 2 : scaleUnits + ipConfigurations: ipConfigurations + }, + (skuName == 'Developer' + ? { + virtualNetwork: { + id: virtualNetworkResourceId + } + } + : {}), + ((skuName == 'Basic' || skuName == 'Standard' || skuName == 'Premium') + ? { + enableKerberos: enableKerberos + } + : {}), + ((skuName == 'Standard' || skuName == 'Premium') + ? { + enableTunneling: skuName == 'Standard' ? true : (enableSessionRecording ? false : true) // Tunneling is enabled by default for Standard SKU. For Premium SKU it is disabled by default if Session Recording is enabled. + disableCopyPaste: disableCopyPaste + enableFileCopy: enableFileCopy + enableIpConnect: enableIpConnect + enableShareableLink: enableShareableLink + } + : {}), + (skuName == 'Premium' + ? { + enableSessionRecording: enableSessionRecording + enablePrivateOnlyBastion: enablePrivateOnlyBastion + } + : {}) +) + +resource azureBastion 'Microsoft.Network/bastionHosts@2024-05-01' = { + name: name + location: location + tags: tags ?? {} // The empty object is a workaround for error when deploying with the Developer SKU. The error seems unrelated to the tags, but it is resolved by adding the empty object. + sku: { + name: skuName + } + zones: skuName == 'Developer' ? [] : map(zones, zone => string(zone)) + properties: bastionpropertiesVar +} + +resource azureBastion_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: azureBastion +} + +resource azureBastion_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: azureBastion + } +] + +resource azureBastion_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(azureBastion.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: azureBastion + } +] + +@description('The resource group the Azure Bastion was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name the Azure Bastion.') +output name string = azureBastion.name + +@description('The resource ID the Azure Bastion.') +output resourceId string = azureBastion.id + +@description('The location the resource was deployed into.') +output location string = azureBastion.location + +@description('The Public IPconfiguration object for the AzureBastionSubnet.') +output ipConfAzureBastionSubnet object = skuName == 'Developer' ? {} : azureBastion.properties.ipConfigurations[0] diff --git a/avm/1.1.0/res/network/bastion-host/main.json b/avm/1.1.0/res/network/bastion-host/main.json new file mode 100644 index 000000000..27dfd312d --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/main.json @@ -0,0 +1,1262 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "16499979971476585213" + }, + "name": "Bastion Hosts", + "description": "This module deploys a Bastion Host." + }, + "definitions": { + "diagnosticSettingLogsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure Bastion resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Shared services Virtual Network resource Id." + } + }, + "bastionSubnetPublicIpResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true." + } + }, + "publicIPAddressObject": { + "type": "object", + "defaultValue": { + "name": "[format('{0}-pip', parameters('name'))]" + }, + "metadata": { + "description": "Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Developer", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. The SKU of this Bastion Host." + } + }, + "disableCopyPaste": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled." + } + }, + "enableFileCopy": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Choose to disable or enable File Copy. Not supported for Basic and Developer SKU." + } + }, + "enableIpConnect": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU." + } + }, + "enableKerberos": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Kerberos authentication. Not supported for Developer SKU." + } + }, + "enableShareableLink": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU." + } + }, + "enableSessionRecording": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled." + } + }, + "enablePrivateOnlyBastion": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature." + } + }, + "scaleUnits": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Optional. The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting where the Bastion Host resource needs to come from. This is not supported for the Developer SKU." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-bastionhost.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "azureBastion": { + "type": "Microsoft.Network/bastionHosts", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[coalesce(parameters('tags'), createObject())]", + "sku": { + "name": "[parameters('skuName')]" + }, + "zones": "[if(equals(parameters('skuName'), 'Developer'), createArray(), map(parameters('zones'), lambda('zone', string(lambdaVariables('zone')))))]", + "properties": "[union(createObject('scaleUnits', if(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Developer')), 2, parameters('scaleUnits')), 'ipConfigurations', if(equals(parameters('skuName'), 'Developer'), createArray(), createArray(createObject('name', 'IpConfAzureBastionSubnet', 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureBastionSubnet', parameters('virtualNetworkResourceId')))), if(not(parameters('enablePrivateOnlyBastion')), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('bastionSubnetPublicIpResourceId'))), parameters('bastionSubnetPublicIpResourceId'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))))), if(equals(parameters('skuName'), 'Developer'), createObject('virtualNetwork', createObject('id', parameters('virtualNetworkResourceId'))), createObject()), if(or(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Standard')), equals(parameters('skuName'), 'Premium')), createObject('enableKerberos', parameters('enableKerberos')), createObject()), if(or(equals(parameters('skuName'), 'Standard'), equals(parameters('skuName'), 'Premium')), createObject('enableTunneling', if(equals(parameters('skuName'), 'Standard'), true(), if(parameters('enableSessionRecording'), false(), true())), 'disableCopyPaste', parameters('disableCopyPaste'), 'enableFileCopy', parameters('enableFileCopy'), 'enableIpConnect', parameters('enableIpConnect'), 'enableShareableLink', parameters('enableShareableLink')), createObject()), if(equals(parameters('skuName'), 'Premium'), createObject('enableSessionRecording', parameters('enableSessionRecording'), 'enablePrivateOnlyBastion', parameters('enablePrivateOnlyBastion')), createObject()))]", + "dependsOn": [ + "publicIPAddress" + ] + }, + "azureBastion_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "azureBastion_diagnosticSettings": { + "copy": { + "name": "azureBastion_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "azureBastion_roleAssignments": { + "copy": { + "name": "azureBastion_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/bastionHosts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "publicIPAddress": { + "condition": "[and(and(empty(parameters('bastionSubnetPublicIpResourceId')), not(equals(parameters('skuName'), 'Developer'))), not(parameters('enablePrivateOnlyBastion')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Bastion-PIP', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('publicIPAddressObject').name]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" + }, + "zones": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'zones'), if(greater(length(parameters('zones')), 0), parameters('zones'), null()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "5168739580767459761" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.8.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2024-05-01', 'full').location]" + } + } + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Azure Bastion was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name the Azure Bastion." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID the Azure Bastion." + }, + "value": "[resourceId('Microsoft.Network/bastionHosts', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('azureBastion', '2024-05-01', 'full').location]" + }, + "ipConfAzureBastionSubnet": { + "type": "object", + "metadata": { + "description": "The Public IPconfiguration object for the AzureBastionSubnet." + }, + "value": "[if(equals(parameters('skuName'), 'Developer'), createObject(), reference('azureBastion').ipConfigurations[0])]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/bastion-host/tests/e2e/custompip/dependencies.bicep b/avm/1.1.0/res/network/bastion-host/tests/e2e/custompip/dependencies.bicep new file mode 100644 index 000000000..e4b108088 --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/tests/e2e/custompip/dependencies.bicep @@ -0,0 +1,41 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-05-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureBastionSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/bastion-host/tests/e2e/custompip/main.test.bicep b/avm/1.1.0/res/network/bastion-host/tests/e2e/custompip/main.test.bicep new file mode 100644 index 000000000..13e17f8de --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/tests/e2e/custompip/main.test.bicep @@ -0,0 +1,111 @@ +targetScope = 'subscription' + +metadata name = 'With a custom public IP address deployed by the module' +metadata description = 'This instance does not require a pre-deployed public IP but includes its deployment as part of the Bastion module deployment.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.bastionhosts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nbhctmpip' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-11-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}03' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + publicIPAddressObject: { + name: '${namePrefix}${serviceShort}001-pip' + allocationMethod: 'Static' + publicIPPrefixResourceId: '' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + skuName: 'Standard' + skuTier: 'Regional' + zones: [ + 1 + 2 + 3 + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } + } +] diff --git a/avm/1.1.0/res/network/bastion-host/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/bastion-host/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..e7f1953da --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,30 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-05-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureBastionSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id diff --git a/avm/1.1.0/res/network/bastion-host/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/bastion-host/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..b87f5575f --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,58 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.bastionhosts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nbhmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-11-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + } + } +] diff --git a/avm/1.1.0/res/network/bastion-host/tests/e2e/developer/dependencies.bicep b/avm/1.1.0/res/network/bastion-host/tests/e2e/developer/dependencies.bicep new file mode 100644 index 000000000..e7f1953da --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/tests/e2e/developer/dependencies.bicep @@ -0,0 +1,30 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-05-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureBastionSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id diff --git a/avm/1.1.0/res/network/bastion-host/tests/e2e/developer/main.test.bicep b/avm/1.1.0/res/network/bastion-host/tests/e2e/developer/main.test.bicep new file mode 100644 index 000000000..a62c4e437 --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/tests/e2e/developer/main.test.bicep @@ -0,0 +1,59 @@ +targetScope = 'subscription' + +metadata name = 'Using Developer SKU' +metadata description = 'This instance deploys the module with the Developer SKU.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.bastionhosts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nbhdev' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-11-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + skuName: 'Developer' + location: resourceLocation + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + } + } +] diff --git a/avm/1.1.0/res/network/bastion-host/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/bastion-host/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..d5fdc8671 --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/tests/e2e/max/dependencies.bicep @@ -0,0 +1,64 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-05-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureBastionSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource publicIP 'Microsoft.Network/publicIPAddresses@2024-05-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + zones: [ + '1' + '2' + '3' + ] + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/bastion-host/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/bastion-host/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..10ede671f --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/tests/e2e/max/main.test.bicep @@ -0,0 +1,127 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.bastionhosts-${serviceShort}-rg' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nbhmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// Availability zones are currently in preview and not available in all regions. This region must be used in the AVM testing subscription +#disable-next-line no-hardcoded-location +var enforcedLocation = 'northeurope' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-11-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: enforcedLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: enforcedLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + bastionSubnetPublicIpResourceId: nestedDependencies.outputs.publicIPResourceId + diagnosticSettings: [ + { + name: 'customSetting' + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'a9329bd8-d7c8-4915-9dfe-04197fa5bf45' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + scaleUnits: 4 + skuName: 'Standard' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + zones: [ + 1 + 2 + 3 + ] + } + } +] diff --git a/avm/1.1.0/res/network/bastion-host/tests/e2e/private/dependencies.bicep b/avm/1.1.0/res/network/bastion-host/tests/e2e/private/dependencies.bicep new file mode 100644 index 000000000..e7f1953da --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/tests/e2e/private/dependencies.bicep @@ -0,0 +1,30 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-05-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureBastionSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id diff --git a/avm/1.1.0/res/network/bastion-host/tests/e2e/private/main.test.bicep b/avm/1.1.0/res/network/bastion-host/tests/e2e/private/main.test.bicep new file mode 100644 index 000000000..eee5592b8 --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/tests/e2e/private/main.test.bicep @@ -0,0 +1,61 @@ +targetScope = 'subscription' + +metadata name = 'Private-only deployment' +metadata description = 'This instance deploys the module as private-only Bastion deployment.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.bastionhosts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nbhprv' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-11-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + skuName: 'Premium' + enableSessionRecording: true + enablePrivateOnlyBastion: true + } + } +] diff --git a/avm/1.1.0/res/network/bastion-host/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/bastion-host/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..4691026fa --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,53 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-05-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureBastionSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource publicIP 'Microsoft.Network/publicIPAddresses@2024-05-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id diff --git a/avm/1.1.0/res/network/bastion-host/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/bastion-host/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..a4b10faba --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,94 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.bastionhosts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nbhwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-11-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + bastionSubnetPublicIpResourceId: nestedDependencies.outputs.publicIPResourceId + diagnosticSettings: [ + { + name: 'customSetting' + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + scaleUnits: 4 + skuName: 'Standard' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/bastion-host/version.json b/avm/1.1.0/res/network/bastion-host/version.json new file mode 100644 index 000000000..21226dd43 --- /dev/null +++ b/avm/1.1.0/res/network/bastion-host/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.6", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/connection/README.md b/avm/1.1.0/res/network/connection/README.md new file mode 100644 index 000000000..68255dbeb --- /dev/null +++ b/avm/1.1.0/res/network/connection/README.md @@ -0,0 +1,874 @@ +# Virtual Network Gateway Connections `[Microsoft.Network/connections]` + +This module deploys a Virtual Network Gateway Connection. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Notes](#Notes) +- [Data Collection](#Data-Collection) + +## 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.Network/connections` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/connections) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/connection:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module connection 'br/public:avm/res/network/connection:' = { + name: 'connectionDeployment' + params: { + // Required parameters + name: 'ncmin001' + virtualNetworkGateway1: { + id: '' + } + // Non-required parameters + connectionType: 'Vnet2Vnet' + location: '' + virtualNetworkGateway2: { + id: '' + } + vpnSharedKey: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ncmin001" + }, + "virtualNetworkGateway1": { + "value": { + "id": "" + } + }, + // Non-required parameters + "connectionType": { + "value": "Vnet2Vnet" + }, + "location": { + "value": "" + }, + "virtualNetworkGateway2": { + "value": { + "id": "" + } + }, + "vpnSharedKey": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/connection:' + +// Required parameters +param name = 'ncmin001' +virtualNetworkGateway1: { + id: '' +} +// Non-required parameters +param connectionType = 'Vnet2Vnet' +param location = '' +virtualNetworkGateway2: { + id: '' +} +param vpnSharedKey = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module connection 'br/public:avm/res/network/connection:' = { + name: 'connectionDeployment' + params: { + // Required parameters + name: 'ncmax001' + virtualNetworkGateway1: { + id: '' + } + // Non-required parameters + connectionType: 'Vnet2Vnet' + dpdTimeoutSeconds: 45 + enableBgp: false + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + usePolicyBasedTrafficSelectors: false + virtualNetworkGateway2: { + id: '' + } + vpnSharedKey: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ncmax001" + }, + "virtualNetworkGateway1": { + "value": { + "id": "" + } + }, + // Non-required parameters + "connectionType": { + "value": "Vnet2Vnet" + }, + "dpdTimeoutSeconds": { + "value": 45 + }, + "enableBgp": { + "value": false + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "usePolicyBasedTrafficSelectors": { + "value": false + }, + "virtualNetworkGateway2": { + "value": { + "id": "" + } + }, + "vpnSharedKey": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/connection:' + +// Required parameters +param name = 'ncmax001' +virtualNetworkGateway1: { + id: '' +} +// Non-required parameters +param connectionType = 'Vnet2Vnet' +param dpdTimeoutSeconds = 45 +param enableBgp = false +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param usePolicyBasedTrafficSelectors = false +virtualNetworkGateway2: { + id: '' +} +param vpnSharedKey = '' +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module connection 'br/public:avm/res/network/connection:' = { + name: 'connectionDeployment' + params: { + // Required parameters + name: 'ncwaf001' + virtualNetworkGateway1: { + id: '' + } + // Non-required parameters + connectionType: 'Vnet2Vnet' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + virtualNetworkGateway2: { + id: '' + } + vpnSharedKey: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ncwaf001" + }, + "virtualNetworkGateway1": { + "value": { + "id": "" + } + }, + // Non-required parameters + "connectionType": { + "value": "Vnet2Vnet" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "virtualNetworkGateway2": { + "value": { + "id": "" + } + }, + "vpnSharedKey": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/connection:' + +// Required parameters +param name = 'ncwaf001' +virtualNetworkGateway1: { + id: '' +} +// Non-required parameters +param connectionType = 'Vnet2Vnet' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +virtualNetworkGateway2: { + id: '' +} +param vpnSharedKey = '' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Remote connection name. | +| [`virtualNetworkGateway1`](#parameter-virtualnetworkgateway1) | object | The primary Virtual Network Gateway. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`authorizationKey`](#parameter-authorizationkey) | securestring | The Authorization Key to connect to an Express Route Circuit. Used for connection type [ExpressRoute]. | +| [`connectionMode`](#parameter-connectionmode) | string | The connection connectionMode for this connection. Available for IPSec connections. | +| [`connectionProtocol`](#parameter-connectionprotocol) | string | Connection connectionProtocol used for this connection. Available for IPSec connections. | +| [`connectionType`](#parameter-connectiontype) | string | Gateway connection connectionType. | +| [`customIPSecPolicy`](#parameter-customipsecpolicy) | object | The IPSec Policies to be considered by this connection. | +| [`dpdTimeoutSeconds`](#parameter-dpdtimeoutseconds) | int | The dead peer detection timeout of this connection in seconds. Setting the timeout to shorter periods will cause IKE to rekey more aggressively, causing the connection to appear to be disconnected in some instances. The general recommendation is to set the timeout between 30 to 45 seconds. | +| [`enableBgp`](#parameter-enablebgp) | bool | Value to specify if BGP is enabled or not. | +| [`enablePrivateLinkFastPath`](#parameter-enableprivatelinkfastpath) | bool | Bypass the ExpressRoute gateway when accessing private-links. ExpressRoute FastPath (expressRouteGatewayBypass) must be enabled. Only available when connection connectionType is Express Route. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`expressRouteGatewayBypass`](#parameter-expressroutegatewaybypass) | bool | Bypass ExpressRoute Gateway for data forwarding. Only available when connection connectionType is Express Route. | +| [`localNetworkGateway2`](#parameter-localnetworkgateway2) | object | The local network gateway. Used for connection type [IPsec]. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`peer`](#parameter-peer) | object | The remote peer. Used for connection connectionType [ExpressRoute]. | +| [`routingWeight`](#parameter-routingweight) | int | The weight added to routes learned from this BGP speaker. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`trafficSelectorPolicies`](#parameter-trafficselectorpolicies) | array | The traffic selector policies to be considered by this connection. | +| [`useLocalAzureIpAddress`](#parameter-uselocalazureipaddress) | bool | Use private local Azure IP for the connection. Only available for IPSec Virtual Network Gateways that use the Azure Private IP Property. | +| [`usePolicyBasedTrafficSelectors`](#parameter-usepolicybasedtrafficselectors) | bool | Enable policy-based traffic selectors. | +| [`virtualNetworkGateway2`](#parameter-virtualnetworkgateway2) | object | The remote Virtual Network Gateway. Used for connection connectionType [Vnet2Vnet]. | +| [`vpnSharedKey`](#parameter-vpnsharedkey) | securestring | Specifies a VPN shared key. The same value has to be specified on both Virtual Network Gateways. | + +### Parameter: `name` + +Remote connection name. + +- Required: Yes +- Type: string + +### Parameter: `virtualNetworkGateway1` + +The primary Virtual Network Gateway. + +- Required: Yes +- Type: object + +### Parameter: `authorizationKey` + +The Authorization Key to connect to an Express Route Circuit. Used for connection type [ExpressRoute]. + +- Required: No +- Type: securestring +- Default: `''` + +### Parameter: `connectionMode` + +The connection connectionMode for this connection. Available for IPSec connections. + +- Required: No +- Type: string +- Default: `'Default'` +- Allowed: + ```Bicep + [ + 'Default' + 'InitiatorOnly' + 'ResponderOnly' + ] + ``` + +### Parameter: `connectionProtocol` + +Connection connectionProtocol used for this connection. Available for IPSec connections. + +- Required: No +- Type: string +- Default: `'IKEv2'` +- Allowed: + ```Bicep + [ + 'IKEv1' + 'IKEv2' + ] + ``` + +### Parameter: `connectionType` + +Gateway connection connectionType. + +- Required: No +- Type: string +- Default: `'IPsec'` +- Allowed: + ```Bicep + [ + 'ExpressRoute' + 'IPsec' + 'Vnet2Vnet' + 'VPNClient' + ] + ``` + +### Parameter: `customIPSecPolicy` + +The IPSec Policies to be considered by this connection. + +- Required: No +- Type: object +- Default: + ```Bicep + { + dhGroup: '' + ikeEncryption: '' + ikeIntegrity: '' + ipsecEncryption: '' + ipsecIntegrity: '' + pfsGroup: '' + saDataSizeKilobytes: 0 + saLifeTimeSeconds: 0 + } + ``` + +### Parameter: `dpdTimeoutSeconds` + +The dead peer detection timeout of this connection in seconds. Setting the timeout to shorter periods will cause IKE to rekey more aggressively, causing the connection to appear to be disconnected in some instances. The general recommendation is to set the timeout between 30 to 45 seconds. + +- Required: No +- Type: int +- Default: `45` +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `enableBgp` + +Value to specify if BGP is enabled or not. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `enablePrivateLinkFastPath` + +Bypass the ExpressRoute gateway when accessing private-links. ExpressRoute FastPath (expressRouteGatewayBypass) must be enabled. Only available when connection connectionType is Express Route. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `expressRouteGatewayBypass` + +Bypass ExpressRoute Gateway for data forwarding. Only available when connection connectionType is Express Route. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `localNetworkGateway2` + +The local network gateway. Used for connection type [IPsec]. + +- Required: No +- Type: object +- Default: `{}` +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object +- MinValue: 9 +- MaxValue: 3600 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `peer` + +The remote peer. Used for connection connectionType [ExpressRoute]. + +- Required: No +- Type: object +- Default: `{}` +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `routingWeight` + +The weight added to routes learned from this BGP speaker. + +- Required: No +- Type: int +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `trafficSelectorPolicies` + +The traffic selector policies to be considered by this connection. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `useLocalAzureIpAddress` + +Use private local Azure IP for the connection. Only available for IPSec Virtual Network Gateways that use the Azure Private IP Property. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `usePolicyBasedTrafficSelectors` + +Enable policy-based traffic selectors. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `virtualNetworkGateway2` + +The remote Virtual Network Gateway. Used for connection connectionType [Vnet2Vnet]. + +- Required: No +- Type: object +- Default: `{}` +- MinValue: 9 +- MaxValue: 3600 + +### Parameter: `vpnSharedKey` + +Specifies a VPN shared key. The same value has to be specified on both Virtual Network Gateways. + +- Required: No +- Type: securestring +- Default: `''` +- MinValue: 9 +- MaxValue: 3600 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the remote connection. | +| `resourceGroupName` | string | The resource group the remote connection was deployed into. | +| `resourceId` | string | The resource ID of the remote connection. | + +## Notes + +### Parameter Usage: `localNetworkGateway2` + +The local virtual network gateway object. + +

+ +Parameter JSON format + +```json +"localNetworkGateway2": { + "value": { + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRG/providers/Microsoft.Network/localNetworkGateways/myGateway" + } +} +``` + +
+ +
+ +Bicep format + +```bicep +localNetworkGateway2: { + id: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRG/providers/Microsoft.Network/localNetworkGateways/myGateway' +} +``` + +
+

+ +### Parameter Usage: `peer` + +The remote peer object used for ExpressRoute connections + +

+ +Parameter JSON format + +```json +"peer": { + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRG/providers/Microsoft.Network/expressRouteCircuits/expressRoute" +} +``` + +
+ +
+ +Bicep format + +```bicep +'peer': { + id: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRG/providers/Microsoft.Network/expressRouteCircuits/expressRoute' +} +``` + +
+

+ +### Parameter Usage: `customIPSecPolicy` + +If ipsecEncryption parameter is empty, customIPSecPolicy will not be deployed. The parameter file should look like below. + +

+ +Parameter JSON format + +```json +"customIPSecPolicy": { + "value": { + "saLifeTimeSeconds": 0, + "saDataSizeKilobytes": 0, + "ipsecEncryption": "", + "ipsecIntegrity": "", + "ikeEncryption": "", + "ikeIntegrity": "", + "dhGroup": "", + "pfsGroup": "" + } +} +``` + +
+ +
+ +Bicep format + +```bicep +customIPSecPolicy: { + saLifeTimeSeconds: 0 + saDataSizeKilobytes: 0 + ipsecEncryption: '' + ipsecIntegrity: '' + ikeEncryption: '' + ikeIntegrity: '' + dhGroup: '' + pfsGroup: '' +} +``` + +
+

+ +Format of the full customIPSecPolicy parameter in parameter file. + +

+ +Parameter JSON format + +```json +"customIPSecPolicy": { + "value": { + "saLifeTimeSeconds": 28800, + "saDataSizeKilobytes": 102400000, + "ipsecEncryption": "AES256", + "ipsecIntegrity": "SHA256", + "ikeEncryption": "AES256", + "ikeIntegrity": "SHA256", + "dhGroup": "DHGroup14", + "pfsGroup": "None" + } +} +``` + +
+ +
+ +Bicep format + +```bicep +customIPSecPolicy: { + saLifeTimeSeconds: 28800 + saDataSizeKilobytes: 102400000 + ipsecEncryption: 'AES256' + ipsecIntegrity: 'SHA256' + ikeEncryption: 'AES256' + ikeIntegrity: 'SHA256' + dhGroup: 'DHGroup14' + pfsGroup: 'None' +} +``` + +
+

+ +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/connection/main.bicep b/avm/1.1.0/res/network/connection/main.bicep new file mode 100644 index 000000000..d7234ca90 --- /dev/null +++ b/avm/1.1.0/res/network/connection/main.bicep @@ -0,0 +1,192 @@ +metadata name = 'Virtual Network Gateway Connections' +metadata description = 'This module deploys a Virtual Network Gateway Connection.' + +@description('Required. Remote connection name.') +param name string + +@description('Optional. Specifies a VPN shared key. The same value has to be specified on both Virtual Network Gateways.') +@secure() +param vpnSharedKey string = '' + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Gateway connection connectionType.') +@allowed([ + 'IPsec' + 'Vnet2Vnet' + 'ExpressRoute' + 'VPNClient' +]) +param connectionType string = 'IPsec' + +@description('Optional. Value to specify if BGP is enabled or not.') +param enableBgp bool = false + +@allowed([ + 'Default' + 'InitiatorOnly' + 'ResponderOnly' +]) +@description('Optional. The connection connectionMode for this connection. Available for IPSec connections.') +param connectionMode string = 'Default' + +@allowed([ + 'IKEv1' + 'IKEv2' +]) +@description('Optional. Connection connectionProtocol used for this connection. Available for IPSec connections.') +param connectionProtocol string = 'IKEv2' + +@minValue(9) +@maxValue(3600) +@description('Optional. The dead peer detection timeout of this connection in seconds. Setting the timeout to shorter periods will cause IKE to rekey more aggressively, causing the connection to appear to be disconnected in some instances. The general recommendation is to set the timeout between 30 to 45 seconds.') +param dpdTimeoutSeconds int = 45 + +@description('Optional. Enable policy-based traffic selectors.') +param usePolicyBasedTrafficSelectors bool = false + +@description('Optional. The traffic selector policies to be considered by this connection.') +param trafficSelectorPolicies array = [] + +@description('Optional. Bypass the ExpressRoute gateway when accessing private-links. ExpressRoute FastPath (expressRouteGatewayBypass) must be enabled. Only available when connection connectionType is Express Route.') +param enablePrivateLinkFastPath bool = false + +@description('Optional. Bypass ExpressRoute Gateway for data forwarding. Only available when connection connectionType is Express Route.') +param expressRouteGatewayBypass bool = false + +@description('Optional. Use private local Azure IP for the connection. Only available for IPSec Virtual Network Gateways that use the Azure Private IP Property.') +param useLocalAzureIpAddress bool = false + +@description('Optional. The IPSec Policies to be considered by this connection.') +param customIPSecPolicy object = { + saLifeTimeSeconds: 0 + saDataSizeKilobytes: 0 + ipsecEncryption: '' + ipsecIntegrity: '' + ikeEncryption: '' + ikeIntegrity: '' + dhGroup: '' + pfsGroup: '' +} + +@description('Optional. The weight added to routes learned from this BGP speaker.') +param routingWeight int? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Required. The primary Virtual Network Gateway.') +param virtualNetworkGateway1 object + +@description('Optional. The remote Virtual Network Gateway. Used for connection connectionType [Vnet2Vnet].') +param virtualNetworkGateway2 object = {} + +@description('Optional. The remote peer. Used for connection connectionType [ExpressRoute].') +param peer object = {} + +@description('Optional. The Authorization Key to connect to an Express Route Circuit. Used for connection type [ExpressRoute].') +@secure() +param authorizationKey string = '' + +@description('Optional. The local network gateway. Used for connection type [IPsec].') +param localNetworkGateway2 object = {} + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-connection.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource connection 'Microsoft.Network/connections@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + connectionType: connectionType + connectionMode: connectionType == 'IPsec' ? connectionMode : null + connectionProtocol: connectionType == 'IPsec' ? connectionProtocol : null + dpdTimeoutSeconds: connectionType == 'IPsec' ? dpdTimeoutSeconds : null + enablePrivateLinkFastPath: connectionType == 'ExpressRoute' ? enablePrivateLinkFastPath : null + expressRouteGatewayBypass: connectionType == 'ExpressRoute' ? expressRouteGatewayBypass : null + virtualNetworkGateway1: virtualNetworkGateway1 + virtualNetworkGateway2: connectionType == 'Vnet2Vnet' ? virtualNetworkGateway2 : null + localNetworkGateway2: connectionType == 'IPsec' ? localNetworkGateway2 : null + peer: connectionType == 'ExpressRoute' ? peer : null + authorizationKey: connectionType == 'ExpressRoute' && !empty(authorizationKey) ? authorizationKey : null + sharedKey: connectionType != 'ExpressRoute' ? vpnSharedKey : null + trafficSelectorPolicies: trafficSelectorPolicies + usePolicyBasedTrafficSelectors: usePolicyBasedTrafficSelectors + ipsecPolicies: !empty(customIPSecPolicy.ipsecEncryption) + ? [ + { + saLifeTimeSeconds: customIPSecPolicy.saLifeTimeSeconds + saDataSizeKilobytes: customIPSecPolicy.saDataSizeKilobytes + ipsecEncryption: customIPSecPolicy.ipsecEncryption + ipsecIntegrity: customIPSecPolicy.ipsecIntegrity + ikeEncryption: customIPSecPolicy.ikeEncryption + ikeIntegrity: customIPSecPolicy.ikeIntegrity + dhGroup: customIPSecPolicy.dhGroup + pfsGroup: customIPSecPolicy.pfsGroup + } + ] + : customIPSecPolicy.ipsecEncryption + routingWeight: routingWeight + enableBgp: enableBgp + useLocalAzureIpAddress: connectionType == 'IPsec' ? useLocalAzureIpAddress : null + } +} + +resource connection_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: connection +} + +@description('The resource group the remote connection was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the remote connection.') +output name string = connection.name + +@description('The resource ID of the remote connection.') +output resourceId string = connection.id + +@description('The location the resource was deployed into.') +output location string = connection.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? diff --git a/avm/1.1.0/res/network/connection/main.json b/avm/1.1.0/res/network/connection/main.json new file mode 100644 index 000000000..6813c8d73 --- /dev/null +++ b/avm/1.1.0/res/network/connection/main.json @@ -0,0 +1,320 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "16708365191698233547" + }, + "name": "Virtual Network Gateway Connections", + "description": "This module deploys a Virtual Network Gateway Connection." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Remote connection name." + } + }, + "vpnSharedKey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies a VPN shared key. The same value has to be specified on both Virtual Network Gateways." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "connectionType": { + "type": "string", + "defaultValue": "IPsec", + "allowedValues": [ + "IPsec", + "Vnet2Vnet", + "ExpressRoute", + "VPNClient" + ], + "metadata": { + "description": "Optional. Gateway connection connectionType." + } + }, + "enableBgp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Value to specify if BGP is enabled or not." + } + }, + "connectionMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "InitiatorOnly", + "ResponderOnly" + ], + "metadata": { + "description": "Optional. The connection connectionMode for this connection. Available for IPSec connections." + } + }, + "connectionProtocol": { + "type": "string", + "defaultValue": "IKEv2", + "allowedValues": [ + "IKEv1", + "IKEv2" + ], + "metadata": { + "description": "Optional. Connection connectionProtocol used for this connection. Available for IPSec connections." + } + }, + "dpdTimeoutSeconds": { + "type": "int", + "defaultValue": 45, + "minValue": 9, + "maxValue": 3600, + "metadata": { + "description": "Optional. The dead peer detection timeout of this connection in seconds. Setting the timeout to shorter periods will cause IKE to rekey more aggressively, causing the connection to appear to be disconnected in some instances. The general recommendation is to set the timeout between 30 to 45 seconds." + } + }, + "usePolicyBasedTrafficSelectors": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable policy-based traffic selectors." + } + }, + "trafficSelectorPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The traffic selector policies to be considered by this connection." + } + }, + "enablePrivateLinkFastPath": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bypass the ExpressRoute gateway when accessing private-links. ExpressRoute FastPath (expressRouteGatewayBypass) must be enabled. Only available when connection connectionType is Express Route." + } + }, + "expressRouteGatewayBypass": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bypass ExpressRoute Gateway for data forwarding. Only available when connection connectionType is Express Route." + } + }, + "useLocalAzureIpAddress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Use private local Azure IP for the connection. Only available for IPSec Virtual Network Gateways that use the Azure Private IP Property." + } + }, + "customIPSecPolicy": { + "type": "object", + "defaultValue": { + "saLifeTimeSeconds": 0, + "saDataSizeKilobytes": 0, + "ipsecEncryption": "", + "ipsecIntegrity": "", + "ikeEncryption": "", + "ikeIntegrity": "", + "dhGroup": "", + "pfsGroup": "" + }, + "metadata": { + "description": "Optional. The IPSec Policies to be considered by this connection." + } + }, + "routingWeight": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The weight added to routes learned from this BGP speaker." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "virtualNetworkGateway1": { + "type": "object", + "metadata": { + "description": "Required. The primary Virtual Network Gateway." + } + }, + "virtualNetworkGateway2": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The remote Virtual Network Gateway. Used for connection connectionType [Vnet2Vnet]." + } + }, + "peer": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The remote peer. Used for connection connectionType [ExpressRoute]." + } + }, + "authorizationKey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. The Authorization Key to connect to an Express Route Circuit. Used for connection type [ExpressRoute]." + } + }, + "localNetworkGateway2": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The local network gateway. Used for connection type [IPsec]." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-connection.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "connection": { + "type": "Microsoft.Network/connections", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "connectionType": "[parameters('connectionType')]", + "connectionMode": "[if(equals(parameters('connectionType'), 'IPsec'), parameters('connectionMode'), null())]", + "connectionProtocol": "[if(equals(parameters('connectionType'), 'IPsec'), parameters('connectionProtocol'), null())]", + "dpdTimeoutSeconds": "[if(equals(parameters('connectionType'), 'IPsec'), parameters('dpdTimeoutSeconds'), null())]", + "enablePrivateLinkFastPath": "[if(equals(parameters('connectionType'), 'ExpressRoute'), parameters('enablePrivateLinkFastPath'), null())]", + "expressRouteGatewayBypass": "[if(equals(parameters('connectionType'), 'ExpressRoute'), parameters('expressRouteGatewayBypass'), null())]", + "virtualNetworkGateway1": "[parameters('virtualNetworkGateway1')]", + "virtualNetworkGateway2": "[if(equals(parameters('connectionType'), 'Vnet2Vnet'), parameters('virtualNetworkGateway2'), null())]", + "localNetworkGateway2": "[if(equals(parameters('connectionType'), 'IPsec'), parameters('localNetworkGateway2'), null())]", + "peer": "[if(equals(parameters('connectionType'), 'ExpressRoute'), parameters('peer'), null())]", + "authorizationKey": "[if(and(equals(parameters('connectionType'), 'ExpressRoute'), not(empty(parameters('authorizationKey')))), parameters('authorizationKey'), null())]", + "sharedKey": "[if(not(equals(parameters('connectionType'), 'ExpressRoute')), parameters('vpnSharedKey'), null())]", + "trafficSelectorPolicies": "[parameters('trafficSelectorPolicies')]", + "usePolicyBasedTrafficSelectors": "[parameters('usePolicyBasedTrafficSelectors')]", + "ipsecPolicies": "[if(not(empty(parameters('customIPSecPolicy').ipsecEncryption)), createArray(createObject('saLifeTimeSeconds', parameters('customIPSecPolicy').saLifeTimeSeconds, 'saDataSizeKilobytes', parameters('customIPSecPolicy').saDataSizeKilobytes, 'ipsecEncryption', parameters('customIPSecPolicy').ipsecEncryption, 'ipsecIntegrity', parameters('customIPSecPolicy').ipsecIntegrity, 'ikeEncryption', parameters('customIPSecPolicy').ikeEncryption, 'ikeIntegrity', parameters('customIPSecPolicy').ikeIntegrity, 'dhGroup', parameters('customIPSecPolicy').dhGroup, 'pfsGroup', parameters('customIPSecPolicy').pfsGroup)), parameters('customIPSecPolicy').ipsecEncryption)]", + "routingWeight": "[parameters('routingWeight')]", + "enableBgp": "[parameters('enableBgp')]", + "useLocalAzureIpAddress": "[if(equals(parameters('connectionType'), 'IPsec'), parameters('useLocalAzureIpAddress'), null())]" + } + }, + "connection_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/connections/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "connection" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the remote connection was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the remote connection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the remote connection." + }, + "value": "[resourceId('Microsoft.Network/connections', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('connection', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/connection/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/connection/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..3cb851874 --- /dev/null +++ b/avm/1.1.0/res/network/connection/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,144 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the primary Public IP to create.') +param primaryPublicIPName string + +@description('Required. The name of the primary VNET to create.') +param primaryVirtualNetworkName string + +@description('Required. The name of the primary Virtual Network Gateway to create.') +param primaryVirtualNetworkGatewayName string + +@description('Required. The name of the secondary Public IP to create.') +param secondaryPublicIPName string + +@description('Required. The name of the secondary VNET to create.') +param secondaryVirtualNetworkName string + +@description('Required. The name of the secondary Virtual Network Gateway to create.') +param secondaryVirtualNetworkGatewayName string + +resource primaryVirtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: primaryVirtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.0.0.0/24' + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: '10.0.0.0/24' + } + } + ] + } +} + +resource primaryPublicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: primaryPublicIPName + location: location + properties: { + publicIPAllocationMethod: 'Static' + } + sku: { + name: 'Standard' + } +} + +resource primaryVNETGateway 'Microsoft.Network/virtualNetworkGateways@2023-04-01' = { + name: primaryVirtualNetworkGatewayName + location: location + properties: { + gatewayType: 'Vpn' + ipConfigurations: [ + { + name: 'default' + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: primaryVirtualNetwork.properties.subnets[0].id + } + publicIPAddress: { + id: primaryPublicIP.id + } + } + } + ] + vpnType: 'RouteBased' + vpnGatewayGeneration: 'Generation2' + sku: { + name: 'VpnGw2' + tier: 'VpnGw2' + } + } +} + +resource secondaryVirtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: secondaryVirtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.0.1.0/24' + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: '10.0.1.0/24' + } + } + ] + } +} + +resource secondaryPublicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: secondaryPublicIPName + location: location + properties: { + publicIPAllocationMethod: 'Static' + } + sku: { + name: 'Standard' + } +} + +resource secondaryVNETGateway 'Microsoft.Network/virtualNetworkGateways@2023-04-01' = { + name: secondaryVirtualNetworkGatewayName + location: location + properties: { + gatewayType: 'Vpn' + ipConfigurations: [ + { + name: 'default' + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: secondaryVirtualNetwork.properties.subnets[0].id + } + publicIPAddress: { + id: secondaryPublicIP.id + } + } + } + ] + vpnType: 'RouteBased' + vpnGatewayGeneration: 'Generation2' + sku: { + name: 'VpnGw2' + tier: 'VpnGw2' + } + } +} + +@description('The resource ID of the created primary Virtual Network Gateway.') +output primaryVNETGatewayResourceID string = primaryVNETGateway.id + +@description('The resource ID of the created secondary Virtual Network Gateway.') +output secondaryVNETGatewayResourceID string = secondaryVNETGateway.id diff --git a/avm/1.1.0/res/network/connection/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/connection/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..173f43b4a --- /dev/null +++ b/avm/1.1.0/res/network/connection/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,77 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.connections-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ncmin' + +@description('Optional. The password to leverage for the shared key.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + primaryPublicIPName: 'dep-${namePrefix}-pip-${serviceShort}-1' + primaryVirtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}-1' + primaryVirtualNetworkGatewayName: 'dep-${namePrefix}-vpn-gw-${serviceShort}-1' + secondaryPublicIPName: 'dep-${namePrefix}-pip-${serviceShort}-2' + secondaryVirtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}-2' + secondaryVirtualNetworkGatewayName: 'dep-${namePrefix}-vpn-gw-${serviceShort}-2' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualNetworkGateway1: { + id: nestedDependencies.outputs.primaryVNETGatewayResourceID + } + virtualNetworkGateway2: { + id: nestedDependencies.outputs.secondaryVNETGatewayResourceID + } + connectionType: 'Vnet2Vnet' + vpnSharedKey: password + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/connection/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/connection/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..f180cae86 --- /dev/null +++ b/avm/1.1.0/res/network/connection/tests/e2e/max/dependencies.bicep @@ -0,0 +1,144 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the primary Public IP to create.') +param primaryPublicIPName string + +@description('Required. The name of the primary VNET to create.') +param primaryVirtualNetworkName string + +@description('Required. The name of the primary Virtual Network Gateway to create.') +param primaryVirtualNetworkGatewayName string + +@description('Required. The name of the secondary Public IP to create.') +param secondaryPublicIPName string + +@description('Required. The name of the secondary VNET to create.') +param secondaryVirtualNetworkName string + +@description('Required. The name of the secondary Virtual Network Gateway to create.') +param secondaryVirtualNetworkGatewayName string + +resource primaryVirtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: primaryVirtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.0.0.0/24' + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: '10.0.0.0/24' + } + } + ] + } +} + +resource primaryPublicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: primaryPublicIPName + location: location + properties: { + publicIPAllocationMethod: 'Static' + } + sku: { + name: 'Standard' + } +} + +resource primaryVNETGateway 'Microsoft.Network/virtualNetworkGateways@2023-04-01' = { + name: primaryVirtualNetworkGatewayName + location: location + properties: { + gatewayType: 'Vpn' + ipConfigurations: [ + { + name: 'default' + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: primaryVirtualNetwork.properties.subnets[0].id + } + publicIPAddress: { + id: primaryPublicIP.id + } + } + } + ] + vpnType: 'RouteBased' + vpnGatewayGeneration: 'Generation2' + sku: { + name: 'VpnGw2' + tier: 'VpnGw2' + } + } +} + +resource secondaryVirtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: secondaryVirtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.0.1.0/24' + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: '10.0.1.0/24' + } + } + ] + } +} + +resource secondaryPublicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: secondaryPublicIPName + location: location + properties: { + publicIPAllocationMethod: 'Static' + } + sku: { + name: 'Standard' + } +} + +resource secondaryVNETGateway 'Microsoft.Network/virtualNetworkGateways@2023-04-01' = { + name: secondaryVirtualNetworkGatewayName + location: location + properties: { + gatewayType: 'Vpn' + ipConfigurations: [ + { + name: 'default' + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: secondaryVirtualNetwork.properties.subnets[0].id + } + publicIPAddress: { + id: secondaryPublicIP.id + } + } + } + ] + vpnType: 'RouteBased' + vpnGatewayGeneration: 'Generation2' + sku: { + name: 'VpnGw2' + tier: 'VpnGw2' + } + } +} + +@description('The resource ID of the created primary Virtual Network Gateway.') +output primaryVNETGatewayResourceID string = primaryVNETGateway.id + +@description('The resource ID of the created secondary Virtual Network Gateway.') +output secondaryVNETGatewayResourceID string = secondaryVNETGateway.id diff --git a/avm/1.1.0/res/network/connection/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/connection/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..e1b1154c0 --- /dev/null +++ b/avm/1.1.0/res/network/connection/tests/e2e/max/main.test.bicep @@ -0,0 +1,89 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.connections-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ncmax' + +@description('Optional. The password to leverage for the shared key.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + primaryPublicIPName: 'dep-${namePrefix}-pip-${serviceShort}-1' + primaryVirtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}-1' + primaryVirtualNetworkGatewayName: 'dep-${namePrefix}-vpn-gw-${serviceShort}-1' + secondaryPublicIPName: 'dep-${namePrefix}-pip-${serviceShort}-2' + secondaryVirtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}-2' + secondaryVirtualNetworkGatewayName: 'dep-${namePrefix}-vpn-gw-${serviceShort}-2' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualNetworkGateway1: { + id: nestedDependencies.outputs.primaryVNETGatewayResourceID + } + enableBgp: false + usePolicyBasedTrafficSelectors: false + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + virtualNetworkGateway2: { + id: nestedDependencies.outputs.secondaryVNETGatewayResourceID + } + connectionType: 'Vnet2Vnet' + dpdTimeoutSeconds: 45 + vpnSharedKey: password + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/connection/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/connection/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..f180cae86 --- /dev/null +++ b/avm/1.1.0/res/network/connection/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,144 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the primary Public IP to create.') +param primaryPublicIPName string + +@description('Required. The name of the primary VNET to create.') +param primaryVirtualNetworkName string + +@description('Required. The name of the primary Virtual Network Gateway to create.') +param primaryVirtualNetworkGatewayName string + +@description('Required. The name of the secondary Public IP to create.') +param secondaryPublicIPName string + +@description('Required. The name of the secondary VNET to create.') +param secondaryVirtualNetworkName string + +@description('Required. The name of the secondary Virtual Network Gateway to create.') +param secondaryVirtualNetworkGatewayName string + +resource primaryVirtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: primaryVirtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.0.0.0/24' + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: '10.0.0.0/24' + } + } + ] + } +} + +resource primaryPublicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: primaryPublicIPName + location: location + properties: { + publicIPAllocationMethod: 'Static' + } + sku: { + name: 'Standard' + } +} + +resource primaryVNETGateway 'Microsoft.Network/virtualNetworkGateways@2023-04-01' = { + name: primaryVirtualNetworkGatewayName + location: location + properties: { + gatewayType: 'Vpn' + ipConfigurations: [ + { + name: 'default' + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: primaryVirtualNetwork.properties.subnets[0].id + } + publicIPAddress: { + id: primaryPublicIP.id + } + } + } + ] + vpnType: 'RouteBased' + vpnGatewayGeneration: 'Generation2' + sku: { + name: 'VpnGw2' + tier: 'VpnGw2' + } + } +} + +resource secondaryVirtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: secondaryVirtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.0.1.0/24' + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: '10.0.1.0/24' + } + } + ] + } +} + +resource secondaryPublicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: secondaryPublicIPName + location: location + properties: { + publicIPAllocationMethod: 'Static' + } + sku: { + name: 'Standard' + } +} + +resource secondaryVNETGateway 'Microsoft.Network/virtualNetworkGateways@2023-04-01' = { + name: secondaryVirtualNetworkGatewayName + location: location + properties: { + gatewayType: 'Vpn' + ipConfigurations: [ + { + name: 'default' + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: secondaryVirtualNetwork.properties.subnets[0].id + } + publicIPAddress: { + id: secondaryPublicIP.id + } + } + } + ] + vpnType: 'RouteBased' + vpnGatewayGeneration: 'Generation2' + sku: { + name: 'VpnGw2' + tier: 'VpnGw2' + } + } +} + +@description('The resource ID of the created primary Virtual Network Gateway.') +output primaryVNETGatewayResourceID string = primaryVNETGateway.id + +@description('The resource ID of the created secondary Virtual Network Gateway.') +output secondaryVNETGatewayResourceID string = secondaryVNETGateway.id diff --git a/avm/1.1.0/res/network/connection/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/connection/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..4d1329495 --- /dev/null +++ b/avm/1.1.0/res/network/connection/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,86 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.connections-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ncwaf' + +@description('Optional. The password to leverage for the shared key.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + primaryPublicIPName: 'dep-${namePrefix}-pip-${serviceShort}-1' + primaryVirtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}-1' + primaryVirtualNetworkGatewayName: 'dep-${namePrefix}-vpn-gw-${serviceShort}-1' + secondaryPublicIPName: 'dep-${namePrefix}-pip-${serviceShort}-2' + secondaryVirtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}-2' + secondaryVirtualNetworkGatewayName: 'dep-${namePrefix}-vpn-gw-${serviceShort}-2' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualNetworkGateway1: { + id: nestedDependencies.outputs.primaryVNETGatewayResourceID + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + virtualNetworkGateway2: { + id: nestedDependencies.outputs.secondaryVNETGatewayResourceID + } + connectionType: 'Vnet2Vnet' + vpnSharedKey: password + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/connection/version.json b/avm/1.1.0/res/network/connection/version.json new file mode 100644 index 000000000..8def869ed --- /dev/null +++ b/avm/1.1.0/res/network/connection/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/res/network/ddos-protection-plan/README.md b/avm/1.1.0/res/network/ddos-protection-plan/README.md new file mode 100644 index 000000000..6465acbe1 --- /dev/null +++ b/avm/1.1.0/res/network/ddos-protection-plan/README.md @@ -0,0 +1,544 @@ +# DDoS Protection Plans `[Microsoft.Network/ddosProtectionPlans]` + +This module deploys a DDoS Protection Plan. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/ddosProtectionPlans` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/ddosProtectionPlans) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/ddos-protection-plan:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan:' = { + name: 'ddosProtectionPlanDeployment' + params: { + // Required parameters + name: 'ndppmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ndppmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/ddos-protection-plan:' + +// Required parameters +param name = 'ndppmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan:' = { + name: 'ddosProtectionPlanDeployment' + params: { + // Required parameters + name: 'ndppmax001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '60339368-138d-4667-988a-5431c156f6ff' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ndppmax001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "60339368-138d-4667-988a-5431c156f6ff", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/ddos-protection-plan:' + +// Required parameters +param name = 'ndppmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '60339368-138d-4667-988a-5431c156f6ff' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan:' = { + name: 'ddosProtectionPlanDeployment' + params: { + // Required parameters + name: 'ndppwaf001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ndppwaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/ddos-protection-plan:' + +// Required parameters +param name = 'ndppwaf001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the DDoS protection plan to assign the VNET to. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `name` + +Name of the DDoS protection plan to assign the VNET to. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the DDOS protection plan. | +| `resourceGroupName` | string | The resource group the DDOS protection plan was deployed into. | +| `resourceId` | string | The resource ID of the DDOS protection plan. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/ddos-protection-plan/main.bicep b/avm/1.1.0/res/network/ddos-protection-plan/main.bicep new file mode 100644 index 000000000..ca9846d95 --- /dev/null +++ b/avm/1.1.0/res/network/ddos-protection-plan/main.bicep @@ -0,0 +1,153 @@ +metadata name = 'DDoS Protection Plans' +metadata description = 'This module deploys a DDoS Protection Plan.' + +@description('Required. Name of the DDoS protection plan to assign the VNET to.') +@minLength(1) +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-ddosprotectionplan.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource ddosProtectionPlan 'Microsoft.Network/ddosProtectionPlans@2023-11-01' = { + name: name + location: location + tags: tags + properties: {} +} + +resource ddosProtectionPlan_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: ddosProtectionPlan +} + +resource ddosProtectionPlan_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + ddosProtectionPlan.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: ddosProtectionPlan + } +] + +@description('The resource group the DDOS protection plan was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the DDOS protection plan.') +output resourceId string = ddosProtectionPlan.id + +@description('The name of the DDOS protection plan.') +output name string = ddosProtectionPlan.name + +@description('The location the resource was deployed into.') +output location string = ddosProtectionPlan.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/ddos-protection-plan/main.json b/avm/1.1.0/res/network/ddos-protection-plan/main.json new file mode 100644 index 000000000..c336e4136 --- /dev/null +++ b/avm/1.1.0/res/network/ddos-protection-plan/main.json @@ -0,0 +1,268 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "7591812138560338682" + }, + "name": "DDoS Protection Plans", + "description": "This module deploys a DDoS Protection Plan." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the DDoS protection plan to assign the VNET to." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-ddosprotectionplan.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "ddosProtectionPlan": { + "type": "Microsoft.Network/ddosProtectionPlans", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + }, + "ddosProtectionPlan_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/ddosProtectionPlans/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "ddosProtectionPlan" + ] + }, + "ddosProtectionPlan_roleAssignments": { + "copy": { + "name": "ddosProtectionPlan_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/ddosProtectionPlans/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/ddosProtectionPlans', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "ddosProtectionPlan" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the DDOS protection plan was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the DDOS protection plan." + }, + "value": "[resourceId('Microsoft.Network/ddosProtectionPlans', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the DDOS protection plan." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('ddosProtectionPlan', '2023-11-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..c8278af04 --- /dev/null +++ b/avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,49 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.ddosprotectionplans-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ndppmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// Due to quotas and capacity challenges, this region must be used in the AVM testing subscription +#disable-next-line no-hardcoded-location +var enforcedLocation = 'eastus' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + } +} diff --git a/avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..2f167d322 --- /dev/null +++ b/avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/max/main.test.bicep @@ -0,0 +1,86 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.ddosprotectionplans-${serviceShort}-rg' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ndppmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// Due to quotas and capacity challenges, this region must be used in the AVM testing subscription +#disable-next-line no-hardcoded-location +var enforcedLocation = 'northeurope' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '60339368-138d-4667-988a-5431c156f6ff' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} diff --git a/avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..59624646f --- /dev/null +++ b/avm/1.1.0/res/network/ddos-protection-plan/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,58 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.ddosprotectionplans-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ndppwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// Due to quotas and capacity challenges, this region must be used in the AVM testing subscription +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} diff --git a/avm/1.1.0/res/network/ddos-protection-plan/version.json b/avm/1.1.0/res/network/ddos-protection-plan/version.json new file mode 100644 index 000000000..c177b1bb5 --- /dev/null +++ b/avm/1.1.0/res/network/ddos-protection-plan/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/README.md b/avm/1.1.0/res/network/dns-forwarding-ruleset/README.md new file mode 100644 index 000000000..8e1cb79b7 --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/README.md @@ -0,0 +1,771 @@ +# Dns Forwarding Rulesets `[Microsoft.Network/dnsForwardingRulesets]` + +This template deploys an dns forwarding ruleset. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/dnsForwardingRulesets` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/dnsForwardingRulesets) | +| `Microsoft.Network/dnsForwardingRulesets/forwardingRules` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/dnsForwardingRulesets/forwardingRules) | +| `Microsoft.Network/dnsForwardingRulesets/virtualNetworkLinks` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/dnsForwardingRulesets/virtualNetworkLinks) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/dns-forwarding-ruleset:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:' = { + name: 'dnsForwardingRulesetDeployment' + params: { + // Required parameters + dnsForwardingRulesetOutboundEndpointResourceIds: [ + '' + ] + name: 'ndfrsmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dnsForwardingRulesetOutboundEndpointResourceIds": { + "value": [ + "" + ] + }, + "name": { + "value": "ndfrsmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-forwarding-ruleset:' + +// Required parameters +param dnsForwardingRulesetOutboundEndpointResourceIds = [ + '' +] +param name = 'ndfrsmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:' = { + name: 'dnsForwardingRulesetDeployment' + params: { + // Required parameters + dnsForwardingRulesetOutboundEndpointResourceIds: [ + '' + ] + name: 'ndfrsmax001' + // Non-required parameters + forwardingRules: [ + { + domainName: 'contoso.' + forwardingRuleState: 'Enabled' + name: 'rule1' + targetDnsServers: [ + { + ipAddress: '192.168.0.1' + port: 53 + } + ] + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '38837eb6-838b-4c77-8d7d-baa102195d9f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + virtualNetworkLinks: [ + { + name: 'mytestvnetlink1' + virtualNetworkResourceId: '' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dnsForwardingRulesetOutboundEndpointResourceIds": { + "value": [ + "" + ] + }, + "name": { + "value": "ndfrsmax001" + }, + // Non-required parameters + "forwardingRules": { + "value": [ + { + "domainName": "contoso.", + "forwardingRuleState": "Enabled", + "name": "rule1", + "targetDnsServers": [ + { + "ipAddress": "192.168.0.1", + "port": 53 + } + ] + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "38837eb6-838b-4c77-8d7d-baa102195d9f", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "virtualNetworkLinks": { + "value": [ + { + "name": "mytestvnetlink1", + "virtualNetworkResourceId": "" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-forwarding-ruleset:' + +// Required parameters +param dnsForwardingRulesetOutboundEndpointResourceIds = [ + '' +] +param name = 'ndfrsmax001' +// Non-required parameters +param forwardingRules = [ + { + domainName: 'contoso.' + forwardingRuleState: 'Enabled' + name: 'rule1' + targetDnsServers: [ + { + ipAddress: '192.168.0.1' + port: 53 + } + ] + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '38837eb6-838b-4c77-8d7d-baa102195d9f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param virtualNetworkLinks = [ + { + name: 'mytestvnetlink1' + virtualNetworkResourceId: '' + } +] +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:' = { + name: 'dnsForwardingRulesetDeployment' + params: { + // Required parameters + dnsForwardingRulesetOutboundEndpointResourceIds: [ + '' + ] + name: 'ndfrswaf001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "dnsForwardingRulesetOutboundEndpointResourceIds": { + "value": [ + "" + ] + }, + "name": { + "value": "ndfrswaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-forwarding-ruleset:' + +// Required parameters +param dnsForwardingRulesetOutboundEndpointResourceIds = [ + '' +] +param name = 'ndfrswaf001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsForwardingRulesetOutboundEndpointResourceIds`](#parameter-dnsforwardingrulesetoutboundendpointresourceids) | array | The reference to the DNS resolver outbound endpoints that are used to route DNS queries matching the forwarding rules in the ruleset to the target DNS servers. | +| [`name`](#parameter-name) | string | Name of the DNS Forwarding Ruleset. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`forwardingRules`](#parameter-forwardingrules) | array | Array of forwarding rules. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`virtualNetworkLinks`](#parameter-virtualnetworklinks) | array | Array of virtual network links. | + +### Parameter: `dnsForwardingRulesetOutboundEndpointResourceIds` + +The reference to the DNS resolver outbound endpoints that are used to route DNS queries matching the forwarding rules in the ruleset to the target DNS servers. + +- Required: Yes +- Type: array + +### Parameter: `name` + +Name of the DNS Forwarding Ruleset. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `forwardingRules` + +Array of forwarding rules. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`domainName`](#parameter-forwardingrulesdomainname) | string | The domain name to forward. | +| [`name`](#parameter-forwardingrulesname) | string | The name of the forwarding rule. | +| [`targetDnsServers`](#parameter-forwardingrulestargetdnsservers) | array | The target DNS servers to forward to. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`forwardingRuleState`](#parameter-forwardingrulesforwardingrulestate) | string | The state of the forwarding rule. | +| [`metadata`](#parameter-forwardingrulesmetadata) | string | Metadata attached to the forwarding rule. | + +### Parameter: `forwardingRules.domainName` + +The domain name to forward. + +- Required: Yes +- Type: string + +### Parameter: `forwardingRules.name` + +The name of the forwarding rule. + +- Required: Yes +- Type: string + +### Parameter: `forwardingRules.targetDnsServers` + +The target DNS servers to forward to. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipAddress`](#parameter-forwardingrulestargetdnsserversipaddress) | string | The IP address of the target DNS server. | +| [`port`](#parameter-forwardingrulestargetdnsserversport) | int | The port of the target DNS server. | + +### Parameter: `forwardingRules.targetDnsServers.ipAddress` + +The IP address of the target DNS server. + +- Required: Yes +- Type: string + +### Parameter: `forwardingRules.targetDnsServers.port` + +The port of the target DNS server. + +- Required: Yes +- Type: int + +### Parameter: `forwardingRules.forwardingRuleState` + +The state of the forwarding rule. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `forwardingRules.metadata` + +Metadata attached to the forwarding rule. + +- Required: No +- Type: string + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `virtualNetworkLinks` + +Array of virtual network links. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`virtualNetworkResourceId`](#parameter-virtualnetworklinksvirtualnetworkresourceid) | string | The resource ID of the virtual network to link. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-virtualnetworklinksname) | string | The name of the virtual network link. | + +### Parameter: `virtualNetworkLinks.virtualNetworkResourceId` + +The resource ID of the virtual network to link. + +- Required: Yes +- Type: string + +### Parameter: `virtualNetworkLinks.name` + +The name of the virtual network link. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the DNS Forwarding Ruleset. | +| `resourceGroupName` | string | The resource group the DNS Forwarding Ruleset was deployed into. | +| `resourceId` | string | The resource ID of the DNS Forwarding Ruleset. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/forwarding-rule/README.md b/avm/1.1.0/res/network/dns-forwarding-ruleset/forwarding-rule/README.md new file mode 100644 index 000000000..d50e22a2e --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/forwarding-rule/README.md @@ -0,0 +1,88 @@ +# Dns Forwarding Rulesets Forwarding Rules `[Microsoft.Network/dnsForwardingRulesets/forwardingRules]` + +This template deploys Forwarding Rule in a Dns Forwarding Ruleset. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/dnsForwardingRulesets/forwardingRules` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/dnsForwardingRulesets/forwardingRules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`domainName`](#parameter-domainname) | string | The domain name for the forwarding rule. | +| [`name`](#parameter-name) | string | Name of the Forwarding Rule. | +| [`targetDnsServers`](#parameter-targetdnsservers) | array | DNS servers to forward the DNS query to. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsForwardingRulesetName`](#parameter-dnsforwardingrulesetname) | string | Name of the parent DNS Forwarding Ruleset. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`forwardingRuleState`](#parameter-forwardingrulestate) | string | The state of forwarding rule. | +| [`metadata`](#parameter-metadata) | object | Metadata attached to the forwarding rule. | + +### Parameter: `domainName` + +The domain name for the forwarding rule. + +- Required: Yes +- Type: string + +### Parameter: `name` + +Name of the Forwarding Rule. + +- Required: Yes +- Type: string + +### Parameter: `targetDnsServers` + +DNS servers to forward the DNS query to. + +- Required: Yes +- Type: array + +### Parameter: `dnsForwardingRulesetName` + +Name of the parent DNS Forwarding Ruleset. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `forwardingRuleState` + +The state of forwarding rule. + +- Required: No +- Type: string + +### Parameter: `metadata` + +Metadata attached to the forwarding rule. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the Forwarding Rule. | +| `resourceGroupName` | string | The resource group the Forwarding Rule was deployed into. | +| `resourceId` | string | The resource ID of the Forwarding Rule. | diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/forwarding-rule/main.bicep b/avm/1.1.0/res/network/dns-forwarding-ruleset/forwarding-rule/main.bicep new file mode 100644 index 000000000..46e17903d --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/forwarding-rule/main.bicep @@ -0,0 +1,45 @@ +metadata name = 'Dns Forwarding Rulesets Forwarding Rules' +metadata description = 'This template deploys Forwarding Rule in a Dns Forwarding Ruleset.' + +@description('Required. Name of the Forwarding Rule.') +@minLength(1) +param name string + +@description('Conditional. Name of the parent DNS Forwarding Ruleset. Required if the template is used in a standalone deployment.') +param dnsForwardingRulesetName string + +@description('Required. The domain name for the forwarding rule.') +param domainName string + +@description('Optional. The state of forwarding rule.') +param forwardingRuleState string? + +@description('Optional. Metadata attached to the forwarding rule.') +param metadata object? + +@description('Required. DNS servers to forward the DNS query to.') +param targetDnsServers array + +resource dnsForwardingRuleset 'Microsoft.Network/dnsForwardingRulesets@2022-07-01' existing = { + name: dnsForwardingRulesetName +} + +resource forwardingRule 'Microsoft.Network/dnsForwardingRulesets/forwardingRules@2022-07-01' = { + name: name + parent: dnsForwardingRuleset + properties: { + domainName: domainName + forwardingRuleState: forwardingRuleState + metadata: metadata + targetDnsServers: targetDnsServers + } +} + +@description('The resource group the Forwarding Rule was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the Forwarding Rule.') +output resourceId string = forwardingRule.id + +@description('The name of the Forwarding Rule.') +output name string = forwardingRule.name diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/forwarding-rule/main.json b/avm/1.1.0/res/network/dns-forwarding-ruleset/forwarding-rule/main.json new file mode 100644 index 000000000..9125e8a29 --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/forwarding-rule/main.json @@ -0,0 +1,97 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "18374273039902105155" + }, + "name": "Dns Forwarding Rulesets Forwarding Rules", + "description": "This template deploys Forwarding Rule in a Dns Forwarding Ruleset." + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the Forwarding Rule." + } + }, + "dnsForwardingRulesetName": { + "type": "string", + "metadata": { + "description": "Conditional. Name of the parent DNS Forwarding Ruleset. Required if the template is used in a standalone deployment." + } + }, + "domainName": { + "type": "string", + "metadata": { + "description": "Required. The domain name for the forwarding rule." + } + }, + "forwardingRuleState": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The state of forwarding rule." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Metadata attached to the forwarding rule." + } + }, + "targetDnsServers": { + "type": "array", + "metadata": { + "description": "Required. DNS servers to forward the DNS query to." + } + } + }, + "resources": { + "dnsForwardingRuleset": { + "existing": true, + "type": "Microsoft.Network/dnsForwardingRulesets", + "apiVersion": "2022-07-01", + "name": "[parameters('dnsForwardingRulesetName')]" + }, + "forwardingRule": { + "type": "Microsoft.Network/dnsForwardingRulesets/forwardingRules", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('dnsForwardingRulesetName'), parameters('name'))]", + "properties": { + "domainName": "[parameters('domainName')]", + "forwardingRuleState": "[parameters('forwardingRuleState')]", + "metadata": "[parameters('metadata')]", + "targetDnsServers": "[parameters('targetDnsServers')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Forwarding Rule was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Forwarding Rule." + }, + "value": "[resourceId('Microsoft.Network/dnsForwardingRulesets/forwardingRules', parameters('dnsForwardingRulesetName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Forwarding Rule." + }, + "value": "[parameters('name')]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/main.bicep b/avm/1.1.0/res/network/dns-forwarding-ruleset/main.bicep new file mode 100644 index 000000000..247ae9508 --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/main.bicep @@ -0,0 +1,238 @@ +metadata name = 'Dns Forwarding Rulesets' +metadata description = 'This template deploys an dns forwarding ruleset.' + +@description('Required. Name of the DNS Forwarding Ruleset.') +@minLength(1) +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Required. The reference to the DNS resolver outbound endpoints that are used to route DNS queries matching the forwarding rules in the ruleset to the target DNS servers.') +param dnsForwardingRulesetOutboundEndpointResourceIds array + +@description('Optional. Array of forwarding rules.') +param forwardingRules forwardingRuleType? + +@description('Optional. Array of virtual network links.') +param virtualNetworkLinks virtualNetworkLinkType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-dnsforwardingruleset.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource dnsForwardingRuleset 'Microsoft.Network/dnsForwardingRulesets@2022-07-01' = { + name: name + location: location + tags: tags + properties: { + dnsResolverOutboundEndpoints: [ + for dnsForwardingRulesetOutboundEndpointResourceId in dnsForwardingRulesetOutboundEndpointResourceIds: { + id: dnsForwardingRulesetOutboundEndpointResourceId + } + ] + } +} + +module dnsForwardingRuleset_forwardingRule 'forwarding-rule/main.bicep' = [ + for (forwardingRule, index) in (forwardingRules ?? []): { + name: '${uniqueString(deployment().name, location)}-forwardingRule-${index}' + params: { + dnsForwardingRulesetName: dnsForwardingRuleset.name + name: forwardingRule.?name + forwardingRuleState: forwardingRule.?forwardingRuleState ?? 'Enabled' + domainName: forwardingRule.?domainName + targetDnsServers: forwardingRule.?targetDnsServers + metadata: forwardingRule.?metadata + } + } +] + +module dnsForwardingRuleset_virtualNetworkLinks 'virtual-network-link/main.bicep' = [ + for (virtualNetworkLink, index) in (virtualNetworkLinks ?? []): { + name: '${uniqueString(deployment().name, location)}-virtualNetworkLink-${index}' + params: { + name: virtualNetworkLink.?name ?? '${last(split(virtualNetworkLink.virtualNetworkResourceId, '/'))}-vnetlink-${index}' + dnsForwardingRulesetName: dnsForwardingRuleset.name + virtualNetworkResourceId: !empty(virtualNetworkLinks) ? virtualNetworkLink.virtualNetworkResourceId : null + } + } +] + +resource dnsForwardingRuleset_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: dnsForwardingRuleset +} + +resource dnsForwardingRuleset_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + dnsForwardingRuleset.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: dnsForwardingRuleset + } +] + +@description('The resource group the DNS Forwarding Ruleset was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the DNS Forwarding Ruleset.') +output resourceId string = dnsForwardingRuleset.id + +@description('The name of the DNS Forwarding Ruleset.') +output name string = dnsForwardingRuleset.name + +@description('The location the resource was deployed into.') +output location string = dnsForwardingRuleset.location + +// ================ // +// Definitions // +// ================ // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type forwardingRuleType = { + @description('Required. The name of the forwarding rule.') + name: string + + @description('Optional. The state of the forwarding rule.') + forwardingRuleState: ('Enabled' | 'Disabled')? + + @description('Required. The domain name to forward.') + domainName: string + + @description('Required. The target DNS servers to forward to.') + targetDnsServers: targetDnsServers + + @description('Optional. Metadata attached to the forwarding rule.') + metadata: string? +}[]? + +type virtualNetworkLinkType = { + @description('Optional. The name of the virtual network link.') + name: string? + + @description('Required. The resource ID of the virtual network to link.') + virtualNetworkResourceId: string +}[]? + +type targetDnsServers = { + @description('Required. The IP address of the target DNS server.') + ipAddress: string + + @description('Required. The port of the target DNS server.') + port: int +}[] diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/main.json b/avm/1.1.0/res/network/dns-forwarding-ruleset/main.json new file mode 100644 index 000000000..09f338374 --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/main.json @@ -0,0 +1,633 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "7989603448774483955" + }, + "name": "Dns Forwarding Rulesets", + "description": "This template deploys an dns forwarding ruleset." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "forwardingRuleType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the forwarding rule." + } + }, + "forwardingRuleState": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. The state of the forwarding rule." + } + }, + "domainName": { + "type": "string", + "metadata": { + "description": "Required. The domain name to forward." + } + }, + "targetDnsServers": { + "$ref": "#/definitions/targetDnsServers", + "metadata": { + "description": "Required. The target DNS servers to forward to." + } + }, + "metadata": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Metadata attached to the forwarding rule." + } + } + } + }, + "nullable": true + }, + "virtualNetworkLinkType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the virtual network to link." + } + } + } + }, + "nullable": true + }, + "targetDnsServers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipAddress": { + "type": "string", + "metadata": { + "description": "Required. The IP address of the target DNS server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. The port of the target DNS server." + } + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the DNS Forwarding Ruleset." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "dnsForwardingRulesetOutboundEndpointResourceIds": { + "type": "array", + "metadata": { + "description": "Required. The reference to the DNS resolver outbound endpoints that are used to route DNS queries matching the forwarding rules in the ruleset to the target DNS servers." + } + }, + "forwardingRules": { + "$ref": "#/definitions/forwardingRuleType", + "nullable": true, + "metadata": { + "description": "Optional. Array of forwarding rules." + } + }, + "virtualNetworkLinks": { + "$ref": "#/definitions/virtualNetworkLinkType", + "metadata": { + "description": "Optional. Array of virtual network links." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-dnsforwardingruleset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "dnsForwardingRuleset": { + "type": "Microsoft.Network/dnsForwardingRulesets", + "apiVersion": "2022-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "dnsResolverOutboundEndpoints", + "count": "[length(parameters('dnsForwardingRulesetOutboundEndpointResourceIds'))]", + "input": { + "id": "[parameters('dnsForwardingRulesetOutboundEndpointResourceIds')[copyIndex('dnsResolverOutboundEndpoints')]]" + } + } + ] + } + }, + "dnsForwardingRuleset_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/dnsForwardingRulesets/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "dnsForwardingRuleset" + ] + }, + "dnsForwardingRuleset_roleAssignments": { + "copy": { + "name": "dnsForwardingRuleset_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsForwardingRulesets/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsForwardingRulesets', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "dnsForwardingRuleset" + ] + }, + "dnsForwardingRuleset_forwardingRule": { + "copy": { + "name": "dnsForwardingRuleset_forwardingRule", + "count": "[length(coalesce(parameters('forwardingRules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-forwardingRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dnsForwardingRulesetName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('forwardingRules'), createArray())[copyIndex()], 'name')]" + }, + "forwardingRuleState": { + "value": "[coalesce(tryGet(coalesce(parameters('forwardingRules'), createArray())[copyIndex()], 'forwardingRuleState'), 'Enabled')]" + }, + "domainName": { + "value": "[tryGet(coalesce(parameters('forwardingRules'), createArray())[copyIndex()], 'domainName')]" + }, + "targetDnsServers": { + "value": "[tryGet(coalesce(parameters('forwardingRules'), createArray())[copyIndex()], 'targetDnsServers')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('forwardingRules'), createArray())[copyIndex()], 'metadata')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "18374273039902105155" + }, + "name": "Dns Forwarding Rulesets Forwarding Rules", + "description": "This template deploys Forwarding Rule in a Dns Forwarding Ruleset." + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the Forwarding Rule." + } + }, + "dnsForwardingRulesetName": { + "type": "string", + "metadata": { + "description": "Conditional. Name of the parent DNS Forwarding Ruleset. Required if the template is used in a standalone deployment." + } + }, + "domainName": { + "type": "string", + "metadata": { + "description": "Required. The domain name for the forwarding rule." + } + }, + "forwardingRuleState": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The state of forwarding rule." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Metadata attached to the forwarding rule." + } + }, + "targetDnsServers": { + "type": "array", + "metadata": { + "description": "Required. DNS servers to forward the DNS query to." + } + } + }, + "resources": { + "dnsForwardingRuleset": { + "existing": true, + "type": "Microsoft.Network/dnsForwardingRulesets", + "apiVersion": "2022-07-01", + "name": "[parameters('dnsForwardingRulesetName')]" + }, + "forwardingRule": { + "type": "Microsoft.Network/dnsForwardingRulesets/forwardingRules", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('dnsForwardingRulesetName'), parameters('name'))]", + "properties": { + "domainName": "[parameters('domainName')]", + "forwardingRuleState": "[parameters('forwardingRuleState')]", + "metadata": "[parameters('metadata')]", + "targetDnsServers": "[parameters('targetDnsServers')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Forwarding Rule was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Forwarding Rule." + }, + "value": "[resourceId('Microsoft.Network/dnsForwardingRulesets/forwardingRules', parameters('dnsForwardingRulesetName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Forwarding Rule." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "dnsForwardingRuleset" + ] + }, + "dnsForwardingRuleset_virtualNetworkLinks": { + "copy": { + "name": "dnsForwardingRuleset_virtualNetworkLinks", + "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink-{1}', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/')), copyIndex()))]" + }, + "dnsForwardingRulesetName": { + "value": "[parameters('name')]" + }, + "virtualNetworkResourceId": "[if(not(empty(parameters('virtualNetworkLinks'))), createObject('value', coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId), createObject('value', null()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "16294594686029517690" + }, + "name": "Dns Forwarding Rulesets Virtual Network Links", + "description": "This template deploys Virtual Network Link in a Dns Forwarding Ruleset." + }, + "parameters": { + "dnsForwardingRulesetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS Fowarding Rule Set. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Metadata attached to the forwarding rule." + } + } + }, + "resources": { + "dnsForwardingRuleset": { + "existing": true, + "type": "Microsoft.Network/dnsForwardingRulesets", + "apiVersion": "2022-07-01", + "name": "[parameters('dnsForwardingRulesetName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/dnsForwardingRulesets/virtualNetworkLinks", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('dnsForwardingRulesetName'), coalesce(parameters('name'), format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))))]", + "properties": { + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + }, + "metadata": "[parameters('metadata')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[coalesce(parameters('name'), format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/dnsForwardingRulesets/virtualNetworkLinks', parameters('dnsForwardingRulesetName'), coalesce(parameters('name'), format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dnsForwardingRuleset" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the DNS Forwarding Ruleset was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the DNS Forwarding Ruleset." + }, + "value": "[resourceId('Microsoft.Network/dnsForwardingRulesets', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the DNS Forwarding Ruleset." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('dnsForwardingRuleset', '2022-07-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..946812afa --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,72 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the DNS Resolver to create.') +param dnsResolverName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: map( + range(0, 2), + i => { + name: 'subnet-${i}' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 25, i) + delegations: [ + { + name: 'dnsdel' + properties: { + serviceName: 'Microsoft.Network/dnsResolvers' + } + } + ] + } + } + ) + } +} + +resource dnsResolver 'Microsoft.Network/dnsResolvers@2022-07-01' = { + name: dnsResolverName + location: location + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + } +} + +resource outboundEndpoints 'Microsoft.Network/dnsResolvers/outboundEndpoints@2022-07-01' = { + name: 'pdnsout' + location: location + parent: dnsResolver + properties: { + subnet: { + id: virtualNetwork.properties.subnets[1].id + } + } +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created inbound endpoint Virtual Network Subnet.') +output subnetResourceId_dnsIn string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created outbound endpoint Virtual Network Subnet.') +output subnetResourceId_dnsOut string = virtualNetwork.properties.subnets[1].id + +@description('The resource ID of the created DNS Resolver.') +output dnsResolverOutboundEndpointsResourceId string = outboundEndpoints.id diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..5c983ca0b --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,64 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.dnsForwardingRuleset-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ndfrsmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + dnsResolverName: 'dep-${namePrefix}-ndr-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + dnsForwardingRulesetOutboundEndpointResourceIds: [ + nestedDependencies.outputs.dnsResolverOutboundEndpointsResourceId + ] + location: resourceLocation + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..d98ebb028 --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/max/dependencies.bicep @@ -0,0 +1,83 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the DNS Resolver to create.') +param dnsResolverName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: map( + range(0, 2), + i => { + name: 'subnet-${i}' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 25, i) + delegations: [ + { + name: 'dnsdel' + properties: { + serviceName: 'Microsoft.Network/dnsResolvers' + } + } + ] + } + } + ) + } +} + +resource dnsResolver 'Microsoft.Network/dnsResolvers@2022-07-01' = { + name: dnsResolverName + location: location + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + } +} + +resource outboundEndpoints 'Microsoft.Network/dnsResolvers/outboundEndpoints@2022-07-01' = { + name: 'pdnsout' + location: location + parent: dnsResolver + properties: { + subnet: { + id: virtualNetwork.properties.subnets[1].id + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created inbound endpoint Virtual Network Subnet.') +output subnetResourceId_dnsIn string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created outbound endpoint Virtual Network Subnet.') +output subnetResourceId_dnsOut string = virtualNetwork.properties.subnets[1].id + +@description('The resource ID of the created DNS Resolver.') +output dnsResolverOutboundEndpointsId string = outboundEndpoints.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..f8f66cd66 --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/max/main.test.bicep @@ -0,0 +1,115 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.dnsForwardingRuleset-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ndfrsmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + dnsResolverName: 'dep-${namePrefix}-ndr-${serviceShort}' + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dnsForwardingRulesetOutboundEndpointResourceIds: [ + nestedDependencies.outputs.dnsResolverOutboundEndpointsId + ] + virtualNetworkLinks: [ + { + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + name: 'mytestvnetlink1' + } + ] + forwardingRules: [ + { + name: 'rule1' + forwardingRuleState: 'Enabled' + domainName: 'contoso.' + targetDnsServers: [ + { + ipAddress: '192.168.0.1' + port: 53 + } + ] + } + ] + roleAssignments: [ + { + name: '38837eb6-838b-4c77-8d7d-baa102195d9f' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..d98ebb028 --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,83 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the DNS Resolver to create.') +param dnsResolverName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: map( + range(0, 2), + i => { + name: 'subnet-${i}' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 25, i) + delegations: [ + { + name: 'dnsdel' + properties: { + serviceName: 'Microsoft.Network/dnsResolvers' + } + } + ] + } + } + ) + } +} + +resource dnsResolver 'Microsoft.Network/dnsResolvers@2022-07-01' = { + name: dnsResolverName + location: location + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + } +} + +resource outboundEndpoints 'Microsoft.Network/dnsResolvers/outboundEndpoints@2022-07-01' = { + name: 'pdnsout' + location: location + parent: dnsResolver + properties: { + subnet: { + id: virtualNetwork.properties.subnets[1].id + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created inbound endpoint Virtual Network Subnet.') +output subnetResourceId_dnsIn string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created outbound endpoint Virtual Network Subnet.') +output subnetResourceId_dnsOut string = virtualNetwork.properties.subnets[1].id + +@description('The resource ID of the created DNS Resolver.') +output dnsResolverOutboundEndpointsId string = outboundEndpoints.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..354044495 --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,74 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.dnsForwardingRuleset-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ndfrswaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + dnsResolverName: 'dep-${namePrefix}-ndr-${serviceShort}' + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dnsForwardingRulesetOutboundEndpointResourceIds: [ + nestedDependencies.outputs.dnsResolverOutboundEndpointsId + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/version.json b/avm/1.1.0/res/network/dns-forwarding-ruleset/version.json new file mode 100644 index 000000000..ea4f3b6e6 --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/virtual-network-link/README.md b/avm/1.1.0/res/network/dns-forwarding-ruleset/virtual-network-link/README.md new file mode 100644 index 000000000..5c13c6d24 --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/virtual-network-link/README.md @@ -0,0 +1,72 @@ +# Dns Forwarding Rulesets Virtual Network Links `[Microsoft.Network/dnsForwardingRulesets/virtualNetworkLinks]` + +This template deploys Virtual Network Link in a Dns Forwarding Ruleset. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/dnsForwardingRulesets/virtualNetworkLinks` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/dnsForwardingRulesets/virtualNetworkLinks) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`virtualNetworkResourceId`](#parameter-virtualnetworkresourceid) | string | Link to another virtual network resource ID. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsForwardingRulesetName`](#parameter-dnsforwardingrulesetname) | string | The name of the parent DNS Fowarding Rule Set. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-metadata) | object | Metadata attached to the forwarding rule. | +| [`name`](#parameter-name) | string | The name of the virtual network link. | + +### Parameter: `virtualNetworkResourceId` + +Link to another virtual network resource ID. + +- Required: Yes +- Type: string + +### Parameter: `dnsForwardingRulesetName` + +The name of the parent DNS Fowarding Rule Set. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `metadata` + +Metadata attached to the forwarding rule. + +- Required: No +- Type: object + +### Parameter: `name` + +The name of the virtual network link. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed virtual network link. | +| `resourceGroupName` | string | The resource group of the deployed virtual network link. | +| `resourceId` | string | The resource ID of the deployed virtual network link. | diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/virtual-network-link/main.bicep b/avm/1.1.0/res/network/dns-forwarding-ruleset/virtual-network-link/main.bicep new file mode 100644 index 000000000..e8430b572 --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/virtual-network-link/main.bicep @@ -0,0 +1,38 @@ +metadata name = 'Dns Forwarding Rulesets Virtual Network Links' +metadata description = 'This template deploys Virtual Network Link in a Dns Forwarding Ruleset.' + +@description('Conditional. The name of the parent DNS Fowarding Rule Set. Required if the template is used in a standalone deployment.') +param dnsForwardingRulesetName string + +@description('Optional. The name of the virtual network link.') +param name string? + +@description('Required. Link to another virtual network resource ID.') +param virtualNetworkResourceId string + +@description('Optional. Metadata attached to the forwarding rule.') +param metadata object? + +resource dnsForwardingRuleset 'Microsoft.Network/dnsForwardingRulesets@2022-07-01' existing = { + name: dnsForwardingRulesetName +} + +resource virtualNetworkLink 'Microsoft.Network/dnsForwardingRulesets/virtualNetworkLinks@2022-07-01' = { + name: name ?? '${last(split(virtualNetworkResourceId, '/'))}-vnetlink' + parent: dnsForwardingRuleset + properties: { + virtualNetwork: { + id: virtualNetworkResourceId + } + metadata: metadata + } +} + +@description('The name of the deployed virtual network link.') +output name string = virtualNetworkLink.name + +@description('The resource ID of the deployed virtual network link.') +output resourceId string = virtualNetworkLink.id + +@description('The resource group of the deployed virtual network link.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/network/dns-forwarding-ruleset/virtual-network-link/main.json b/avm/1.1.0/res/network/dns-forwarding-ruleset/virtual-network-link/main.json new file mode 100644 index 000000000..bf9443a02 --- /dev/null +++ b/avm/1.1.0/res/network/dns-forwarding-ruleset/virtual-network-link/main.json @@ -0,0 +1,84 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "16294594686029517690" + }, + "name": "Dns Forwarding Rulesets Virtual Network Links", + "description": "This template deploys Virtual Network Link in a Dns Forwarding Ruleset." + }, + "parameters": { + "dnsForwardingRulesetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS Fowarding Rule Set. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Metadata attached to the forwarding rule." + } + } + }, + "resources": { + "dnsForwardingRuleset": { + "existing": true, + "type": "Microsoft.Network/dnsForwardingRulesets", + "apiVersion": "2022-07-01", + "name": "[parameters('dnsForwardingRulesetName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/dnsForwardingRulesets/virtualNetworkLinks", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('dnsForwardingRulesetName'), coalesce(parameters('name'), format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))))]", + "properties": { + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + }, + "metadata": "[parameters('metadata')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[coalesce(parameters('name'), format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/'))))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/dnsForwardingRulesets/virtualNetworkLinks', parameters('dnsForwardingRulesetName'), coalesce(parameters('name'), format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-resolver/README.md b/avm/1.1.0/res/network/dns-resolver/README.md new file mode 100644 index 000000000..83f5b9b16 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/README.md @@ -0,0 +1,777 @@ +# DNS Resolver `[Microsoft.Network/dnsResolvers]` + +This module deploys a DNS Resolver. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/dnsResolvers` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/dnsResolvers) | +| `Microsoft.Network/dnsResolvers/inboundEndpoints` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/dnsResolvers/inboundEndpoints) | +| `Microsoft.Network/dnsResolvers/outboundEndpoints` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/dnsResolvers/outboundEndpoints) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/dns-resolver:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module dnsResolver 'br/public:avm/res/network/dns-resolver:' = { + name: 'dnsResolverDeployment' + params: { + // Required parameters + name: 'ndrmin001' + virtualNetworkResourceId: '' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ndrmin001" + }, + "virtualNetworkResourceId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-resolver:' + +// Required parameters +param name = 'ndrmin001' +param virtualNetworkResourceId = '' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module dnsResolver 'br/public:avm/res/network/dns-resolver:' = { + name: 'dnsResolverDeployment' + params: { + // Required parameters + name: 'ndrmax001' + virtualNetworkResourceId: '' + // Non-required parameters + inboundEndpoints: [ + { + name: 'ndrmax-az-pdnsin-x-001' + subnetResourceId: '' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + outboundEndpoints: [ + { + name: 'ndrmax-az-pdnsout-x-001' + subnetResourceId: '' + } + ] + roleAssignments: [ + { + name: '83c82ade-1ada-4374-82d0-325f39a44af6' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ndrmax001" + }, + "virtualNetworkResourceId": { + "value": "" + }, + // Non-required parameters + "inboundEndpoints": { + "value": [ + { + "name": "ndrmax-az-pdnsin-x-001", + "subnetResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "outboundEndpoints": { + "value": [ + { + "name": "ndrmax-az-pdnsout-x-001", + "subnetResourceId": "" + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "83c82ade-1ada-4374-82d0-325f39a44af6", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-resolver:' + +// Required parameters +param name = 'ndrmax001' +param virtualNetworkResourceId = '' +// Non-required parameters +param inboundEndpoints = [ + { + name: 'ndrmax-az-pdnsin-x-001' + subnetResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param outboundEndpoints = [ + { + name: 'ndrmax-az-pdnsout-x-001' + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '83c82ade-1ada-4374-82d0-325f39a44af6' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module dnsResolver 'br/public:avm/res/network/dns-resolver:' = { + name: 'dnsResolverDeployment' + params: { + // Required parameters + name: 'ndrwaf001' + virtualNetworkResourceId: '' + // Non-required parameters + inboundEndpoints: [ + { + name: 'ndrwaf-az-pdnsin-x-001' + subnetResourceId: '' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + outboundEndpoints: [ + { + name: 'ndrwaf-az-pdnsout-x-001' + subnetResourceId: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ndrwaf001" + }, + "virtualNetworkResourceId": { + "value": "" + }, + // Non-required parameters + "inboundEndpoints": { + "value": [ + { + "name": "ndrwaf-az-pdnsin-x-001", + "subnetResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "outboundEndpoints": { + "value": [ + { + "name": "ndrwaf-az-pdnsout-x-001", + "subnetResourceId": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-resolver:' + +// Required parameters +param name = 'ndrwaf001' +param virtualNetworkResourceId = '' +// Non-required parameters +param inboundEndpoints = [ + { + name: 'ndrwaf-az-pdnsin-x-001' + subnetResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param outboundEndpoints = [ + { + name: 'ndrwaf-az-pdnsout-x-001' + subnetResourceId: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the DNS Private Resolver. | +| [`virtualNetworkResourceId`](#parameter-virtualnetworkresourceid) | string | ResourceId of the virtual network to attach the DNS Private Resolver to. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`inboundEndpoints`](#parameter-inboundendpoints) | array | Inbound Endpoints for DNS Private Resolver. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`outboundEndpoints`](#parameter-outboundendpoints) | array | Outbound Endpoints for DNS Private Resolver. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `name` + +Name of the DNS Private Resolver. + +- Required: Yes +- Type: string + +### Parameter: `virtualNetworkResourceId` + +ResourceId of the virtual network to attach the DNS Private Resolver to. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `inboundEndpoints` + +Inbound Endpoints for DNS Private Resolver. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-inboundendpointsname) | string | Name of the inbound endpoint. | +| [`subnetResourceId`](#parameter-inboundendpointssubnetresourceid) | string | The reference to the subnet bound to the IP configuration. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`location`](#parameter-inboundendpointslocation) | string | Location for all resources. | +| [`privateIpAddress`](#parameter-inboundendpointsprivateipaddress) | string | Private IP address of the IP configuration. | +| [`privateIpAllocationMethod`](#parameter-inboundendpointsprivateipallocationmethod) | string | Private IP address allocation method. | +| [`tags`](#parameter-inboundendpointstags) | object | Tags for the resource. | + +### Parameter: `inboundEndpoints.name` + +Name of the inbound endpoint. + +- Required: Yes +- Type: string + +### Parameter: `inboundEndpoints.subnetResourceId` + +The reference to the subnet bound to the IP configuration. + +- Required: Yes +- Type: string + +### Parameter: `inboundEndpoints.location` + +Location for all resources. + +- Required: No +- Type: string + +### Parameter: `inboundEndpoints.privateIpAddress` + +Private IP address of the IP configuration. + +- Required: No +- Type: string + +### Parameter: `inboundEndpoints.privateIpAllocationMethod` + +Private IP address allocation method. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Dynamic' + 'Static' + ] + ``` + +### Parameter: `inboundEndpoints.tags` + +Tags for the resource. + +- Required: No +- Type: object + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `outboundEndpoints` + +Outbound Endpoints for DNS Private Resolver. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-outboundendpointsname) | string | Name of the outbound endpoint. | +| [`subnetResourceId`](#parameter-outboundendpointssubnetresourceid) | string | ResourceId of the subnet to attach the outbound endpoint to. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`location`](#parameter-outboundendpointslocation) | string | Location for all resources. | +| [`tags`](#parameter-outboundendpointstags) | object | Tags of the resource. | + +### Parameter: `outboundEndpoints.name` + +Name of the outbound endpoint. + +- Required: Yes +- Type: string + +### Parameter: `outboundEndpoints.subnetResourceId` + +ResourceId of the subnet to attach the outbound endpoint to. + +- Required: Yes +- Type: string + +### Parameter: `outboundEndpoints.location` + +Location for all resources. + +- Required: No +- Type: string + +### Parameter: `outboundEndpoints.tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the DNS Private Resolver. | +| `resourceGroupName` | string | The resource group the DNS Private Resolver was deployed into. | +| `resourceId` | string | The resource ID of the DNS Private Resolver. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/dns-resolver/inbound-endpoint/README.md b/avm/1.1.0/res/network/dns-resolver/inbound-endpoint/README.md new file mode 100644 index 000000000..139bc6eeb --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/inbound-endpoint/README.md @@ -0,0 +1,93 @@ +# DNS Resolver Inbound Endpoint `[Microsoft.Network/dnsResolvers/inboundEndpoints]` + +This module deploys a DNS Resolver Inbound Endpoint. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/dnsResolvers/inboundEndpoints` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/dnsResolvers/inboundEndpoints) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsResolverName`](#parameter-dnsresolvername) | string | Name of the DNS Private Resolver. | +| [`name`](#parameter-name) | string | The name of the inbound endpoint. | +| [`subnetResourceId`](#parameter-subnetresourceid) | string | The subnet ID of the inbound endpoint. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`privateIpAddress`](#parameter-privateipaddress) | string | The private IP address of the inbound endpoint. | +| [`privateIpAllocationMethod`](#parameter-privateipallocationmethod) | string | The private IP allocation method of the inbound endpoint. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `dnsResolverName` + +Name of the DNS Private Resolver. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the inbound endpoint. + +- Required: Yes +- Type: string + +### Parameter: `subnetResourceId` + +The subnet ID of the inbound endpoint. + +- Required: Yes +- Type: string + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `privateIpAddress` + +The private IP address of the inbound endpoint. + +- Required: No +- Type: string + +### Parameter: `privateIpAllocationMethod` + +The private IP allocation method of the inbound endpoint. + +- Required: No +- Type: string +- Default: `'Dynamic'` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the resource. | +| `resourceGroupName` | string | The resource group of the resource. | +| `resourceId` | string | The resource ID of the resource. | diff --git a/avm/1.1.0/res/network/dns-resolver/inbound-endpoint/main.bicep b/avm/1.1.0/res/network/dns-resolver/inbound-endpoint/main.bicep new file mode 100644 index 000000000..c1b166182 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/inbound-endpoint/main.bicep @@ -0,0 +1,55 @@ +metadata name = 'DNS Resolver Inbound Endpoint' +metadata description = 'This module deploys a DNS Resolver Inbound Endpoint.' + +@description('Required. Name of the DNS Private Resolver.') +@minLength(1) +param dnsResolverName string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Required. The subnet ID of the inbound endpoint.') +param subnetResourceId string + +@description('Optional. The private IP address of the inbound endpoint.') +param privateIpAddress string? + +@description('Optional. The private IP allocation method of the inbound endpoint.') +param privateIpAllocationMethod string = 'Dynamic' + +@description('Required. The name of the inbound endpoint.') +param name string + +resource dnsResolver 'Microsoft.Network/dnsResolvers@2022-07-01' existing = { + name: dnsResolverName +} + +resource inboundEndpoint 'Microsoft.Network/dnsResolvers/inboundEndpoints@2022-07-01' = { + parent: dnsResolver + name: name + location: location + tags: tags + properties: { + ipConfigurations: [ + { + subnet: { + id: subnetResourceId + } + privateIpAddress: privateIpAddress + privateIpAllocationMethod: privateIpAllocationMethod + } + ] + } +} + +@description('The name of the resource.') +output name string = inboundEndpoint.name + +@description('The resource ID of the resource.') +output resourceId string = inboundEndpoint.id + +@description('The resource group of the resource.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/network/dns-resolver/inbound-endpoint/main.json b/avm/1.1.0/res/network/dns-resolver/inbound-endpoint/main.json new file mode 100644 index 000000000..26b8f1836 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/inbound-endpoint/main.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3824129655159697612" + }, + "name": "DNS Resolver Inbound Endpoint", + "description": "This module deploys a DNS Resolver Inbound Endpoint." + }, + "parameters": { + "dnsResolverName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the DNS Private Resolver." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The subnet ID of the inbound endpoint." + } + }, + "privateIpAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address of the inbound endpoint." + } + }, + "privateIpAllocationMethod": { + "type": "string", + "defaultValue": "Dynamic", + "metadata": { + "description": "Optional. The private IP allocation method of the inbound endpoint." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the inbound endpoint." + } + } + }, + "resources": { + "dnsResolver": { + "existing": true, + "type": "Microsoft.Network/dnsResolvers", + "apiVersion": "2022-07-01", + "name": "[parameters('dnsResolverName')]" + }, + "inboundEndpoint": { + "type": "Microsoft.Network/dnsResolvers/inboundEndpoints", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('dnsResolverName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "ipConfigurations": [ + { + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "privateIpAddress": "[parameters('privateIpAddress')]", + "privateIpAllocationMethod": "[parameters('privateIpAllocationMethod')]" + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the resource." + }, + "value": "[resourceId('Microsoft.Network/dnsResolvers/inboundEndpoints', parameters('dnsResolverName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the resource." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-resolver/main.bicep b/avm/1.1.0/res/network/dns-resolver/main.bicep new file mode 100644 index 000000000..9517c87e5 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/main.bicep @@ -0,0 +1,244 @@ +metadata name = 'DNS Resolver' +metadata description = 'This module deploys a DNS Resolver.' + +@description('Required. Name of the DNS Private Resolver.') +@minLength(1) +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Required. ResourceId of the virtual network to attach the DNS Private Resolver to.') +param virtualNetworkResourceId string + +@description('Optional. Outbound Endpoints for DNS Private Resolver.') +param outboundEndpoints outboundEndpointType + +@description('Optional. Inbound Endpoints for DNS Private Resolver.') +param inboundEndpoints inboundEndpointType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-dnsresolver.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource dnsResolver 'Microsoft.Network/dnsResolvers@2022-07-01' = { + name: name + location: location + tags: tags + properties: { + virtualNetwork: { + id: virtualNetworkResourceId + } + } +} + +resource dnsResolver_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: dnsResolver +} + +resource dnsResolver_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(dnsResolver.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: dnsResolver + } +] + +module dnsResolver_inboundEndpoints 'inbound-endpoint/main.bicep' = [ + for (inboundEndpoint, index) in (inboundEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-dnsResolver-inbound-${index}' + params: { + name: inboundEndpoint.name + tags: inboundEndpoint.?tags ?? tags + location: inboundEndpoint.?location ?? location + dnsResolverName: dnsResolver.name + subnetResourceId: inboundEndpoint.subnetResourceId + privateIpAddress: inboundEndpoint.?privateIpAddress + privateIpAllocationMethod: inboundEndpoint.?privateIpAllocationMethod + } + } +] + +module dnsResolver_outboundEndpoints 'outbound-endpoint/main.bicep' = [ + for (outboundEndpoint, index) in (outboundEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-dnsResolver-outbound-${index}' + params: { + name: outboundEndpoint.name + tags: outboundEndpoint.?tags ?? tags + location: outboundEndpoint.?location ?? location + dnsResolverName: dnsResolver.name + subnetResourceId: outboundEndpoint.subnetResourceId + } + } +] + +@description('The resource group the DNS Private Resolver was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the DNS Private Resolver.') +output resourceId string = dnsResolver.id + +@description('The name of the DNS Private Resolver.') +output name string = dnsResolver.name + +@description('The location the resource was deployed into.') +output location string = dnsResolver.location + +// ================ // +// Definitions // +// ================ // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type inboundEndpointType = { + @description('Required. Name of the inbound endpoint.') + name: string + + @description('Required. The reference to the subnet bound to the IP configuration.') + subnetResourceId: string + + @description('Optional. Tags for the resource.') + tags: object? + + @description('Optional. Location for all resources.') + location: string? + + @description('Optional. Private IP address of the IP configuration.') + privateIpAddress: string? + + @description('Optional. Private IP address allocation method.') + privateIpAllocationMethod: ('Dynamic' | 'Static')? +}[]? + +type outboundEndpointType = { + @description('Required. Name of the outbound endpoint.') + name: string + + @description('Required. ResourceId of the subnet to attach the outbound endpoint to.') + subnetResourceId: string + + @description('Optional. Tags of the resource.') + tags: object? + + @description('Optional. Location for all resources.') + location: string? +}[]? diff --git a/avm/1.1.0/res/network/dns-resolver/main.json b/avm/1.1.0/res/network/dns-resolver/main.json new file mode 100644 index 000000000..b0d3807d2 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/main.json @@ -0,0 +1,663 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "353797495875556869" + }, + "name": "DNS Resolver", + "description": "This module deploys a DNS Resolver." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "inboundEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the inbound endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The reference to the subnet bound to the IP configuration." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for the resource." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "privateIpAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Private IP address of the IP configuration." + } + }, + "privateIpAllocationMethod": { + "type": "string", + "allowedValues": [ + "Dynamic", + "Static" + ], + "nullable": true, + "metadata": { + "description": "Optional. Private IP address allocation method." + } + } + } + }, + "nullable": true + }, + "outboundEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the outbound endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. ResourceId of the subnet to attach the outbound endpoint to." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location for all resources." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the DNS Private Resolver." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. ResourceId of the virtual network to attach the DNS Private Resolver to." + } + }, + "outboundEndpoints": { + "$ref": "#/definitions/outboundEndpointType", + "metadata": { + "description": "Optional. Outbound Endpoints for DNS Private Resolver." + } + }, + "inboundEndpoints": { + "$ref": "#/definitions/inboundEndpointType", + "metadata": { + "description": "Optional. Inbound Endpoints for DNS Private Resolver." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-dnsresolver.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "dnsResolver": { + "type": "Microsoft.Network/dnsResolvers", + "apiVersion": "2022-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + } + } + }, + "dnsResolver_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/dnsResolvers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "dnsResolver" + ] + }, + "dnsResolver_roleAssignments": { + "copy": { + "name": "dnsResolver_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsResolvers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsResolvers', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "dnsResolver" + ] + }, + "dnsResolver_inboundEndpoints": { + "copy": { + "name": "dnsResolver_inboundEndpoints", + "count": "[length(coalesce(parameters('inboundEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-dnsResolver-inbound-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('inboundEndpoints'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('inboundEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('inboundEndpoints'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "dnsResolverName": { + "value": "[parameters('name')]" + }, + "subnetResourceId": { + "value": "[coalesce(parameters('inboundEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "privateIpAddress": { + "value": "[tryGet(coalesce(parameters('inboundEndpoints'), createArray())[copyIndex()], 'privateIpAddress')]" + }, + "privateIpAllocationMethod": { + "value": "[tryGet(coalesce(parameters('inboundEndpoints'), createArray())[copyIndex()], 'privateIpAllocationMethod')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3824129655159697612" + }, + "name": "DNS Resolver Inbound Endpoint", + "description": "This module deploys a DNS Resolver Inbound Endpoint." + }, + "parameters": { + "dnsResolverName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the DNS Private Resolver." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The subnet ID of the inbound endpoint." + } + }, + "privateIpAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The private IP address of the inbound endpoint." + } + }, + "privateIpAllocationMethod": { + "type": "string", + "defaultValue": "Dynamic", + "metadata": { + "description": "Optional. The private IP allocation method of the inbound endpoint." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the inbound endpoint." + } + } + }, + "resources": { + "dnsResolver": { + "existing": true, + "type": "Microsoft.Network/dnsResolvers", + "apiVersion": "2022-07-01", + "name": "[parameters('dnsResolverName')]" + }, + "inboundEndpoint": { + "type": "Microsoft.Network/dnsResolvers/inboundEndpoints", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('dnsResolverName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "ipConfigurations": [ + { + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "privateIpAddress": "[parameters('privateIpAddress')]", + "privateIpAllocationMethod": "[parameters('privateIpAllocationMethod')]" + } + ] + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the resource." + }, + "value": "[resourceId('Microsoft.Network/dnsResolvers/inboundEndpoints', parameters('dnsResolverName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the resource." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dnsResolver" + ] + }, + "dnsResolver_outboundEndpoints": { + "copy": { + "name": "dnsResolver_outboundEndpoints", + "count": "[length(coalesce(parameters('outboundEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-dnsResolver-outbound-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('outboundEndpoints'), createArray())[copyIndex()].name]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('outboundEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('outboundEndpoints'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "dnsResolverName": { + "value": "[parameters('name')]" + }, + "subnetResourceId": { + "value": "[coalesce(parameters('outboundEndpoints'), createArray())[copyIndex()].subnetResourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "17231952253556640030" + }, + "name": "DNS Resolver Outbound Endpoint", + "description": "This module deploys a DNS Resolver Outbound Endpoint." + }, + "parameters": { + "dnsResolverName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the DNS Private Resolver." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The subnet ID of the inbound endpoint." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the inbound endpoint." + } + } + }, + "resources": { + "dnsResolver": { + "existing": true, + "type": "Microsoft.Network/dnsResolvers", + "apiVersion": "2022-07-01", + "name": "[parameters('dnsResolverName')]" + }, + "outboundEndpoint": { + "type": "Microsoft.Network/dnsResolvers/outboundEndpoints", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('dnsResolverName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the resource." + }, + "value": "[resourceId('Microsoft.Network/dnsResolvers/outboundEndpoints', parameters('dnsResolverName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the resource." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dnsResolver" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the DNS Private Resolver was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the DNS Private Resolver." + }, + "value": "[resourceId('Microsoft.Network/dnsResolvers', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the DNS Private Resolver." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('dnsResolver', '2022-07-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-resolver/outbound-endpoint/README.md b/avm/1.1.0/res/network/dns-resolver/outbound-endpoint/README.md new file mode 100644 index 000000000..1f646fbfa --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/outbound-endpoint/README.md @@ -0,0 +1,76 @@ +# DNS Resolver Outbound Endpoint `[Microsoft.Network/dnsResolvers/outboundEndpoints]` + +This module deploys a DNS Resolver Outbound Endpoint. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/dnsResolvers/outboundEndpoints` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/dnsResolvers/outboundEndpoints) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsResolverName`](#parameter-dnsresolvername) | string | Name of the DNS Private Resolver. | +| [`name`](#parameter-name) | string | The name of the inbound endpoint. | +| [`subnetResourceId`](#parameter-subnetresourceid) | string | The subnet ID of the inbound endpoint. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `dnsResolverName` + +Name of the DNS Private Resolver. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the inbound endpoint. + +- Required: Yes +- Type: string + +### Parameter: `subnetResourceId` + +The subnet ID of the inbound endpoint. + +- Required: Yes +- Type: string + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the resource. | +| `resourceGroupName` | string | The resource group of the resource. | +| `resourceId` | string | The resource ID of the resource. | diff --git a/avm/1.1.0/res/network/dns-resolver/outbound-endpoint/main.bicep b/avm/1.1.0/res/network/dns-resolver/outbound-endpoint/main.bicep new file mode 100644 index 000000000..e386cd8d9 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/outbound-endpoint/main.bicep @@ -0,0 +1,43 @@ +metadata name = 'DNS Resolver Outbound Endpoint' +metadata description = 'This module deploys a DNS Resolver Outbound Endpoint.' + +@description('Required. Name of the DNS Private Resolver.') +@minLength(1) +param dnsResolverName string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Required. The subnet ID of the inbound endpoint.') +param subnetResourceId string + +@description('Required. The name of the inbound endpoint.') +param name string + +resource dnsResolver 'Microsoft.Network/dnsResolvers@2022-07-01' existing = { + name: dnsResolverName +} + +resource outboundEndpoint 'Microsoft.Network/dnsResolvers/outboundEndpoints@2022-07-01' = { + name: name + parent: dnsResolver + location: location + tags: tags + properties: { + subnet: { + id: subnetResourceId + } + } +} + +@description('The name of the resource.') +output name string = outboundEndpoint.name + +@description('The resource ID of the resource.') +output resourceId string = outboundEndpoint.id + +@description('The resource group of the resource.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/network/dns-resolver/outbound-endpoint/main.json b/avm/1.1.0/res/network/dns-resolver/outbound-endpoint/main.json new file mode 100644 index 000000000..6755ad749 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/outbound-endpoint/main.json @@ -0,0 +1,92 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "17231952253556640030" + }, + "name": "DNS Resolver Outbound Endpoint", + "description": "This module deploys a DNS Resolver Outbound Endpoint." + }, + "parameters": { + "dnsResolverName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the DNS Private Resolver." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The subnet ID of the inbound endpoint." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the inbound endpoint." + } + } + }, + "resources": { + "dnsResolver": { + "existing": true, + "type": "Microsoft.Network/dnsResolvers", + "apiVersion": "2022-07-01", + "name": "[parameters('dnsResolverName')]" + }, + "outboundEndpoint": { + "type": "Microsoft.Network/dnsResolvers/outboundEndpoints", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('dnsResolverName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the resource." + }, + "value": "[resourceId('Microsoft.Network/dnsResolvers/outboundEndpoints', parameters('dnsResolverName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the resource." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-resolver/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/dns-resolver/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..555c9c977 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,56 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: map( + range(0, 2), + i => { + name: 'subnet-${i}' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 25, i) + delegations: [ + { + name: 'dnsdel' + properties: { + serviceName: 'Microsoft.Network/dnsResolvers' + } + } + ] + } + } + ) + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created inbound endpoint Virtual Network Subnet.') +output subnetResourceId_dnsIn string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created outbound endpoint Virtual Network Subnet.') +output subnetResourceId_dnsOut string = virtualNetwork.properties.subnets[1].id diff --git a/avm/1.1.0/res/network/dns-resolver/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/dns-resolver/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..3ce2bbf07 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,59 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.dnsResolvers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ndrmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/network/dns-resolver/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/dns-resolver/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..555c9c977 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/tests/e2e/max/dependencies.bicep @@ -0,0 +1,56 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: map( + range(0, 2), + i => { + name: 'subnet-${i}' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 25, i) + delegations: [ + { + name: 'dnsdel' + properties: { + serviceName: 'Microsoft.Network/dnsResolvers' + } + } + ] + } + } + ) + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created inbound endpoint Virtual Network Subnet.') +output subnetResourceId_dnsIn string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created outbound endpoint Virtual Network Subnet.') +output subnetResourceId_dnsOut string = virtualNetwork.properties.subnets[1].id diff --git a/avm/1.1.0/res/network/dns-resolver/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/dns-resolver/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..5f40c2af3 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/tests/e2e/max/main.test.bicep @@ -0,0 +1,102 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.dnsResolvers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ndrmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '83c82ade-1ada-4374-82d0-325f39a44af6' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + inboundEndpoints: [ + { + name: '${namePrefix}${serviceShort}-az-pdnsin-x-001' + subnetResourceId: nestedDependencies.outputs.subnetResourceId_dnsIn + } + ] + outboundEndpoints: [ + { + name: '${namePrefix}${serviceShort}-az-pdnsout-x-001' + subnetResourceId: nestedDependencies.outputs.subnetResourceId_dnsOut + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/dns-resolver/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/dns-resolver/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..555c9c977 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,56 @@ +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: map( + range(0, 2), + i => { + name: 'subnet-${i}' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 25, i) + delegations: [ + { + name: 'dnsdel' + properties: { + serviceName: 'Microsoft.Network/dnsResolvers' + } + } + ] + } + } + ) + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created inbound endpoint Virtual Network Subnet.') +output subnetResourceId_dnsIn string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created outbound endpoint Virtual Network Subnet.') +output subnetResourceId_dnsOut string = virtualNetwork.properties.subnets[1].id diff --git a/avm/1.1.0/res/network/dns-resolver/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/dns-resolver/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..04a405707 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,80 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.dnsResolvers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ndrwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + name: 'myCustomLockName' + kind: 'CanNotDelete' + } + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + inboundEndpoints: [ + { + name: '${namePrefix}${serviceShort}-az-pdnsin-x-001' + subnetResourceId: nestedDependencies.outputs.subnetResourceId_dnsIn + } + ] + outboundEndpoints: [ + { + name: '${namePrefix}${serviceShort}-az-pdnsout-x-001' + subnetResourceId: nestedDependencies.outputs.subnetResourceId_dnsOut + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/dns-resolver/tests/unit/custom.tests.ps1 b/avm/1.1.0/res/network/dns-resolver/tests/unit/custom.tests.ps1 new file mode 100644 index 000000000..36b53af9c --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/tests/unit/custom.tests.ps1 @@ -0,0 +1,7 @@ +########################### +## Additional unit tests ## +########################### +## +## You can add any custom static validation tests you want here, or add them spread accross multiple test files in the unit folder. +## +########################### diff --git a/avm/1.1.0/res/network/dns-resolver/version.json b/avm/1.1.0/res/network/dns-resolver/version.json new file mode 100644 index 000000000..ea4f3b6e6 --- /dev/null +++ b/avm/1.1.0/res/network/dns-resolver/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-zone/README.md b/avm/1.1.0/res/network/dns-zone/README.md new file mode 100644 index 000000000..b3df572f8 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/README.md @@ -0,0 +1,3268 @@ +# Public DNS Zones `[Microsoft.Network/dnsZones]` + +This module deploys a Public DNS zone. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/dnsZones` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones) | +| `Microsoft.Network/dnsZones/A` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/A) | +| `Microsoft.Network/dnsZones/AAAA` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/AAAA) | +| `Microsoft.Network/dnsZones/CAA` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/CAA) | +| `Microsoft.Network/dnsZones/CNAME` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/CNAME) | +| `Microsoft.Network/dnsZones/MX` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/MX) | +| `Microsoft.Network/dnsZones/NS` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/NS) | +| `Microsoft.Network/dnsZones/PTR` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/PTR) | +| `Microsoft.Network/dnsZones/SOA` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/SOA) | +| `Microsoft.Network/dnsZones/SRV` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/SRV) | +| `Microsoft.Network/dnsZones/TXT` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/TXT) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/dns-zone:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module dnsZone 'br/public:avm/res/network/dns-zone:' = { + name: 'dnsZoneDeployment' + params: { + // Required parameters + name: 'ndzmin001.com' + // Non-required parameters + location: 'global' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ndzmin001.com" + }, + // Non-required parameters + "location": { + "value": "global" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-zone:' + +// Required parameters +param name = 'ndzmin001.com' +// Non-required parameters +param location = 'global' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module dnsZone 'br/public:avm/res/network/dns-zone:' = { + name: 'dnsZoneDeployment' + params: { + // Required parameters + name: 'ndzmax001.com' + // Non-required parameters + a: [ + { + aRecords: [ + { + ipv4Address: '10.240.4.4' + } + ] + name: 'A_10.240.4.4' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } + ] + aaaa: [ + { + aaaaRecords: [ + { + ipv6Address: '2001:0db8:85a3:0000:0000:8a2e:0370:7334' + } + ] + name: 'AAAA_2001_0db8_85a3_0000_0000_8a2e_0370_7334' + ttl: 3600 + } + ] + caa: [ + { + caaRecords: [ + { + flags: 0 + tag: 'issue' + value: 'ca.contoso.com' + } + ] + name: 'CAA_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } + ] + cname: [ + { + cnameRecord: { + cname: 'test' + } + name: 'CNAME_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } + { + name: 'CNAME_aliasRecordSet' + targetResourceId: '' + } + ] + location: 'global' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + mx: [ + { + mxRecords: [ + { + exchange: 'contoso.com' + preference: 100 + } + ] + name: 'MX_contoso' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } + ] + ns: [ + { + name: 'NS_test' + nsRecords: [ + { + nsdname: 'ns.contoso.com' + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } + ] + ptr: [ + { + name: 'PTR_contoso' + ptrRecords: [ + { + ptrdname: 'contoso.com' + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } + ] + roleAssignments: [ + { + name: 'a8697438-70e8-4f40-baa4-6e90a57fe1dc' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + soa: [ + { + name: '@' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + soaRecord: { + email: 'azuredns-hostmaster.microsoft.com' + expireTime: 2419200 + host: 'ns1-04.azure-dns.com.' + minimumTtl: 300 + refreshTime: 3600 + retryTime: 300 + serialNumber: 1 + } + ttl: 3600 + } + ] + srv: [ + { + name: 'SRV_contoso' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + srvRecords: [ + { + port: 9332 + priority: 0 + target: 'test.contoso.com' + weight: 0 + } + ] + ttl: 3600 + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + txt: [ + { + name: 'TXT_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + txtRecords: [ + { + value: [ + 'test' + ] + } + ] + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ndzmax001.com" + }, + // Non-required parameters + "a": { + "value": [ + { + "aRecords": [ + { + "ipv4Address": "10.240.4.4" + } + ], + "name": "A_10.240.4.4", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "ttl": 3600 + } + ] + }, + "aaaa": { + "value": [ + { + "aaaaRecords": [ + { + "ipv6Address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + ], + "name": "AAAA_2001_0db8_85a3_0000_0000_8a2e_0370_7334", + "ttl": 3600 + } + ] + }, + "caa": { + "value": [ + { + "caaRecords": [ + { + "flags": 0, + "tag": "issue", + "value": "ca.contoso.com" + } + ], + "name": "CAA_test", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "ttl": 3600 + } + ] + }, + "cname": { + "value": [ + { + "cnameRecord": { + "cname": "test" + }, + "name": "CNAME_test", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "ttl": 3600 + }, + { + "name": "CNAME_aliasRecordSet", + "targetResourceId": "" + } + ] + }, + "location": { + "value": "global" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "mx": { + "value": [ + { + "mxRecords": [ + { + "exchange": "contoso.com", + "preference": 100 + } + ], + "name": "MX_contoso", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "ttl": 3600 + } + ] + }, + "ns": { + "value": [ + { + "name": "NS_test", + "nsRecords": [ + { + "nsdname": "ns.contoso.com" + } + ], + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "ttl": 3600 + } + ] + }, + "ptr": { + "value": [ + { + "name": "PTR_contoso", + "ptrRecords": [ + { + "ptrdname": "contoso.com" + } + ], + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "ttl": 3600 + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "a8697438-70e8-4f40-baa4-6e90a57fe1dc", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "soa": { + "value": [ + { + "name": "@", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "soaRecord": { + "email": "azuredns-hostmaster.microsoft.com", + "expireTime": 2419200, + "host": "ns1-04.azure-dns.com.", + "minimumTtl": 300, + "refreshTime": 3600, + "retryTime": 300, + "serialNumber": 1 + }, + "ttl": 3600 + } + ] + }, + "srv": { + "value": [ + { + "name": "SRV_contoso", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "srvRecords": [ + { + "port": 9332, + "priority": 0, + "target": "test.contoso.com", + "weight": 0 + } + ], + "ttl": 3600 + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "txt": { + "value": [ + { + "name": "TXT_test", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "ttl": 3600, + "txtRecords": [ + { + "value": [ + "test" + ] + } + ] + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-zone:' + +// Required parameters +param name = 'ndzmax001.com' +// Non-required parameters +param a = [ + { + aRecords: [ + { + ipv4Address: '10.240.4.4' + } + ] + name: 'A_10.240.4.4' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param aaaa = [ + { + aaaaRecords: [ + { + ipv6Address: '2001:0db8:85a3:0000:0000:8a2e:0370:7334' + } + ] + name: 'AAAA_2001_0db8_85a3_0000_0000_8a2e_0370_7334' + ttl: 3600 + } +] +param caa = [ + { + caaRecords: [ + { + flags: 0 + tag: 'issue' + value: 'ca.contoso.com' + } + ] + name: 'CAA_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param cname = [ + { + cnameRecord: { + cname: 'test' + } + name: 'CNAME_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } + { + name: 'CNAME_aliasRecordSet' + targetResourceId: '' + } +] +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param mx = [ + { + mxRecords: [ + { + exchange: 'contoso.com' + preference: 100 + } + ] + name: 'MX_contoso' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param ns = [ + { + name: 'NS_test' + nsRecords: [ + { + nsdname: 'ns.contoso.com' + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param ptr = [ + { + name: 'PTR_contoso' + ptrRecords: [ + { + ptrdname: 'contoso.com' + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param roleAssignments = [ + { + name: 'a8697438-70e8-4f40-baa4-6e90a57fe1dc' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param soa = [ + { + name: '@' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + soaRecord: { + email: 'azuredns-hostmaster.microsoft.com' + expireTime: 2419200 + host: 'ns1-04.azure-dns.com.' + minimumTtl: 300 + refreshTime: 3600 + retryTime: 300 + serialNumber: 1 + } + ttl: 3600 + } +] +param srv = [ + { + name: 'SRV_contoso' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + srvRecords: [ + { + port: 9332 + priority: 0 + target: 'test.contoso.com' + weight: 0 + } + ] + ttl: 3600 + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param txt = [ + { + name: 'TXT_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + txtRecords: [ + { + value: [ + 'test' + ] + } + ] + } +] +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module dnsZone 'br/public:avm/res/network/dns-zone:' = { + name: 'dnsZoneDeployment' + params: { + // Required parameters + name: 'ndzwaf001.com' + // Non-required parameters + location: 'global' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ndzwaf001.com" + }, + // Non-required parameters + "location": { + "value": "global" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-zone:' + +// Required parameters +param name = 'ndzwaf001.com' +// Non-required parameters +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | DNS zone name. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`a`](#parameter-a) | array | Array of A records. | +| [`aaaa`](#parameter-aaaa) | array | Array of AAAA records. | +| [`caa`](#parameter-caa) | array | Array of CAA records. | +| [`cname`](#parameter-cname) | array | Array of CNAME records. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | The location of the dnsZone. Should be global. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`mx`](#parameter-mx) | array | Array of MX records. | +| [`ns`](#parameter-ns) | array | Array of NS records. | +| [`ptr`](#parameter-ptr) | array | Array of PTR records. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`soa`](#parameter-soa) | array | Array of SOA records. | +| [`srv`](#parameter-srv) | array | Array of SRV records. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`txt`](#parameter-txt) | array | Array of TXT records. | + +### Parameter: `name` + +DNS zone name. + +- Required: Yes +- Type: string + +### Parameter: `a` + +Array of A records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-aname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`aRecords`](#parameter-aarecords) | array | The list of A records in the record set. | +| [`metadata`](#parameter-ametadata) | object | The metadata of the record. | +| [`roleAssignments`](#parameter-aroleassignments) | array | Array of role assignments to create. | +| [`targetResourceId`](#parameter-atargetresourceid) | string | A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. | +| [`ttl`](#parameter-attl) | int | The TTL of the record. | + +### Parameter: `a.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `a.aRecords` + +The list of A records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipv4Address`](#parameter-aarecordsipv4address) | string | The IPv4 address of this A record. | + +### Parameter: `a.aRecords.ipv4Address` + +The IPv4 address of this A record. + +- Required: Yes +- Type: string + +### Parameter: `a.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `a.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-aroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-aroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-aroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-aroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-aroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-aroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-aroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-aroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `a.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `a.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `a.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `a.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `a.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `a.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `a.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `a.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `a.targetResourceId` + +A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. + +- Required: No +- Type: string + +### Parameter: `a.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `aaaa` + +Array of AAAA records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-aaaaname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`aaaaRecords`](#parameter-aaaaaaaarecords) | array | The list of AAAA records in the record set. | +| [`metadata`](#parameter-aaaametadata) | object | The metadata of the record. | +| [`roleAssignments`](#parameter-aaaaroleassignments) | array | Array of role assignments to create. | +| [`targetResourceId`](#parameter-aaaatargetresourceid) | string | A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. | +| [`ttl`](#parameter-aaaattl) | int | The TTL of the record. | + +### Parameter: `aaaa.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `aaaa.aaaaRecords` + +The list of AAAA records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipv6Address`](#parameter-aaaaaaaarecordsipv6address) | string | The IPv6 address of this AAAA record. | + +### Parameter: `aaaa.aaaaRecords.ipv6Address` + +The IPv6 address of this AAAA record. + +- Required: Yes +- Type: string + +### Parameter: `aaaa.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `aaaa.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-aaaaroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-aaaaroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-aaaaroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-aaaaroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-aaaaroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-aaaaroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-aaaaroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-aaaaroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `aaaa.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `aaaa.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `aaaa.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `aaaa.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `aaaa.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `aaaa.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `aaaa.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `aaaa.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `aaaa.targetResourceId` + +A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. + +- Required: No +- Type: string + +### Parameter: `aaaa.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `caa` + +Array of CAA records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-caaname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`caaRecords`](#parameter-caacaarecords) | array | The list of CAA records in the record set. | +| [`metadata`](#parameter-caametadata) | object | The metadata of the record. | +| [`roleAssignments`](#parameter-caaroleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-caattl) | int | The TTL of the record. | + +### Parameter: `caa.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `caa.caaRecords` + +The list of CAA records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`flags`](#parameter-caacaarecordsflags) | int | The flags for this CAA record as an integer between 0 and 255. | +| [`tag`](#parameter-caacaarecordstag) | string | The tag for this CAA record.. | +| [`value`](#parameter-caacaarecordsvalue) | string | The value for this CAA record. | + +### Parameter: `caa.caaRecords.flags` + +The flags for this CAA record as an integer between 0 and 255. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 255 + +### Parameter: `caa.caaRecords.tag` + +The tag for this CAA record.. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 255 + +### Parameter: `caa.caaRecords.value` + +The value for this CAA record. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 255 + +### Parameter: `caa.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `caa.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-caaroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-caaroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-caaroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-caaroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-caaroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-caaroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-caaroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-caaroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `caa.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `caa.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `caa.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `caa.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `caa.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `caa.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `caa.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `caa.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `caa.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `cname` + +Array of CNAME records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-cnamename) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`cnameRecord`](#parameter-cnamecnamerecord) | object | The CNAME record in the record set. | +| [`metadata`](#parameter-cnamemetadata) | object | The metadata of the record. | +| [`roleAssignments`](#parameter-cnameroleassignments) | array | Array of role assignments to create. | +| [`targetResourceId`](#parameter-cnametargetresourceid) | string | A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. | +| [`ttl`](#parameter-cnamettl) | int | The TTL of the record. | + +### Parameter: `cname.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `cname.cnameRecord` + +The CNAME record in the record set. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`cname`](#parameter-cnamecnamerecordcname) | string | The canonical name of the CNAME record. | + +### Parameter: `cname.cnameRecord.cname` + +The canonical name of the CNAME record. + +- Required: Yes +- Type: string + +### Parameter: `cname.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `cname.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-cnameroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-cnameroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-cnameroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-cnameroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-cnameroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-cnameroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-cnameroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-cnameroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `cname.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `cname.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `cname.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `cname.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `cname.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `cname.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `cname.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `cname.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `cname.targetResourceId` + +A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. + +- Required: No +- Type: string + +### Parameter: `cname.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +The location of the dnsZone. Should be global. + +- Required: No +- Type: string +- Default: `'global'` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `mx` + +Array of MX records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-mxname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-mxmetadata) | object | The metadata of the record. | +| [`mxRecords`](#parameter-mxmxrecords) | array | The list of MX records in the record set. | +| [`roleAssignments`](#parameter-mxroleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-mxttl) | int | The TTL of the record. | + +### Parameter: `mx.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `mx.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `mx.mxRecords` + +The list of MX records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`exchange`](#parameter-mxmxrecordsexchange) | string | The domain name of the mail host for this MX record. | +| [`preference`](#parameter-mxmxrecordspreference) | int | The preference value for this MX record. | + +### Parameter: `mx.mxRecords.exchange` + +The domain name of the mail host for this MX record. + +- Required: Yes +- Type: string + +### Parameter: `mx.mxRecords.preference` + +The preference value for this MX record. + +- Required: Yes +- Type: int + +### Parameter: `mx.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-mxroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-mxroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-mxroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-mxroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-mxroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-mxroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-mxroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-mxroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `mx.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `mx.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `mx.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `mx.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `mx.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `mx.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `mx.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `mx.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `mx.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `ns` + +Array of NS records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-nsname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-nsmetadata) | object | The metadata of the record. | +| [`nsRecords`](#parameter-nsnsrecords) | array | The list of NS records in the record set. | +| [`roleAssignments`](#parameter-nsroleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-nsttl) | int | The TTL of the record. | + +### Parameter: `ns.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `ns.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `ns.nsRecords` + +The list of NS records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`nsdname`](#parameter-nsnsrecordsnsdname) | string | The name server name for this NS record. | + +### Parameter: `ns.nsRecords.nsdname` + +The name server name for this NS record. + +- Required: Yes +- Type: string + +### Parameter: `ns.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-nsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-nsroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-nsroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-nsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-nsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-nsroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-nsroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-nsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `ns.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `ns.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `ns.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `ns.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `ns.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `ns.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `ns.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `ns.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ns.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `ptr` + +Array of PTR records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-ptrname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-ptrmetadata) | object | The metadata of the record. | +| [`ptrRecords`](#parameter-ptrptrrecords) | array | The list of PTR records in the record set. | +| [`roleAssignments`](#parameter-ptrroleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-ptrttl) | int | The TTL of the record. | + +### Parameter: `ptr.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `ptr.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `ptr.ptrRecords` + +The list of PTR records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ptrdname`](#parameter-ptrptrrecordsptrdname) | string | The PTR target domain name for this PTR record. | + +### Parameter: `ptr.ptrRecords.ptrdname` + +The PTR target domain name for this PTR record. + +- Required: Yes +- Type: string + +### Parameter: `ptr.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-ptrroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-ptrroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-ptrroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-ptrroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-ptrroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-ptrroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-ptrroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-ptrroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `ptr.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `ptr.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `ptr.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `ptr.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `ptr.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `ptr.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `ptr.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `ptr.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ptr.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `soa` + +Array of SOA records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-soaname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-soametadata) | object | The metadata of the record. | +| [`roleAssignments`](#parameter-soaroleassignments) | array | Array of role assignments to create. | +| [`soaRecord`](#parameter-soasoarecord) | object | The SOA record in the record set. | +| [`ttl`](#parameter-soattl) | int | The TTL of the record. | + +### Parameter: `soa.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `soa.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `soa.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-soaroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-soaroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-soaroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-soaroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-soaroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-soaroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-soaroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-soaroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `soa.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `soa.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `soa.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `soa.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `soa.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `soa.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `soa.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `soa.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `soa.soaRecord` + +The SOA record in the record set. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`email`](#parameter-soasoarecordemail) | string | The email contact for this SOA record. | +| [`expireTime`](#parameter-soasoarecordexpiretime) | int | The expire time for this SOA record. | +| [`host`](#parameter-soasoarecordhost) | string | The domain name of the authoritative name server for this SOA record. | +| [`minimumTtl`](#parameter-soasoarecordminimumttl) | int | The minimum value for this SOA record. By convention this is used to determine the negative caching duration. | +| [`refreshTime`](#parameter-soasoarecordrefreshtime) | int | The refresh value for this SOA record. | +| [`retryTime`](#parameter-soasoarecordretrytime) | int | The retry time for this SOA record. | +| [`serialNumber`](#parameter-soasoarecordserialnumber) | int | The serial number for this SOA record. | + +### Parameter: `soa.soaRecord.email` + +The email contact for this SOA record. + +- Required: Yes +- Type: string + +### Parameter: `soa.soaRecord.expireTime` + +The expire time for this SOA record. + +- Required: Yes +- Type: int + +### Parameter: `soa.soaRecord.host` + +The domain name of the authoritative name server for this SOA record. + +- Required: Yes +- Type: string + +### Parameter: `soa.soaRecord.minimumTtl` + +The minimum value for this SOA record. By convention this is used to determine the negative caching duration. + +- Required: Yes +- Type: int + +### Parameter: `soa.soaRecord.refreshTime` + +The refresh value for this SOA record. + +- Required: Yes +- Type: int + +### Parameter: `soa.soaRecord.retryTime` + +The retry time for this SOA record. + +- Required: Yes +- Type: int + +### Parameter: `soa.soaRecord.serialNumber` + +The serial number for this SOA record. + +- Required: Yes +- Type: int + +### Parameter: `soa.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `srv` + +Array of SRV records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-srvname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-srvmetadata) | object | The metadata of the record. | +| [`roleAssignments`](#parameter-srvroleassignments) | array | Array of role assignments to create. | +| [`srvRecords`](#parameter-srvsrvrecords) | array | The list of SRV records in the record set. | +| [`ttl`](#parameter-srvttl) | int | The TTL of the record. | + +### Parameter: `srv.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `srv.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `srv.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-srvroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-srvroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-srvroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-srvroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-srvroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-srvroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-srvroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-srvroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `srv.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `srv.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `srv.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `srv.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `srv.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `srv.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `srv.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `srv.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `srv.srvRecords` + +The list of SRV records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`port`](#parameter-srvsrvrecordsport) | int | The port value for this SRV record. | +| [`priority`](#parameter-srvsrvrecordspriority) | int | The priority value for this SRV record. | +| [`target`](#parameter-srvsrvrecordstarget) | string | The target domain name for this SRV record. | +| [`weight`](#parameter-srvsrvrecordsweight) | int | The weight value for this SRV record. | + +### Parameter: `srv.srvRecords.port` + +The port value for this SRV record. + +- Required: Yes +- Type: int + +### Parameter: `srv.srvRecords.priority` + +The priority value for this SRV record. + +- Required: Yes +- Type: int + +### Parameter: `srv.srvRecords.target` + +The target domain name for this SRV record. + +- Required: Yes +- Type: string + +### Parameter: `srv.srvRecords.weight` + +The weight value for this SRV record. + +- Required: Yes +- Type: int + +### Parameter: `srv.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `txt` + +Array of TXT records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-txtname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-txtmetadata) | object | The metadata of the record. | +| [`roleAssignments`](#parameter-txtroleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-txtttl) | int | The TTL of the record. | +| [`txtRecords`](#parameter-txttxtrecords) | array | The list of TXT records in the record set. | + +### Parameter: `txt.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `txt.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `txt.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-txtroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-txtroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-txtroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-txtroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-txtroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-txtroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-txtroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-txtroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `txt.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `txt.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `txt.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `txt.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `txt.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `txt.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `txt.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `txt.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `txt.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `txt.txtRecords` + +The list of TXT records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`value`](#parameter-txttxtrecordsvalue) | array | The text value of this TXT record. | + +### Parameter: `txt.txtRecords.value` + +The text value of this TXT record. + +- Required: Yes +- Type: array + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the DNS zone. | +| `nameServers` | array | The name servers of the DNS zone. | +| `resourceGroupName` | string | The resource group the DNS zone was deployed into. | +| `resourceId` | string | The resource ID of the DNS zone. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/dns-zone/a/README.md b/avm/1.1.0/res/network/dns-zone/a/README.md new file mode 100644 index 000000000..e93a99ac4 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/a/README.md @@ -0,0 +1,200 @@ +# Public DNS Zone A record `[Microsoft.Network/dnsZones/A]` + +This module deploys a Public DNS Zone A record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/dnsZones/A` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/A) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the A record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsZoneName`](#parameter-dnszonename) | string | The name of the parent DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`aRecords`](#parameter-arecords) | array | The list of A records in the record set. Cannot be used in conjuction with the "targetResource" property. | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`targetResourceId`](#parameter-targetresourceid) | string | A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the A record. + +- Required: Yes +- Type: string + +### Parameter: `dnsZoneName` + +The name of the parent DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `aRecords` + +The list of A records in the record set. Cannot be used in conjuction with the "targetResource" property. + +- Required: No +- Type: array + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `targetResourceId` + +A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. + +- Required: No +- Type: string + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed A record. | +| `resourceGroupName` | string | The resource group of the deployed A record. | +| `resourceId` | string | The resource ID of the deployed A record. | diff --git a/avm/1.1.0/res/network/dns-zone/a/main.bicep b/avm/1.1.0/res/network/dns-zone/a/main.bicep new file mode 100644 index 000000000..0c531772f --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/a/main.bicep @@ -0,0 +1,144 @@ +metadata name = 'Public DNS Zone A record' +metadata description = 'This module deploys a Public DNS Zone A record.' + +@description('Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment.') +param dnsZoneName string + +@description('Required. The name of the A record.') +param name string + +@description('Optional. The list of A records in the record set. Cannot be used in conjuction with the "targetResource" property.') +param aRecords array? + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property.') +param targetResourceId string? + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] +resource dnsZone 'Microsoft.Network/dnsZones@2018-05-01' existing = { + name: dnsZoneName +} + +resource A 'Microsoft.Network/dnsZones/A@2018-05-01' = { + name: name + parent: dnsZone + properties: { + ARecords: aRecords + metadata: metadata + TTL: ttl + targetResource: !empty(targetResourceId) + ? { + id: targetResourceId + } + : null + } +} + +resource A_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(A.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: A + } +] + +@description('The name of the deployed A record.') +output name string = A.name + +@description('The resource ID of the deployed A record.') +output resourceId string = A.id + +@description('The resource group of the deployed A record.') +output resourceGroupName string = resourceGroup().name +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/dns-zone/a/main.json b/avm/1.1.0/res/network/dns-zone/a/main.json new file mode 100644 index 000000000..75c20fb1e --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/a/main.json @@ -0,0 +1,223 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15608891845705409701" + }, + "name": "Public DNS Zone A record", + "description": "This module deploys a Public DNS Zone A record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the A record." + } + }, + "aRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of A records in the record set. Cannot be used in conjuction with the \"targetResource\" property." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "targetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the \"aRecords\" property." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "A": { + "type": "Microsoft.Network/dnsZones/A", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "ARecords": "[parameters('aRecords')]", + "metadata": "[parameters('metadata')]", + "TTL": "[parameters('ttl')]", + "targetResource": "[if(not(empty(parameters('targetResourceId'))), createObject('id', parameters('targetResourceId')), null())]" + } + }, + "A_roleAssignments": { + "copy": { + "name": "A_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/A/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/A', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "A" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed A record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed A record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/A', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed A record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-zone/aaaa/README.md b/avm/1.1.0/res/network/dns-zone/aaaa/README.md new file mode 100644 index 000000000..99120461e --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/aaaa/README.md @@ -0,0 +1,200 @@ +# Public DNS Zone AAAA record `[Microsoft.Network/dnsZones/AAAA]` + +This module deploys a Public DNS Zone AAAA record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/dnsZones/AAAA` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/AAAA) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the AAAA record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsZoneName`](#parameter-dnszonename) | string | The name of the parent DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`aaaaRecords`](#parameter-aaaarecords) | array | The list of AAAA records in the record set. Cannot be used in conjuction with the "targetResource" property. | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`targetResourceId`](#parameter-targetresourceid) | string | A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the AAAA record. + +- Required: Yes +- Type: string + +### Parameter: `dnsZoneName` + +The name of the parent DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `aaaaRecords` + +The list of AAAA records in the record set. Cannot be used in conjuction with the "targetResource" property. + +- Required: No +- Type: array + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `targetResourceId` + +A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. + +- Required: No +- Type: string + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed AAAA record. | +| `resourceGroupName` | string | The resource group of the deployed AAAA record. | +| `resourceId` | string | The resource ID of the deployed AAAA record. | diff --git a/avm/1.1.0/res/network/dns-zone/aaaa/main.bicep b/avm/1.1.0/res/network/dns-zone/aaaa/main.bicep new file mode 100644 index 000000000..fd9460167 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/aaaa/main.bicep @@ -0,0 +1,145 @@ +metadata name = 'Public DNS Zone AAAA record' +metadata description = 'This module deploys a Public DNS Zone AAAA record.' + +@description('Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment.') +param dnsZoneName string + +@description('Required. The name of the AAAA record.') +param name string + +@description('Optional. The list of AAAA records in the record set. Cannot be used in conjuction with the "targetResource" property.') +param aaaaRecords array? + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property.') +param targetResourceId string? + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource dnsZone 'Microsoft.Network/dnsZones@2018-05-01' existing = { + name: dnsZoneName +} + +resource AAAA 'Microsoft.Network/dnsZones/AAAA@2018-05-01' = { + name: name + parent: dnsZone + properties: { + AAAARecords: aaaaRecords + metadata: metadata + TTL: ttl + targetResource: !empty(targetResourceId) + ? { + id: targetResourceId + } + : null + } +} + +resource AAAA_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(AAAA.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: AAAA + } +] + +@description('The name of the deployed AAAA record.') +output name string = AAAA.name + +@description('The resource ID of the deployed AAAA record.') +output resourceId string = AAAA.id + +@description('The resource group of the deployed AAAA record.') +output resourceGroupName string = resourceGroup().name +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/dns-zone/aaaa/main.json b/avm/1.1.0/res/network/dns-zone/aaaa/main.json new file mode 100644 index 000000000..03d2e8c72 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/aaaa/main.json @@ -0,0 +1,223 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3985689670692711318" + }, + "name": "Public DNS Zone AAAA record", + "description": "This module deploys a Public DNS Zone AAAA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the AAAA record." + } + }, + "aaaaRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of AAAA records in the record set. Cannot be used in conjuction with the \"targetResource\" property." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "targetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the \"aRecords\" property." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "AAAA": { + "type": "Microsoft.Network/dnsZones/AAAA", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "AAAARecords": "[parameters('aaaaRecords')]", + "metadata": "[parameters('metadata')]", + "TTL": "[parameters('ttl')]", + "targetResource": "[if(not(empty(parameters('targetResourceId'))), createObject('id', parameters('targetResourceId')), null())]" + } + }, + "AAAA_roleAssignments": { + "copy": { + "name": "AAAA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/AAAA/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/AAAA', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "AAAA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed AAAA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed AAAA record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/AAAA', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed AAAA record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-zone/caa/README.md b/avm/1.1.0/res/network/dns-zone/caa/README.md new file mode 100644 index 000000000..7d1b1ef22 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/caa/README.md @@ -0,0 +1,192 @@ +# Public DNS Zone CAA record `[Microsoft.Network/dnsZones/CAA]` + +This module deploys a Public DNS Zone CAA record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/dnsZones/CAA` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/CAA) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the CAA record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsZoneName`](#parameter-dnszonename) | string | The name of the parent DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`caaRecords`](#parameter-caarecords) | array | The list of CAA records in the record set. | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the CAA record. + +- Required: Yes +- Type: string + +### Parameter: `dnsZoneName` + +The name of the parent DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `caaRecords` + +The list of CAA records in the record set. + +- Required: No +- Type: array + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed CAA record. | +| `resourceGroupName` | string | The resource group of the deployed CAA record. | +| `resourceId` | string | The resource ID of the deployed CAA record. | diff --git a/avm/1.1.0/res/network/dns-zone/caa/main.bicep b/avm/1.1.0/res/network/dns-zone/caa/main.bicep new file mode 100644 index 000000000..897fe7776 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/caa/main.bicep @@ -0,0 +1,137 @@ +metadata name = 'Public DNS Zone CAA record' +metadata description = 'This module deploys a Public DNS Zone CAA record.' + +@description('Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment.') +param dnsZoneName string + +@description('Required. The name of the CAA record.') +param name string + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The list of CAA records in the record set.') +param caaRecords array? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource dnsZone 'Microsoft.Network/dnsZones@2018-05-01' existing = { + name: dnsZoneName +} + +resource CAA 'Microsoft.Network/dnsZones/CAA@2018-05-01' = { + name: name + parent: dnsZone + properties: { + metadata: metadata + caaRecords: caaRecords + TTL: ttl + } +} + +resource CAA_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(CAA.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: CAA + } +] + +@description('The name of the deployed CAA record.') +output name string = CAA.name + +@description('The resource ID of the deployed CAA record.') +output resourceId string = CAA.id + +@description('The resource group of the deployed CAA record.') +output resourceGroupName string = resourceGroup().name +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/dns-zone/caa/main.json b/avm/1.1.0/res/network/dns-zone/caa/main.json new file mode 100644 index 000000000..50028f0bc --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/caa/main.json @@ -0,0 +1,215 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "11491148399190061858" + }, + "name": "Public DNS Zone CAA record", + "description": "This module deploys a Public DNS Zone CAA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the CAA record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "caaRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of CAA records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "CAA": { + "type": "Microsoft.Network/dnsZones/CAA", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "caaRecords": "[parameters('caaRecords')]", + "TTL": "[parameters('ttl')]" + } + }, + "CAA_roleAssignments": { + "copy": { + "name": "CAA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/CAA/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/CAA', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "CAA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed CAA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed CAA record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/CAA', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed CAA record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-zone/cname/README.md b/avm/1.1.0/res/network/dns-zone/cname/README.md new file mode 100644 index 000000000..7107700e8 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/cname/README.md @@ -0,0 +1,200 @@ +# Public DNS Zone CNAME record `[Microsoft.Network/dnsZones/CNAME]` + +This module deploys a Public DNS Zone CNAME record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/dnsZones/CNAME` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/CNAME) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the CNAME record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsZoneName`](#parameter-dnszonename) | string | The name of the parent DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`cnameRecord`](#parameter-cnamerecord) | object | A CNAME record. Cannot be used in conjuction with the "targetResource" property. | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`targetResourceId`](#parameter-targetresourceid) | string | A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the CNAME record. + +- Required: Yes +- Type: string + +### Parameter: `dnsZoneName` + +The name of the parent DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `cnameRecord` + +A CNAME record. Cannot be used in conjuction with the "targetResource" property. + +- Required: No +- Type: object + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `targetResourceId` + +A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property. + +- Required: No +- Type: string + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed CNAME record. | +| `resourceGroupName` | string | The resource group of the deployed CNAME record. | +| `resourceId` | string | The resource ID of the deployed CNAME record. | diff --git a/avm/1.1.0/res/network/dns-zone/cname/main.bicep b/avm/1.1.0/res/network/dns-zone/cname/main.bicep new file mode 100644 index 000000000..786a3f7c4 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/cname/main.bicep @@ -0,0 +1,145 @@ +metadata name = 'Public DNS Zone CNAME record' +metadata description = 'This module deploys a Public DNS Zone CNAME record.' + +@description('Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment.') +param dnsZoneName string + +@description('Required. The name of the CNAME record.') +param name string + +@description('Optional. A CNAME record. Cannot be used in conjuction with the "targetResource" property.') +param cnameRecord object? + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property.') +param targetResourceId string? + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource dnsZone 'Microsoft.Network/dnsZones@2018-05-01' existing = { + name: dnsZoneName +} + +resource CNAME 'Microsoft.Network/dnsZones/CNAME@2018-05-01' = { + name: name + parent: dnsZone + properties: { + CNAMERecord: cnameRecord + metadata: metadata + TTL: ttl + targetResource: !empty(targetResourceId) + ? { + id: targetResourceId + } + : null + } +} + +resource CNAME_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(CNAME.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: CNAME + } +] + +@description('The name of the deployed CNAME record.') +output name string = CNAME.name + +@description('The resource ID of the deployed CNAME record.') +output resourceId string = CNAME.id + +@description('The resource group of the deployed CNAME record.') +output resourceGroupName string = resourceGroup().name +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/dns-zone/cname/main.json b/avm/1.1.0/res/network/dns-zone/cname/main.json new file mode 100644 index 000000000..aed841c56 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/cname/main.json @@ -0,0 +1,223 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12621931033265041406" + }, + "name": "Public DNS Zone CNAME record", + "description": "This module deploys a Public DNS Zone CNAME record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the CNAME record." + } + }, + "cnameRecord": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A CNAME record. Cannot be used in conjuction with the \"targetResource\" property." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "targetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the \"aRecords\" property." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "CNAME": { + "type": "Microsoft.Network/dnsZones/CNAME", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "CNAMERecord": "[parameters('cnameRecord')]", + "metadata": "[parameters('metadata')]", + "TTL": "[parameters('ttl')]", + "targetResource": "[if(not(empty(parameters('targetResourceId'))), createObject('id', parameters('targetResourceId')), null())]" + } + }, + "CNAME_roleAssignments": { + "copy": { + "name": "CNAME_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/CNAME/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/CNAME', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "CNAME" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed CNAME record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed CNAME record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/CNAME', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed CNAME record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-zone/main.bicep b/avm/1.1.0/res/network/dns-zone/main.bicep new file mode 100644 index 000000000..3a173633c --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/main.bicep @@ -0,0 +1,599 @@ +metadata name = 'Public DNS Zones' +metadata description = 'This module deploys a Public DNS zone.' + +@description('Required. DNS zone name.') +@minLength(1) +@maxLength(63) +param name string + +@description('Optional. Array of A records.') +param a aType + +@description('Optional. Array of AAAA records.') +param aaaa aaaaType + +@description('Optional. Array of CNAME records.') +param cname cnameType + +@description('Optional. Array of CAA records.') +param caa caaType + +@description('Optional. Array of MX records.') +param mx mxType + +@description('Optional. Array of NS records.') +param ns nsType + +@description('Optional. Array of PTR records.') +param ptr ptrType + +@description('Optional. Array of SOA records.') +param soa soaType + +@description('Optional. Array of SRV records.') +param srv srvType + +@description('Optional. Array of TXT records.') +param txt txtType + +@description('Optional. The location of the dnsZone. Should be global.') +param location string = 'global' + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-dnszone.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource dnsZone 'Microsoft.Network/dnsZones@2018-05-01' = { + name: name + location: location + tags: tags + properties: { + zoneType: 'Public' + } +} + +module dnsZone_A 'a/main.bicep' = [ + for (aRecord, index) in (a ?? []): { + name: '${uniqueString(deployment().name, location)}-dnsZone-ARecord-${index}' + params: { + dnsZoneName: dnsZone.name + name: aRecord.name + aRecords: aRecord.?aRecords + metadata: aRecord.?metadata + ttl: aRecord.?ttl ?? 3600 + targetResourceId: aRecord.?targetResourceId + roleAssignments: aRecord.?roleAssignments + } + } +] + +module dnsZone_AAAA 'aaaa/main.bicep' = [ + for (aaaaRecord, index) in (aaaa ?? []): { + name: '${uniqueString(deployment().name, location)}-dnsZone-AAAARecord-${index}' + params: { + dnsZoneName: dnsZone.name + name: aaaaRecord.name + aaaaRecords: aaaaRecord.?aaaaRecords + metadata: aaaaRecord.?metadata + ttl: aaaaRecord.?ttl ?? 3600 + targetResourceId: aaaaRecord.?targetResourceId + roleAssignments: aaaaRecord.?roleAssignments + } + } +] + +module dnsZone_CNAME 'cname/main.bicep' = [ + for (cnameRecord, index) in (cname ?? []): { + name: '${uniqueString(deployment().name, location)}-dnsZone-CNAMERecord-${index}' + params: { + dnsZoneName: dnsZone.name + name: cnameRecord.name + cnameRecord: cnameRecord.?cnameRecord + metadata: cnameRecord.?metadata + ttl: cnameRecord.?ttl ?? 3600 + targetResourceId: cnameRecord.?targetResourceId + roleAssignments: cnameRecord.?roleAssignments + } + } +] + +module dnsZone_CAA 'caa/main.bicep' = [ + for (caaRecord, index) in (caa ?? []): { + name: '${uniqueString(deployment().name, location)}-dnsZone-CAARecord-${index}' + params: { + dnsZoneName: dnsZone.name + name: caaRecord.name + metadata: caaRecord.?metadata + caaRecords: caaRecord.?caaRecords + ttl: caaRecord.?ttl ?? 3600 + roleAssignments: caaRecord.?roleAssignments + } + } +] + +module dnsZone_MX 'mx/main.bicep' = [ + for (mxRecord, index) in (mx ?? []): { + name: '${uniqueString(deployment().name, location)}-dnsZone-MXRecord-${index}' + params: { + dnsZoneName: dnsZone.name + name: mxRecord.name + metadata: mxRecord.?metadata + mxRecords: mxRecord.?mxRecords + ttl: mxRecord.?ttl ?? 3600 + roleAssignments: mxRecord.?roleAssignments + } + } +] + +module dnsZone_NS 'ns/main.bicep' = [ + for (nsRecord, index) in (ns ?? []): { + name: '${uniqueString(deployment().name, location)}-dnsZone-NSRecord-${index}' + params: { + dnsZoneName: dnsZone.name + name: nsRecord.name + metadata: nsRecord.?metadata + nsRecords: nsRecord.?nsRecords + ttl: nsRecord.?ttl ?? 3600 + roleAssignments: nsRecord.?roleAssignments + } + } +] + +module dnsZone_PTR 'ptr/main.bicep' = [ + for (ptrRecord, index) in (ptr ?? []): { + name: '${uniqueString(deployment().name, location)}-dnsZone-PTRRecord-${index}' + params: { + dnsZoneName: dnsZone.name + name: ptrRecord.name + metadata: ptrRecord.?metadata + ptrRecords: ptrRecord.?ptrRecords + ttl: ptrRecord.?ttl ?? 3600 + roleAssignments: ptrRecord.?roleAssignments + } + } +] + +module dnsZone_SOA 'soa/main.bicep' = [ + for (soaRecord, index) in (soa ?? []): { + name: '${uniqueString(deployment().name, location)}-dnsZone-SOARecord-${index}' + params: { + dnsZoneName: dnsZone.name + name: soaRecord.name + metadata: soaRecord.?metadata + soaRecord: soaRecord.?soaRecord + ttl: soaRecord.?ttl ?? 3600 + roleAssignments: soaRecord.?roleAssignments + } + } +] + +module dnsZone_SRV 'srv/main.bicep' = [ + for (srvRecord, index) in (srv ?? []): { + name: '${uniqueString(deployment().name, location)}-dnsZone-SRVRecord-${index}' + params: { + dnsZoneName: dnsZone.name + name: srvRecord.name + metadata: srvRecord.?metadata + srvRecords: srvRecord.?srvRecords + ttl: srvRecord.?ttl ?? 3600 + roleAssignments: srvRecord.?roleAssignments + } + } +] + +module dnsZone_TXT 'txt/main.bicep' = [ + for (txtRecord, index) in (txt ?? []): { + name: '${uniqueString(deployment().name, location)}-dnsZone-TXTRecord-${index}' + params: { + dnsZoneName: dnsZone.name + name: txtRecord.name + metadata: txtRecord.?metadata + txtRecords: txtRecord.?txtRecords + ttl: txtRecord.?ttl ?? 3600 + roleAssignments: txtRecord.?roleAssignments + } + } +] + +resource dnsZone_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: dnsZone +} + +resource dnsZone_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(dnsZone.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: dnsZone + } +] + +@description('The resource group the DNS zone was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the DNS zone.') +output name string = dnsZone.name + +@description('The resource ID of the DNS zone.') +output resourceId string = dnsZone.id + +@description('The location the resource was deployed into.') +output location string = dnsZone.location + +@description('The name servers of the DNS zone.') +output nameServers array = dnsZone.properties.nameServers + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type aType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property.') + targetResourceId: string? + + @description('Optional. The list of A records in the record set.') + aRecords: { + @description('Required. The IPv4 address of this A record.') + ipv4Address: string + }[]? +}[]? + +type aaaaType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property.') + targetResourceId: string? + + @description('Optional. The list of AAAA records in the record set.') + aaaaRecords: { + @description('Required. The IPv6 address of this AAAA record.') + ipv6Address: string + }[]? +}[]? + +type cnameType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the "aRecords" property.') + targetResourceId: string? + + @description('Optional. The CNAME record in the record set.') + cnameRecord: { + @description('Required. The canonical name of the CNAME record.') + cname: string + }? +}[]? + +type caaType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The list of CAA records in the record set.') + caaRecords: { + @description('Required. The flags for this CAA record as an integer between 0 and 255.') + @minValue(0) + @maxValue(255) + flags: int + + @description('Required. The tag for this CAA record..') + tag: string + + @description('Required. The value for this CAA record.') + value: string + }[]? +}[]? + +type mxType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The list of MX records in the record set.') + mxRecords: { + @description('Required. The domain name of the mail host for this MX record.') + exchange: string + + @description('Required. The preference value for this MX record.') + preference: int + }[]? +}[]? + +type nsType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The list of NS records in the record set.') + nsRecords: { + @description('Required. The name server name for this NS record.') + nsdname: string + }[]? +}[]? + +type ptrType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The list of PTR records in the record set.') + ptrRecords: { + @description('Required. The PTR target domain name for this PTR record.') + ptrdname: string + }[]? +}[]? + +type soaType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The SOA record in the record set.') + soaRecord: { + @description('Required. The email contact for this SOA record.') + email: string + + @description('Required. The expire time for this SOA record.') + expireTime: int + + @description('Required. The domain name of the authoritative name server for this SOA record.') + host: string + + @description('Required. The minimum value for this SOA record. By convention this is used to determine the negative caching duration.') + minimumTtl: int + + @description('Required. The refresh value for this SOA record.') + refreshTime: int + + @description('Required. The retry time for this SOA record.') + retryTime: int + + @description('Required. The serial number for this SOA record.') + serialNumber: int + }? +}[]? + +type srvType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The list of SRV records in the record set.') + srvRecords: { + @description('Required. The priority value for this SRV record.') + priority: int + + @description('Required. The weight value for this SRV record.') + weight: int + + @description('Required. The port value for this SRV record.') + port: int + + @description('Required. The target domain name for this SRV record.') + target: string + }[]? +}[]? + +type txtType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The list of TXT records in the record set.') + txtRecords: { + @description('Required. The text value of this TXT record.') + value: string[] + }[]? +}[]? diff --git a/avm/1.1.0/res/network/dns-zone/main.json b/avm/1.1.0/res/network/dns-zone/main.json new file mode 100644 index 000000000..d92037fa3 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/main.json @@ -0,0 +1,3529 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9421241657819525275" + }, + "name": "Public DNS Zones", + "description": "This module deploys a Public DNS zone." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "aType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "targetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the \"aRecords\" property." + } + }, + "aRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipv4Address": { + "type": "string", + "metadata": { + "description": "Required. The IPv4 address of this A record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of A records in the record set." + } + } + } + }, + "nullable": true + }, + "aaaaType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "targetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the \"aRecords\" property." + } + }, + "aaaaRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipv6Address": { + "type": "string", + "metadata": { + "description": "Required. The IPv6 address of this AAAA record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of AAAA records in the record set." + } + } + } + }, + "nullable": true + }, + "cnameType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "targetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the \"aRecords\" property." + } + }, + "cnameRecord": { + "type": "object", + "properties": { + "cname": { + "type": "string", + "metadata": { + "description": "Required. The canonical name of the CNAME record." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The CNAME record in the record set." + } + } + } + }, + "nullable": true + }, + "caaType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "caaRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "flags": { + "type": "int", + "minValue": 0, + "maxValue": 255, + "metadata": { + "description": "Required. The flags for this CAA record as an integer between 0 and 255." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The tag for this CAA record.." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. The value for this CAA record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of CAA records in the record set." + } + } + } + }, + "nullable": true + }, + "mxType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "mxRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "exchange": { + "type": "string", + "metadata": { + "description": "Required. The domain name of the mail host for this MX record." + } + }, + "preference": { + "type": "int", + "metadata": { + "description": "Required. The preference value for this MX record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of MX records in the record set." + } + } + } + }, + "nullable": true + }, + "nsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "nsRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "nsdname": { + "type": "string", + "metadata": { + "description": "Required. The name server name for this NS record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of NS records in the record set." + } + } + } + }, + "nullable": true + }, + "ptrType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "ptrRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ptrdname": { + "type": "string", + "metadata": { + "description": "Required. The PTR target domain name for this PTR record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of PTR records in the record set." + } + } + } + }, + "nullable": true + }, + "soaType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "soaRecord": { + "type": "object", + "properties": { + "email": { + "type": "string", + "metadata": { + "description": "Required. The email contact for this SOA record." + } + }, + "expireTime": { + "type": "int", + "metadata": { + "description": "Required. The expire time for this SOA record." + } + }, + "host": { + "type": "string", + "metadata": { + "description": "Required. The domain name of the authoritative name server for this SOA record." + } + }, + "minimumTtl": { + "type": "int", + "metadata": { + "description": "Required. The minimum value for this SOA record. By convention this is used to determine the negative caching duration." + } + }, + "refreshTime": { + "type": "int", + "metadata": { + "description": "Required. The refresh value for this SOA record." + } + }, + "retryTime": { + "type": "int", + "metadata": { + "description": "Required. The retry time for this SOA record." + } + }, + "serialNumber": { + "type": "int", + "metadata": { + "description": "Required. The serial number for this SOA record." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The SOA record in the record set." + } + } + } + }, + "nullable": true + }, + "srvType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "srvRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "priority": { + "type": "int", + "metadata": { + "description": "Required. The priority value for this SRV record." + } + }, + "weight": { + "type": "int", + "metadata": { + "description": "Required. The weight value for this SRV record." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. The port value for this SRV record." + } + }, + "target": { + "type": "string", + "metadata": { + "description": "Required. The target domain name for this SRV record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of SRV records in the record set." + } + } + } + }, + "nullable": true + }, + "txtType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "txtRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The text value of this TXT record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of TXT records in the record set." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 63, + "metadata": { + "description": "Required. DNS zone name." + } + }, + "a": { + "$ref": "#/definitions/aType", + "metadata": { + "description": "Optional. Array of A records." + } + }, + "aaaa": { + "$ref": "#/definitions/aaaaType", + "metadata": { + "description": "Optional. Array of AAAA records." + } + }, + "cname": { + "$ref": "#/definitions/cnameType", + "metadata": { + "description": "Optional. Array of CNAME records." + } + }, + "caa": { + "$ref": "#/definitions/caaType", + "metadata": { + "description": "Optional. Array of CAA records." + } + }, + "mx": { + "$ref": "#/definitions/mxType", + "metadata": { + "description": "Optional. Array of MX records." + } + }, + "ns": { + "$ref": "#/definitions/nsType", + "metadata": { + "description": "Optional. Array of NS records." + } + }, + "ptr": { + "$ref": "#/definitions/ptrType", + "metadata": { + "description": "Optional. Array of PTR records." + } + }, + "soa": { + "$ref": "#/definitions/soaType", + "metadata": { + "description": "Optional. Array of SOA records." + } + }, + "srv": { + "$ref": "#/definitions/srvType", + "metadata": { + "description": "Optional. Array of SRV records." + } + }, + "txt": { + "$ref": "#/definitions/txtType", + "metadata": { + "description": "Optional. Array of TXT records." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the dnsZone. Should be global." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-dnszone.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "dnsZone": { + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "zoneType": "Public" + } + }, + "dnsZone_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "dnsZone" + ] + }, + "dnsZone_roleAssignments": { + "copy": { + "name": "dnsZone_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "dnsZone" + ] + }, + "dnsZone_A": { + "copy": { + "name": "dnsZone_A", + "count": "[length(coalesce(parameters('a'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-dnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" + }, + "aRecords": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "targetResourceId": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'targetResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15608891845705409701" + }, + "name": "Public DNS Zone A record", + "description": "This module deploys a Public DNS Zone A record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the A record." + } + }, + "aRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of A records in the record set. Cannot be used in conjuction with the \"targetResource\" property." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "targetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the \"aRecords\" property." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "A": { + "type": "Microsoft.Network/dnsZones/A", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "ARecords": "[parameters('aRecords')]", + "metadata": "[parameters('metadata')]", + "TTL": "[parameters('ttl')]", + "targetResource": "[if(not(empty(parameters('targetResourceId'))), createObject('id', parameters('targetResourceId')), null())]" + } + }, + "A_roleAssignments": { + "copy": { + "name": "A_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/A/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/A', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "A" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed A record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed A record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/A', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed A record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dnsZone" + ] + }, + "dnsZone_AAAA": { + "copy": { + "name": "dnsZone_AAAA", + "count": "[length(coalesce(parameters('aaaa'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-dnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" + }, + "aaaaRecords": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "targetResourceId": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'targetResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3985689670692711318" + }, + "name": "Public DNS Zone AAAA record", + "description": "This module deploys a Public DNS Zone AAAA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the AAAA record." + } + }, + "aaaaRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of AAAA records in the record set. Cannot be used in conjuction with the \"targetResource\" property." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "targetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the \"aRecords\" property." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "AAAA": { + "type": "Microsoft.Network/dnsZones/AAAA", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "AAAARecords": "[parameters('aaaaRecords')]", + "metadata": "[parameters('metadata')]", + "TTL": "[parameters('ttl')]", + "targetResource": "[if(not(empty(parameters('targetResourceId'))), createObject('id', parameters('targetResourceId')), null())]" + } + }, + "AAAA_roleAssignments": { + "copy": { + "name": "AAAA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/AAAA/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/AAAA', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "AAAA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed AAAA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed AAAA record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/AAAA', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed AAAA record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dnsZone" + ] + }, + "dnsZone_CNAME": { + "copy": { + "name": "dnsZone_CNAME", + "count": "[length(coalesce(parameters('cname'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-dnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" + }, + "cnameRecord": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "targetResourceId": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'targetResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12621931033265041406" + }, + "name": "Public DNS Zone CNAME record", + "description": "This module deploys a Public DNS Zone CNAME record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the CNAME record." + } + }, + "cnameRecord": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A CNAME record. Cannot be used in conjuction with the \"targetResource\" property." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "targetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A reference to an azure resource from where the dns resource value is taken. Also known as an alias record sets and are only supported for record types A, AAAA and CNAME. A resource ID can be an Azure Traffic Manager, Azure CDN, Front Door, Static Web App, or a resource ID of a record set of the same type in the DNS zone (i.e. A, AAAA or CNAME). Cannot be used in conjuction with the \"aRecords\" property." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "CNAME": { + "type": "Microsoft.Network/dnsZones/CNAME", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "CNAMERecord": "[parameters('cnameRecord')]", + "metadata": "[parameters('metadata')]", + "TTL": "[parameters('ttl')]", + "targetResource": "[if(not(empty(parameters('targetResourceId'))), createObject('id', parameters('targetResourceId')), null())]" + } + }, + "CNAME_roleAssignments": { + "copy": { + "name": "CNAME_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/CNAME/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/CNAME', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "CNAME" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed CNAME record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed CNAME record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/CNAME', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed CNAME record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dnsZone" + ] + }, + "dnsZone_CAA": { + "copy": { + "name": "dnsZone_CAA", + "count": "[length(coalesce(parameters('caa'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-dnsZone-CAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('caa'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('caa'), createArray())[copyIndex()], 'metadata')]" + }, + "caaRecords": { + "value": "[tryGet(coalesce(parameters('caa'), createArray())[copyIndex()], 'caaRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('caa'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('caa'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "11491148399190061858" + }, + "name": "Public DNS Zone CAA record", + "description": "This module deploys a Public DNS Zone CAA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the CAA record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "caaRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of CAA records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "CAA": { + "type": "Microsoft.Network/dnsZones/CAA", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "caaRecords": "[parameters('caaRecords')]", + "TTL": "[parameters('ttl')]" + } + }, + "CAA_roleAssignments": { + "copy": { + "name": "CAA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/CAA/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/CAA', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "CAA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed CAA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed CAA record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/CAA', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed CAA record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dnsZone" + ] + }, + "dnsZone_MX": { + "copy": { + "name": "dnsZone_MX", + "count": "[length(coalesce(parameters('mx'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-dnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" + }, + "mxRecords": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "1922326996634877482" + }, + "name": "Public DNS Zone MX record", + "description": "This module deploys a Public DNS Zone MX record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the MX record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "mxRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of MX records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "MX": { + "type": "Microsoft.Network/dnsZones/MX", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "MXRecords": "[parameters('mxRecords')]", + "TTL": "[parameters('ttl')]" + } + }, + "MX_roleAssignments": { + "copy": { + "name": "MX_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/MX/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/MX', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "MX" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed MX record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed MX record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/MX', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed MX record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dnsZone" + ] + }, + "dnsZone_NS": { + "copy": { + "name": "dnsZone_NS", + "count": "[length(coalesce(parameters('ns'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-dnsZone-NSRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('ns'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('ns'), createArray())[copyIndex()], 'metadata')]" + }, + "nsRecords": { + "value": "[tryGet(coalesce(parameters('ns'), createArray())[copyIndex()], 'nsRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('ns'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('ns'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "13132579465005423306" + }, + "name": "Public DNS Zone NS record", + "description": "This module deploys a Public DNS Zone NS record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NS record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "nsRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of NS records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "NS": { + "type": "Microsoft.Network/dnsZones/NS", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "NSRecords": "[parameters('nsRecords')]", + "TTL": "[parameters('ttl')]" + } + }, + "NS_roleAssignments": { + "copy": { + "name": "NS_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/NS/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/NS', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "NS" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed NS record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed NS record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/NS', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed NS record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dnsZone" + ] + }, + "dnsZone_PTR": { + "copy": { + "name": "dnsZone_PTR", + "count": "[length(coalesce(parameters('ptr'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-dnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" + }, + "ptrRecords": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3784464033988272421" + }, + "name": "Public DNS Zone PTR record", + "description": "This module deploys a Public DNS Zone PTR record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the PTR record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ptrRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of PTR records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "PTR": { + "type": "Microsoft.Network/dnsZones/PTR", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "PTRRecords": "[parameters('ptrRecords')]", + "TTL": "[parameters('ttl')]" + } + }, + "PTR_roleAssignments": { + "copy": { + "name": "PTR_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/PTR/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/PTR', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "PTR" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed PTR record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed PTR record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/PTR', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed PTR record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dnsZone" + ] + }, + "dnsZone_SOA": { + "copy": { + "name": "dnsZone_SOA", + "count": "[length(coalesce(parameters('soa'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-dnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" + }, + "soaRecord": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "13888523145142266910" + }, + "name": "Public DNS Zone SOA record", + "description": "This module deploys a Public DNS Zone SOA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SOA record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "soaRecord": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A SOA record." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "SOA": { + "type": "Microsoft.Network/dnsZones/SOA", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "SOARecord": "[parameters('soaRecord')]", + "TTL": "[parameters('ttl')]" + } + }, + "SOA_roleAssignments": { + "copy": { + "name": "SOA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/SOA/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/SOA', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SOA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SOA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SOA record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/SOA', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SOA record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dnsZone" + ] + }, + "dnsZone_SRV": { + "copy": { + "name": "dnsZone_SRV", + "count": "[length(coalesce(parameters('srv'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-dnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" + }, + "srvRecords": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3361201996898116870" + }, + "name": "Public DNS Zone SRV record", + "description": "This module deploys a Public DNS Zone SRV record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SRV record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "srvRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of SRV records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "SRV": { + "type": "Microsoft.Network/dnsZones/SRV", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "SRVRecords": "[parameters('srvRecords')]", + "TTL": "[parameters('ttl')]" + } + }, + "SRV_roleAssignments": { + "copy": { + "name": "SRV_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/SRV/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/SRV', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SRV" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SRV record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SRV record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/SRV', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SRV record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dnsZone" + ] + }, + "dnsZone_TXT": { + "copy": { + "name": "dnsZone_TXT", + "count": "[length(coalesce(parameters('txt'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-dnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" + }, + "txtRecords": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "6318820825027351839" + }, + "name": "Public DNS Zone TXT record", + "description": "This module deploys a Public DNS Zone TXT record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the TXT record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "txtRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of TXT records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "TXT": { + "type": "Microsoft.Network/dnsZones/TXT", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "TTL": "[parameters('ttl')]", + "TXTRecords": "[parameters('txtRecords')]" + } + }, + "TXT_roleAssignments": { + "copy": { + "name": "TXT_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/TXT/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/TXT', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "TXT" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed TXT record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed TXT record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/TXT', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed TXT record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "dnsZone" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the DNS zone." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the DNS zone." + }, + "value": "[resourceId('Microsoft.Network/dnsZones', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('dnsZone', '2018-05-01', 'full').location]" + }, + "nameServers": { + "type": "array", + "metadata": { + "description": "The name servers of the DNS zone." + }, + "value": "[reference('dnsZone').nameServers]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-zone/mx/README.md b/avm/1.1.0/res/network/dns-zone/mx/README.md new file mode 100644 index 000000000..68615af23 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/mx/README.md @@ -0,0 +1,192 @@ +# Public DNS Zone MX record `[Microsoft.Network/dnsZones/MX]` + +This module deploys a Public DNS Zone MX record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/dnsZones/MX` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/MX) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the MX record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsZoneName`](#parameter-dnszonename) | string | The name of the parent DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`mxRecords`](#parameter-mxrecords) | array | The list of MX records in the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the MX record. + +- Required: Yes +- Type: string + +### Parameter: `dnsZoneName` + +The name of the parent DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `mxRecords` + +The list of MX records in the record set. + +- Required: No +- Type: array + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed MX record. | +| `resourceGroupName` | string | The resource group of the deployed MX record. | +| `resourceId` | string | The resource ID of the deployed MX record. | diff --git a/avm/1.1.0/res/network/dns-zone/mx/main.bicep b/avm/1.1.0/res/network/dns-zone/mx/main.bicep new file mode 100644 index 000000000..5c4334bd3 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/mx/main.bicep @@ -0,0 +1,137 @@ +metadata name = 'Public DNS Zone MX record' +metadata description = 'This module deploys a Public DNS Zone MX record.' + +@description('Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment.') +param dnsZoneName string + +@description('Required. The name of the MX record.') +param name string + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The list of MX records in the record set.') +param mxRecords array? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource dnsZone 'Microsoft.Network/dnsZones@2018-05-01' existing = { + name: dnsZoneName +} + +resource MX 'Microsoft.Network/dnsZones/MX@2018-05-01' = { + name: name + parent: dnsZone + properties: { + metadata: metadata + MXRecords: mxRecords + TTL: ttl + } +} + +resource MX_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(MX.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: MX + } +] + +@description('The name of the deployed MX record.') +output name string = MX.name + +@description('The resource ID of the deployed MX record.') +output resourceId string = MX.id + +@description('The resource group of the deployed MX record.') +output resourceGroupName string = resourceGroup().name +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/dns-zone/mx/main.json b/avm/1.1.0/res/network/dns-zone/mx/main.json new file mode 100644 index 000000000..2c28f8202 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/mx/main.json @@ -0,0 +1,215 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "1922326996634877482" + }, + "name": "Public DNS Zone MX record", + "description": "This module deploys a Public DNS Zone MX record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the MX record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "mxRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of MX records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "MX": { + "type": "Microsoft.Network/dnsZones/MX", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "MXRecords": "[parameters('mxRecords')]", + "TTL": "[parameters('ttl')]" + } + }, + "MX_roleAssignments": { + "copy": { + "name": "MX_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/MX/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/MX', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "MX" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed MX record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed MX record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/MX', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed MX record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-zone/ns/README.md b/avm/1.1.0/res/network/dns-zone/ns/README.md new file mode 100644 index 000000000..43fd817fe --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/ns/README.md @@ -0,0 +1,192 @@ +# Public DNS Zone NS record `[Microsoft.Network/dnsZones/NS]` + +This module deploys a Public DNS Zone NS record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/dnsZones/NS` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/NS) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the NS record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsZoneName`](#parameter-dnszonename) | string | The name of the parent DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`nsRecords`](#parameter-nsrecords) | array | The list of NS records in the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the NS record. + +- Required: Yes +- Type: string + +### Parameter: `dnsZoneName` + +The name of the parent DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `nsRecords` + +The list of NS records in the record set. + +- Required: No +- Type: array + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed NS record. | +| `resourceGroupName` | string | The resource group of the deployed NS record. | +| `resourceId` | string | The resource ID of the deployed NS record. | diff --git a/avm/1.1.0/res/network/dns-zone/ns/main.bicep b/avm/1.1.0/res/network/dns-zone/ns/main.bicep new file mode 100644 index 000000000..d50e0876d --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/ns/main.bicep @@ -0,0 +1,136 @@ +metadata name = 'Public DNS Zone NS record' +metadata description = 'This module deploys a Public DNS Zone NS record.' + +@description('Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment.') +param dnsZoneName string + +@description('Required. The name of the NS record.') +param name string + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The list of NS records in the record set.') +param nsRecords array? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] +resource dnsZone 'Microsoft.Network/dnsZones@2018-05-01' existing = { + name: dnsZoneName +} + +resource NS 'Microsoft.Network/dnsZones/NS@2018-05-01' = { + name: name + parent: dnsZone + properties: { + metadata: metadata + NSRecords: nsRecords + TTL: ttl + } +} + +resource NS_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(NS.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: NS + } +] + +@description('The name of the deployed NS record.') +output name string = NS.name + +@description('The resource ID of the deployed NS record.') +output resourceId string = NS.id + +@description('The resource group of the deployed NS record.') +output resourceGroupName string = resourceGroup().name +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/dns-zone/ns/main.json b/avm/1.1.0/res/network/dns-zone/ns/main.json new file mode 100644 index 000000000..7471e4fdd --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/ns/main.json @@ -0,0 +1,215 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "13132579465005423306" + }, + "name": "Public DNS Zone NS record", + "description": "This module deploys a Public DNS Zone NS record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NS record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "nsRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of NS records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "NS": { + "type": "Microsoft.Network/dnsZones/NS", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "NSRecords": "[parameters('nsRecords')]", + "TTL": "[parameters('ttl')]" + } + }, + "NS_roleAssignments": { + "copy": { + "name": "NS_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/NS/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/NS', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "NS" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed NS record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed NS record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/NS', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed NS record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-zone/ptr/README.md b/avm/1.1.0/res/network/dns-zone/ptr/README.md new file mode 100644 index 000000000..2dda8e4f5 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/ptr/README.md @@ -0,0 +1,192 @@ +# Public DNS Zone PTR record `[Microsoft.Network/dnsZones/PTR]` + +This module deploys a Public DNS Zone PTR record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/dnsZones/PTR` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/PTR) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the PTR record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsZoneName`](#parameter-dnszonename) | string | The name of the parent DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`ptrRecords`](#parameter-ptrrecords) | array | The list of PTR records in the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the PTR record. + +- Required: Yes +- Type: string + +### Parameter: `dnsZoneName` + +The name of the parent DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `ptrRecords` + +The list of PTR records in the record set. + +- Required: No +- Type: array + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed PTR record. | +| `resourceGroupName` | string | The resource group of the deployed PTR record. | +| `resourceId` | string | The resource ID of the deployed PTR record. | diff --git a/avm/1.1.0/res/network/dns-zone/ptr/main.bicep b/avm/1.1.0/res/network/dns-zone/ptr/main.bicep new file mode 100644 index 000000000..fbcb1d45f --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/ptr/main.bicep @@ -0,0 +1,137 @@ +metadata name = 'Public DNS Zone PTR record' +metadata description = 'This module deploys a Public DNS Zone PTR record.' + +@description('Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment.') +param dnsZoneName string + +@description('Required. The name of the PTR record.') +param name string + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The list of PTR records in the record set.') +param ptrRecords array? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource dnsZone 'Microsoft.Network/dnsZones@2018-05-01' existing = { + name: dnsZoneName +} + +resource PTR 'Microsoft.Network/dnsZones/PTR@2018-05-01' = { + name: name + parent: dnsZone + properties: { + metadata: metadata + PTRRecords: ptrRecords + TTL: ttl + } +} + +resource PTR_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(PTR.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: PTR + } +] + +@description('The name of the deployed PTR record.') +output name string = PTR.name + +@description('The resource ID of the deployed PTR record.') +output resourceId string = PTR.id + +@description('The resource group of the deployed PTR record.') +output resourceGroupName string = resourceGroup().name +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/dns-zone/ptr/main.json b/avm/1.1.0/res/network/dns-zone/ptr/main.json new file mode 100644 index 000000000..d26a76bef --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/ptr/main.json @@ -0,0 +1,215 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3784464033988272421" + }, + "name": "Public DNS Zone PTR record", + "description": "This module deploys a Public DNS Zone PTR record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the PTR record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ptrRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of PTR records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "PTR": { + "type": "Microsoft.Network/dnsZones/PTR", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "PTRRecords": "[parameters('ptrRecords')]", + "TTL": "[parameters('ttl')]" + } + }, + "PTR_roleAssignments": { + "copy": { + "name": "PTR_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/PTR/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/PTR', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "PTR" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed PTR record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed PTR record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/PTR', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed PTR record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-zone/soa/README.md b/avm/1.1.0/res/network/dns-zone/soa/README.md new file mode 100644 index 000000000..22832138f --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/soa/README.md @@ -0,0 +1,192 @@ +# Public DNS Zone SOA record `[Microsoft.Network/dnsZones/SOA]` + +This module deploys a Public DNS Zone SOA record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/dnsZones/SOA` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/SOA) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the SOA record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsZoneName`](#parameter-dnszonename) | string | The name of the parent DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`soaRecord`](#parameter-soarecord) | object | A SOA record. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the SOA record. + +- Required: Yes +- Type: string + +### Parameter: `dnsZoneName` + +The name of the parent DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `soaRecord` + +A SOA record. + +- Required: No +- Type: object + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed SOA record. | +| `resourceGroupName` | string | The resource group of the deployed SOA record. | +| `resourceId` | string | The resource ID of the deployed SOA record. | diff --git a/avm/1.1.0/res/network/dns-zone/soa/main.bicep b/avm/1.1.0/res/network/dns-zone/soa/main.bicep new file mode 100644 index 000000000..cc99e8674 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/soa/main.bicep @@ -0,0 +1,137 @@ +metadata name = 'Public DNS Zone SOA record' +metadata description = 'This module deploys a Public DNS Zone SOA record.' + +@description('Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment.') +param dnsZoneName string + +@description('Required. The name of the SOA record.') +param name string + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. A SOA record.') +param soaRecord object? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource dnsZone 'Microsoft.Network/dnsZones@2018-05-01' existing = { + name: dnsZoneName +} + +resource SOA 'Microsoft.Network/dnsZones/SOA@2018-05-01' = { + name: name + parent: dnsZone + properties: { + metadata: metadata + SOARecord: soaRecord + TTL: ttl + } +} + +resource SOA_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(SOA.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: SOA + } +] + +@description('The name of the deployed SOA record.') +output name string = SOA.name + +@description('The resource ID of the deployed SOA record.') +output resourceId string = SOA.id + +@description('The resource group of the deployed SOA record.') +output resourceGroupName string = resourceGroup().name +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/dns-zone/soa/main.json b/avm/1.1.0/res/network/dns-zone/soa/main.json new file mode 100644 index 000000000..9c375314e --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/soa/main.json @@ -0,0 +1,215 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "13888523145142266910" + }, + "name": "Public DNS Zone SOA record", + "description": "This module deploys a Public DNS Zone SOA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SOA record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "soaRecord": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A SOA record." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "SOA": { + "type": "Microsoft.Network/dnsZones/SOA", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "SOARecord": "[parameters('soaRecord')]", + "TTL": "[parameters('ttl')]" + } + }, + "SOA_roleAssignments": { + "copy": { + "name": "SOA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/SOA/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/SOA', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SOA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SOA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SOA record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/SOA', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SOA record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-zone/srv/README.md b/avm/1.1.0/res/network/dns-zone/srv/README.md new file mode 100644 index 000000000..c733d6957 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/srv/README.md @@ -0,0 +1,192 @@ +# Public DNS Zone SRV record `[Microsoft.Network/dnsZones/SRV]` + +This module deploys a Public DNS Zone SRV record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/dnsZones/SRV` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/SRV) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the SRV record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsZoneName`](#parameter-dnszonename) | string | The name of the parent DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`srvRecords`](#parameter-srvrecords) | array | The list of SRV records in the record set. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the SRV record. + +- Required: Yes +- Type: string + +### Parameter: `dnsZoneName` + +The name of the parent DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `srvRecords` + +The list of SRV records in the record set. + +- Required: No +- Type: array + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed SRV record. | +| `resourceGroupName` | string | The resource group of the deployed SRV record. | +| `resourceId` | string | The resource ID of the deployed SRV record. | diff --git a/avm/1.1.0/res/network/dns-zone/srv/main.bicep b/avm/1.1.0/res/network/dns-zone/srv/main.bicep new file mode 100644 index 000000000..60c3f79aa --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/srv/main.bicep @@ -0,0 +1,136 @@ +metadata name = 'Public DNS Zone SRV record' +metadata description = 'This module deploys a Public DNS Zone SRV record.' + +@description('Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment.') +param dnsZoneName string + +@description('Required. The name of the SRV record.') +param name string + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The list of SRV records in the record set.') +param srvRecords array? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] +resource dnsZone 'Microsoft.Network/dnsZones@2018-05-01' existing = { + name: dnsZoneName +} + +resource SRV 'Microsoft.Network/dnsZones/SRV@2018-05-01' = { + name: name + parent: dnsZone + properties: { + metadata: metadata + SRVRecords: srvRecords + TTL: ttl + } +} + +resource SRV_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(SRV.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: SRV + } +] + +@description('The name of the deployed SRV record.') +output name string = SRV.name + +@description('The resource ID of the deployed SRV record.') +output resourceId string = SRV.id + +@description('The resource group of the deployed SRV record.') +output resourceGroupName string = resourceGroup().name +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/dns-zone/srv/main.json b/avm/1.1.0/res/network/dns-zone/srv/main.json new file mode 100644 index 000000000..39d74aad6 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/srv/main.json @@ -0,0 +1,215 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3361201996898116870" + }, + "name": "Public DNS Zone SRV record", + "description": "This module deploys a Public DNS Zone SRV record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SRV record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "srvRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of SRV records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "SRV": { + "type": "Microsoft.Network/dnsZones/SRV", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "SRVRecords": "[parameters('srvRecords')]", + "TTL": "[parameters('ttl')]" + } + }, + "SRV_roleAssignments": { + "copy": { + "name": "SRV_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/SRV/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/SRV', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SRV" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SRV record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SRV record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/SRV', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SRV record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-zone/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/dns-zone/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..41d0b5823 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.dnszones-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ndzmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001.com' + location: 'global' + } + } +] diff --git a/avm/1.1.0/res/network/dns-zone/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/dns-zone/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..8f0e73eeb --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/tests/e2e/max/dependencies.bicep @@ -0,0 +1,37 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Traffic Manager Profile to create.') +param trafficManagerProfileName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource trafficManagerProfile 'Microsoft.Network/trafficmanagerprofiles@2022-04-01-preview' = { + name: trafficManagerProfileName + location: 'global' + properties: { + trafficRoutingMethod: 'Performance' + maxReturn: 0 + dnsConfig: { + relativeName: trafficManagerProfileName + ttl: 60 + } + monitorConfig: { + protocol: 'HTTP' + port: 80 + path: '/' + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Traffic Manager Profile.') +output trafficManagerProfileResourceId string = trafficManagerProfile.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/dns-zone/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/dns-zone/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..2e88f60af --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/tests/e2e/max/main.test.bicep @@ -0,0 +1,393 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.dnszones-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ndzmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + trafficManagerProfileName: 'dep-${namePrefix}-tmp-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001.com' + location: 'global' + a: [ + { + name: 'A_10.240.4.4' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + aRecords: [ + { + ipv4Address: '10.240.4.4' + } + ] + } + ] + aaaa: [ + { + name: 'AAAA_2001_0db8_85a3_0000_0000_8a2e_0370_7334' + ttl: 3600 + aaaaRecords: [ + { + ipv6Address: '2001:0db8:85a3:0000:0000:8a2e:0370:7334' + } + ] + } + ] + cname: [ + { + name: 'CNAME_test' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + cnameRecord: { + cname: 'test' + } + } + { + name: 'CNAME_aliasRecordSet' + targetResourceId: nestedDependencies.outputs.trafficManagerProfileResourceId + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + mx: [ + { + name: 'MX_contoso' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + mxRecords: [ + { + exchange: 'contoso.com' + preference: 100 + } + ] + } + ] + ptr: [ + { + name: 'PTR_contoso' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + ptrRecords: [ + { + ptrdname: 'contoso.com' + } + ] + } + ] + roleAssignments: [ + { + name: 'a8697438-70e8-4f40-baa4-6e90a57fe1dc' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + soa: [ + { + name: '@' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + soaRecord: { + email: 'azuredns-hostmaster.microsoft.com' + expireTime: 2419200 + host: 'ns1-04.azure-dns.com.' + minimumTtl: 300 + refreshTime: 3600 + retryTime: 300 + serialNumber: 1 + } + } + ] + srv: [ + { + name: 'SRV_contoso' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + srvRecords: [ + { + port: 9332 + priority: 0 + target: 'test.contoso.com' + weight: 0 + } + ] + } + ] + txt: [ + { + name: 'TXT_test' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + txtRecords: [ + { + value: [ + 'test' + ] + } + ] + } + ] + caa: [ + { + name: 'CAA_test' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + caaRecords: [ + { + flags: 0 + tag: 'issue' + value: 'ca.contoso.com' + } + ] + } + ] + ns: [ + { + name: 'NS_test' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + nsRecords: [ + { + nsdname: 'ns.contoso.com' + } + ] + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/dns-zone/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/dns-zone/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..8f0e73eeb --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,37 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Traffic Manager Profile to create.') +param trafficManagerProfileName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource trafficManagerProfile 'Microsoft.Network/trafficmanagerprofiles@2022-04-01-preview' = { + name: trafficManagerProfileName + location: 'global' + properties: { + trafficRoutingMethod: 'Performance' + maxReturn: 0 + dnsConfig: { + relativeName: trafficManagerProfileName + ttl: 60 + } + monitorConfig: { + protocol: 'HTTP' + port: 80 + path: '/' + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Traffic Manager Profile.') +output trafficManagerProfileResourceId string = trafficManagerProfile.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/dns-zone/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/dns-zone/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..fa2386963 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,67 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.dnszones-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ndzwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + trafficManagerProfileName: 'dep-${namePrefix}-tmp-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001.com' + location: 'global' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/dns-zone/txt/README.md b/avm/1.1.0/res/network/dns-zone/txt/README.md new file mode 100644 index 000000000..35f4be5c4 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/txt/README.md @@ -0,0 +1,192 @@ +# Public DNS Zone TXT record `[Microsoft.Network/dnsZones/TXT]` + +This module deploys a Public DNS Zone TXT record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/dnsZones/TXT` | [2018-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-05-01/dnsZones/TXT) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the TXT record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dnsZoneName`](#parameter-dnszonename) | string | The name of the parent DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | +| [`txtRecords`](#parameter-txtrecords) | array | The list of TXT records in the record set. | + +### Parameter: `name` + +The name of the TXT record. + +- Required: Yes +- Type: string + +### Parameter: `dnsZoneName` + +The name of the parent DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +### Parameter: `txtRecords` + +The list of TXT records in the record set. + +- Required: No +- Type: array + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed TXT record. | +| `resourceGroupName` | string | The resource group of the deployed TXT record. | +| `resourceId` | string | The resource ID of the deployed TXT record. | diff --git a/avm/1.1.0/res/network/dns-zone/txt/main.bicep b/avm/1.1.0/res/network/dns-zone/txt/main.bicep new file mode 100644 index 000000000..5a8dd4a44 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/txt/main.bicep @@ -0,0 +1,136 @@ +metadata name = 'Public DNS Zone TXT record' +metadata description = 'This module deploys a Public DNS Zone TXT record.' + +@description('Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment.') +param dnsZoneName string + +@description('Required. The name of the TXT record.') +param name string + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. The list of TXT records in the record set.') +param txtRecords array? + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] +resource dnsZone 'Microsoft.Network/dnsZones@2018-05-01' existing = { + name: dnsZoneName +} + +resource TXT 'Microsoft.Network/dnsZones/TXT@2018-05-01' = { + name: name + parent: dnsZone + properties: { + metadata: metadata + TTL: ttl + TXTRecords: txtRecords + } +} + +resource TXT_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(TXT.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: TXT + } +] + +@description('The name of the deployed TXT record.') +output name string = TXT.name + +@description('The resource ID of the deployed TXT record.') +output resourceId string = TXT.id + +@description('The resource group of the deployed TXT record.') +output resourceGroupName string = resourceGroup().name +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/dns-zone/txt/main.json b/avm/1.1.0/res/network/dns-zone/txt/main.json new file mode 100644 index 000000000..7f015bc1b --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/txt/main.json @@ -0,0 +1,215 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "6318820825027351839" + }, + "name": "Public DNS Zone TXT record", + "description": "This module deploys a Public DNS Zone TXT record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "dnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the TXT record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "txtRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of TXT records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "dnsZone": { + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[parameters('dnsZoneName')]" + }, + "TXT": { + "type": "Microsoft.Network/dnsZones/TXT", + "apiVersion": "2018-05-01", + "name": "[format('{0}/{1}', parameters('dnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "TTL": "[parameters('ttl')]", + "TXTRecords": "[parameters('txtRecords')]" + } + }, + "TXT_roleAssignments": { + "copy": { + "name": "TXT_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}/TXT/{1}', parameters('dnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/dnsZones/TXT', parameters('dnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "TXT" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed TXT record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed TXT record." + }, + "value": "[resourceId('Microsoft.Network/dnsZones/TXT', parameters('dnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed TXT record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/dns-zone/version.json b/avm/1.1.0/res/network/dns-zone/version.json new file mode 100644 index 000000000..ea4f3b6e6 --- /dev/null +++ b/avm/1.1.0/res/network/dns-zone/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/express-route-circuit/README.md b/avm/1.1.0/res/network/express-route-circuit/README.md new file mode 100644 index 000000000..c8972d64f --- /dev/null +++ b/avm/1.1.0/res/network/express-route-circuit/README.md @@ -0,0 +1,1030 @@ +# ExpressRoute Circuits `[Microsoft.Network/expressRouteCircuits]` + +This module deploys an Express Route Circuit. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/expressRouteCircuits` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/expressRouteCircuits) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/express-route-circuit:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit:' = { + name: 'expressRouteCircuitDeployment' + params: { + // Required parameters + bandwidthInMbps: 50 + name: 'nercmin001' + peeringLocation: 'Amsterdam' + serviceProviderName: 'Equinix' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "bandwidthInMbps": { + "value": 50 + }, + "name": { + "value": "nercmin001" + }, + "peeringLocation": { + "value": "Amsterdam" + }, + "serviceProviderName": { + "value": "Equinix" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-circuit:' + +// Required parameters +param bandwidthInMbps = 50 +param name = 'nercmin001' +param peeringLocation = 'Amsterdam' +param serviceProviderName = 'Equinix' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit:' = { + name: 'expressRouteCircuitDeployment' + params: { + // Required parameters + bandwidthInMbps: 50 + name: 'nercmax001' + peeringLocation: 'Amsterdam' + serviceProviderName: 'Equinix' + // Non-required parameters + allowClassicOperations: true + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'd7aa3dfa-6ba6-4ed8-b561-2164fbb1327e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + skuFamily: 'MeteredData' + skuTier: 'Standard' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "bandwidthInMbps": { + "value": 50 + }, + "name": { + "value": "nercmax001" + }, + "peeringLocation": { + "value": "Amsterdam" + }, + "serviceProviderName": { + "value": "Equinix" + }, + // Non-required parameters + "allowClassicOperations": { + "value": true + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "d7aa3dfa-6ba6-4ed8-b561-2164fbb1327e", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "skuFamily": { + "value": "MeteredData" + }, + "skuTier": { + "value": "Standard" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-circuit:' + +// Required parameters +param bandwidthInMbps = 50 +param name = 'nercmax001' +param peeringLocation = 'Amsterdam' +param serviceProviderName = 'Equinix' +// Non-required parameters +param allowClassicOperations = true +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'd7aa3dfa-6ba6-4ed8-b561-2164fbb1327e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuFamily = 'MeteredData' +param skuTier = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit:' = { + name: 'expressRouteCircuitDeployment' + params: { + // Required parameters + bandwidthInMbps: 50 + name: 'nercwaf001' + peeringLocation: 'Amsterdam' + serviceProviderName: 'Equinix' + // Non-required parameters + allowClassicOperations: true + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + skuFamily: 'MeteredData' + skuTier: 'Standard' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "bandwidthInMbps": { + "value": 50 + }, + "name": { + "value": "nercwaf001" + }, + "peeringLocation": { + "value": "Amsterdam" + }, + "serviceProviderName": { + "value": "Equinix" + }, + // Non-required parameters + "allowClassicOperations": { + "value": true + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "skuFamily": { + "value": "MeteredData" + }, + "skuTier": { + "value": "Standard" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-circuit:' + +// Required parameters +param bandwidthInMbps = 50 +param name = 'nercwaf001' +param peeringLocation = 'Amsterdam' +param serviceProviderName = 'Equinix' +// Non-required parameters +param allowClassicOperations = true +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param skuFamily = 'MeteredData' +param skuTier = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`bandwidthInMbps`](#parameter-bandwidthinmbps) | int | This is the bandwidth in Mbps of the circuit being created. It must exactly match one of the available bandwidth offers List ExpressRoute Service Providers API call. | +| [`name`](#parameter-name) | string | This is the name of the ExpressRoute circuit. | +| [`peeringLocation`](#parameter-peeringlocation) | string | This is the name of the peering location and not the ARM resource location. It must exactly match one of the available peering locations from List ExpressRoute Service Providers API call. | +| [`serviceProviderName`](#parameter-serviceprovidername) | string | This is the name of the ExpressRoute Service Provider. It must exactly match one of the Service Providers from List ExpressRoute Service Providers API call. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowClassicOperations`](#parameter-allowclassicoperations) | bool | Allow classic operations. You can connect to virtual networks in the classic deployment model by setting allowClassicOperations to true. | +| [`authorizationNames`](#parameter-authorizationnames) | array | List of names for ExpressRoute circuit authorizations to create. To fetch the `authorizationKey` for the authorization, use the `existing` resource reference for `Microsoft.Network/expressRouteCircuits/authorizations`. | +| [`bandwidthInGbps`](#parameter-bandwidthingbps) | int | The bandwidth of the circuit when the circuit is provisioned on an ExpressRoutePort resource. Available when configuring Express Route Direct. Default value of 0 will set the property to null. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`expressRoutePortResourceId`](#parameter-expressrouteportresourceid) | string | The reference to the ExpressRoutePort resource when the circuit is provisioned on an ExpressRoutePort resource. Available when configuring Express Route Direct. | +| [`globalReachEnabled`](#parameter-globalreachenabled) | bool | Flag denoting global reach status. To enable ExpressRoute Global Reach between different geopolitical regions, your circuits must be Premium SKU. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`peerASN`](#parameter-peerasn) | int | The autonomous system number of the customer/connectivity provider. | +| [`peering`](#parameter-peering) | bool | Enabled BGP peering type for the Circuit. | +| [`peeringType`](#parameter-peeringtype) | string | BGP peering type for the Circuit. Choose from AzurePrivatePeering, AzurePublicPeering or MicrosoftPeering. | +| [`primaryPeerAddressPrefix`](#parameter-primarypeeraddressprefix) | string | A /30 subnet used to configure IP addresses for interfaces on Link1. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`secondaryPeerAddressPrefix`](#parameter-secondarypeeraddressprefix) | string | A /30 subnet used to configure IP addresses for interfaces on Link2. | +| [`sharedKey`](#parameter-sharedkey) | securestring | The shared key for peering configuration. Router does MD5 hash comparison to validate the packets sent by BGP connection. This parameter is optional and can be removed from peering configuration if not required. | +| [`skuFamily`](#parameter-skufamily) | string | Chosen SKU family of ExpressRoute circuit. Choose from MeteredData or UnlimitedData SKU families. | +| [`skuTier`](#parameter-skutier) | string | Chosen SKU Tier of ExpressRoute circuit. Choose from Local, Premium or Standard SKU tiers. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`vlanId`](#parameter-vlanid) | int | Specifies the identifier that is used to identify the customer. | + +### Parameter: `bandwidthInMbps` + +This is the bandwidth in Mbps of the circuit being created. It must exactly match one of the available bandwidth offers List ExpressRoute Service Providers API call. + +- Required: Yes +- Type: int + +### Parameter: `name` + +This is the name of the ExpressRoute circuit. + +- Required: Yes +- Type: string + +### Parameter: `peeringLocation` + +This is the name of the peering location and not the ARM resource location. It must exactly match one of the available peering locations from List ExpressRoute Service Providers API call. + +- Required: Yes +- Type: string + +### Parameter: `serviceProviderName` + +This is the name of the ExpressRoute Service Provider. It must exactly match one of the Service Providers from List ExpressRoute Service Providers API call. + +- Required: Yes +- Type: string + +### Parameter: `allowClassicOperations` + +Allow classic operations. You can connect to virtual networks in the classic deployment model by setting allowClassicOperations to true. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `authorizationNames` + +List of names for ExpressRoute circuit authorizations to create. To fetch the `authorizationKey` for the authorization, use the `existing` resource reference for `Microsoft.Network/expressRouteCircuits/authorizations`. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `bandwidthInGbps` + +The bandwidth of the circuit when the circuit is provisioned on an ExpressRoutePort resource. Available when configuring Express Route Direct. Default value of 0 will set the property to null. + +- Required: No +- Type: int +- Default: `0` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `expressRoutePortResourceId` + +The reference to the ExpressRoutePort resource when the circuit is provisioned on an ExpressRoutePort resource. Available when configuring Express Route Direct. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `globalReachEnabled` + +Flag denoting global reach status. To enable ExpressRoute Global Reach between different geopolitical regions, your circuits must be Premium SKU. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `peerASN` + +The autonomous system number of the customer/connectivity provider. + +- Required: No +- Type: int +- Default: `0` + +### Parameter: `peering` + +Enabled BGP peering type for the Circuit. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `peeringType` + +BGP peering type for the Circuit. Choose from AzurePrivatePeering, AzurePublicPeering or MicrosoftPeering. + +- Required: No +- Type: string +- Default: `'AzurePrivatePeering'` +- Allowed: + ```Bicep + [ + 'AzurePrivatePeering' + 'MicrosoftPeering' + ] + ``` + +### Parameter: `primaryPeerAddressPrefix` + +A /30 subnet used to configure IP addresses for interfaces on Link1. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `secondaryPeerAddressPrefix` + +A /30 subnet used to configure IP addresses for interfaces on Link2. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `sharedKey` + +The shared key for peering configuration. Router does MD5 hash comparison to validate the packets sent by BGP connection. This parameter is optional and can be removed from peering configuration if not required. + +- Required: No +- Type: securestring +- Default: `''` + +### Parameter: `skuFamily` + +Chosen SKU family of ExpressRoute circuit. Choose from MeteredData or UnlimitedData SKU families. + +- Required: No +- Type: string +- Default: `'MeteredData'` +- Allowed: + ```Bicep + [ + 'MeteredData' + 'UnlimitedData' + ] + ``` + +### Parameter: `skuTier` + +Chosen SKU Tier of ExpressRoute circuit. Choose from Local, Premium or Standard SKU tiers. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Local' + 'Premium' + 'Standard' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `vlanId` + +Specifies the identifier that is used to identify the customer. + +- Required: No +- Type: int +- Default: `0` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of express route curcuit. | +| `resourceGroupName` | string | The resource group the express route curcuit was deployed into. | +| `resourceId` | string | The resource ID of express route curcuit. | +| `serviceKey` | string | The service key of the express route circuit. | +| `serviceProviderProvisioningState` | string | The service provider provisioning state of the express route circuit. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/express-route-circuit/main.bicep b/avm/1.1.0/res/network/express-route-circuit/main.bicep new file mode 100644 index 000000000..6e0332ae4 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-circuit/main.bicep @@ -0,0 +1,342 @@ +metadata name = 'ExpressRoute Circuits' +metadata description = 'This module deploys an Express Route Circuit.' + +@description('Required. This is the name of the ExpressRoute circuit.') +param name string + +@description('Required. This is the name of the ExpressRoute Service Provider. It must exactly match one of the Service Providers from List ExpressRoute Service Providers API call.') +param serviceProviderName string + +@description('Required. This is the name of the peering location and not the ARM resource location. It must exactly match one of the available peering locations from List ExpressRoute Service Providers API call.') +param peeringLocation string + +@description('Required. This is the bandwidth in Mbps of the circuit being created. It must exactly match one of the available bandwidth offers List ExpressRoute Service Providers API call.') +param bandwidthInMbps int + +@description('Optional. Chosen SKU Tier of ExpressRoute circuit. Choose from Local, Premium or Standard SKU tiers.') +@allowed([ + 'Local' + 'Standard' + 'Premium' +]) +param skuTier string = 'Standard' + +@description('Optional. Chosen SKU family of ExpressRoute circuit. Choose from MeteredData or UnlimitedData SKU families.') +@allowed([ + 'MeteredData' + 'UnlimitedData' +]) +param skuFamily string = 'MeteredData' + +@description('Optional. Enabled BGP peering type for the Circuit.') +param peering bool = false + +@description('Optional. BGP peering type for the Circuit. Choose from AzurePrivatePeering, AzurePublicPeering or MicrosoftPeering.') +@allowed([ + 'AzurePrivatePeering' + 'MicrosoftPeering' +]) +param peeringType string = 'AzurePrivatePeering' + +@secure() +@description('Optional. The shared key for peering configuration. Router does MD5 hash comparison to validate the packets sent by BGP connection. This parameter is optional and can be removed from peering configuration if not required.') +param sharedKey string = '' + +@description('Optional. The autonomous system number of the customer/connectivity provider.') +param peerASN int = 0 + +@description('Optional. A /30 subnet used to configure IP addresses for interfaces on Link1.') +param primaryPeerAddressPrefix string = '' + +@description('Optional. A /30 subnet used to configure IP addresses for interfaces on Link2.') +param secondaryPeerAddressPrefix string = '' + +@description('Optional. Specifies the identifier that is used to identify the customer.') +param vlanId int = 0 + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Allow classic operations. You can connect to virtual networks in the classic deployment model by setting allowClassicOperations to true.') +param allowClassicOperations bool = false + +@description('Optional. List of names for ExpressRoute circuit authorizations to create. To fetch the `authorizationKey` for the authorization, use the `existing` resource reference for `Microsoft.Network/expressRouteCircuits/authorizations`.') +param authorizationNames string[] = [] + +@description('Optional. The bandwidth of the circuit when the circuit is provisioned on an ExpressRoutePort resource. Available when configuring Express Route Direct. Default value of 0 will set the property to null.') +param bandwidthInGbps int = 0 + +@description('Optional. The reference to the ExpressRoutePort resource when the circuit is provisioned on an ExpressRoutePort resource. Available when configuring Express Route Direct.') +param expressRoutePortResourceId string = '' + +@description('Optional. Flag denoting global reach status. To enable ExpressRoute Global Reach between different geopolitical regions, your circuits must be Premium SKU.') +param globalReachEnabled bool = false + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-expressroutecircuit.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource expressRouteCircuit 'Microsoft.Network/expressRouteCircuits@2023-04-01' = { + name: name + location: location + tags: tags + sku: { + name: '${skuTier}_${skuFamily}' + tier: skuTier + family: skuTier == 'Local' ? 'UnlimitedData' : skuFamily + } + properties: { + allowClassicOperations: allowClassicOperations + authorizations: [ + for authorizationName in authorizationNames: { + name: authorizationName + } + ] + globalReachEnabled: globalReachEnabled + bandwidthInGbps: bandwidthInGbps != 0 ? bandwidthInGbps : null + expressRoutePort: !empty(expressRoutePortResourceId) + ? { + id: expressRoutePortResourceId + } + : null + serviceProviderProperties: { + serviceProviderName: serviceProviderName + peeringLocation: peeringLocation + bandwidthInMbps: bandwidthInMbps + } + peerings: peering + ? [ + { + name: peeringType + properties: { + peeringType: peeringType + sharedKey: sharedKey + peerASN: peerASN + primaryPeerAddressPrefix: primaryPeerAddressPrefix + secondaryPeerAddressPrefix: secondaryPeerAddressPrefix + vlanId: vlanId + } + } + ] + : null + } +} + +resource expressRouteCircuit_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: expressRouteCircuit +} + +resource expressRouteCircuit_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: expressRouteCircuit + } +] + +resource expressRouteCircuit_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + expressRouteCircuit.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: expressRouteCircuit + } +] + +@description('The resource ID of express route curcuit.') +output resourceId string = expressRouteCircuit.id + +@description('The resource group the express route curcuit was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of express route curcuit.') +output name string = expressRouteCircuit.name + +@description('The service key of the express route circuit.') +output serviceKey string = expressRouteCircuit.properties.serviceKey + +@description('The service provider provisioning state of the express route circuit.') +output serviceProviderProvisioningState string = expressRouteCircuit.properties.serviceProviderProvisioningState + +@description('The location the resource was deployed into.') +output location string = expressRouteCircuit.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/express-route-circuit/main.json b/avm/1.1.0/res/network/express-route-circuit/main.json new file mode 100644 index 000000000..9029bd322 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-circuit/main.json @@ -0,0 +1,606 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "8776591928362518786" + }, + "name": "ExpressRoute Circuits", + "description": "This module deploys an Express Route Circuit." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. This is the name of the ExpressRoute circuit." + } + }, + "serviceProviderName": { + "type": "string", + "metadata": { + "description": "Required. This is the name of the ExpressRoute Service Provider. It must exactly match one of the Service Providers from List ExpressRoute Service Providers API call." + } + }, + "peeringLocation": { + "type": "string", + "metadata": { + "description": "Required. This is the name of the peering location and not the ARM resource location. It must exactly match one of the available peering locations from List ExpressRoute Service Providers API call." + } + }, + "bandwidthInMbps": { + "type": "int", + "metadata": { + "description": "Required. This is the bandwidth in Mbps of the circuit being created. It must exactly match one of the available bandwidth offers List ExpressRoute Service Providers API call." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Local", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Chosen SKU Tier of ExpressRoute circuit. Choose from Local, Premium or Standard SKU tiers." + } + }, + "skuFamily": { + "type": "string", + "defaultValue": "MeteredData", + "allowedValues": [ + "MeteredData", + "UnlimitedData" + ], + "metadata": { + "description": "Optional. Chosen SKU family of ExpressRoute circuit. Choose from MeteredData or UnlimitedData SKU families." + } + }, + "peering": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enabled BGP peering type for the Circuit." + } + }, + "peeringType": { + "type": "string", + "defaultValue": "AzurePrivatePeering", + "allowedValues": [ + "AzurePrivatePeering", + "MicrosoftPeering" + ], + "metadata": { + "description": "Optional. BGP peering type for the Circuit. Choose from AzurePrivatePeering, AzurePublicPeering or MicrosoftPeering." + } + }, + "sharedKey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. The shared key for peering configuration. Router does MD5 hash comparison to validate the packets sent by BGP connection. This parameter is optional and can be removed from peering configuration if not required." + } + }, + "peerASN": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The autonomous system number of the customer/connectivity provider." + } + }, + "primaryPeerAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. A /30 subnet used to configure IP addresses for interfaces on Link1." + } + }, + "secondaryPeerAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. A /30 subnet used to configure IP addresses for interfaces on Link2." + } + }, + "vlanId": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Specifies the identifier that is used to identify the customer." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "allowClassicOperations": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Allow classic operations. You can connect to virtual networks in the classic deployment model by setting allowClassicOperations to true." + } + }, + "authorizationNames": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. List of names for ExpressRoute circuit authorizations to create. To fetch the `authorizationKey` for the authorization, use the `existing` resource reference for `Microsoft.Network/expressRouteCircuits/authorizations`." + } + }, + "bandwidthInGbps": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The bandwidth of the circuit when the circuit is provisioned on an ExpressRoutePort resource. Available when configuring Express Route Direct. Default value of 0 will set the property to null." + } + }, + "expressRoutePortResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The reference to the ExpressRoutePort resource when the circuit is provisioned on an ExpressRoutePort resource. Available when configuring Express Route Direct." + } + }, + "globalReachEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag denoting global reach status. To enable ExpressRoute Global Reach between different geopolitical regions, your circuits must be Premium SKU." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-expressroutecircuit.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "expressRouteCircuit": { + "type": "Microsoft.Network/expressRouteCircuits", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[format('{0}_{1}', parameters('skuTier'), parameters('skuFamily'))]", + "tier": "[parameters('skuTier')]", + "family": "[if(equals(parameters('skuTier'), 'Local'), 'UnlimitedData', parameters('skuFamily'))]" + }, + "properties": { + "copy": [ + { + "name": "authorizations", + "count": "[length(parameters('authorizationNames'))]", + "input": { + "name": "[parameters('authorizationNames')[copyIndex('authorizations')]]" + } + } + ], + "allowClassicOperations": "[parameters('allowClassicOperations')]", + "globalReachEnabled": "[parameters('globalReachEnabled')]", + "bandwidthInGbps": "[if(not(equals(parameters('bandwidthInGbps'), 0)), parameters('bandwidthInGbps'), null())]", + "expressRoutePort": "[if(not(empty(parameters('expressRoutePortResourceId'))), createObject('id', parameters('expressRoutePortResourceId')), null())]", + "serviceProviderProperties": { + "serviceProviderName": "[parameters('serviceProviderName')]", + "peeringLocation": "[parameters('peeringLocation')]", + "bandwidthInMbps": "[parameters('bandwidthInMbps')]" + }, + "peerings": "[if(parameters('peering'), createArray(createObject('name', parameters('peeringType'), 'properties', createObject('peeringType', parameters('peeringType'), 'sharedKey', parameters('sharedKey'), 'peerASN', parameters('peerASN'), 'primaryPeerAddressPrefix', parameters('primaryPeerAddressPrefix'), 'secondaryPeerAddressPrefix', parameters('secondaryPeerAddressPrefix'), 'vlanId', parameters('vlanId')))), null())]" + } + }, + "expressRouteCircuit_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/expressRouteCircuits/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "expressRouteCircuit" + ] + }, + "expressRouteCircuit_diagnosticSettings": { + "copy": { + "name": "expressRouteCircuit_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/expressRouteCircuits/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "expressRouteCircuit" + ] + }, + "expressRouteCircuit_roleAssignments": { + "copy": { + "name": "expressRouteCircuit_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/expressRouteCircuits/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/expressRouteCircuits', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "expressRouteCircuit" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of express route curcuit." + }, + "value": "[resourceId('Microsoft.Network/expressRouteCircuits', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the express route curcuit was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of express route curcuit." + }, + "value": "[parameters('name')]" + }, + "serviceKey": { + "type": "string", + "metadata": { + "description": "The service key of the express route circuit." + }, + "value": "[reference('expressRouteCircuit').serviceKey]" + }, + "serviceProviderProvisioningState": { + "type": "string", + "metadata": { + "description": "The service provider provisioning state of the express route circuit." + }, + "value": "[reference('expressRouteCircuit').serviceProviderProvisioningState]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('expressRouteCircuit', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/express-route-circuit/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/express-route-circuit/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..8d241b905 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-circuit/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,51 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.expressroutecircuits-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nercmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + bandwidthInMbps: 50 + peeringLocation: 'Amsterdam' + serviceProviderName: 'Equinix' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/network/express-route-circuit/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/express-route-circuit/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-circuit/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/express-route-circuit/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/express-route-circuit/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..eaee710ac --- /dev/null +++ b/avm/1.1.0/res/network/express-route-circuit/tests/e2e/max/main.test.bicep @@ -0,0 +1,122 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.expressroutecircuits-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nercmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + bandwidthInMbps: 50 + peeringLocation: 'Amsterdam' + serviceProviderName: 'Equinix' + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'd7aa3dfa-6ba6-4ed8-b561-2164fbb1327e' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + skuFamily: 'MeteredData' + skuTier: 'Standard' + allowClassicOperations: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [nestedDependencies] + } +] diff --git a/avm/1.1.0/res/network/express-route-circuit/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/express-route-circuit/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-circuit/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/express-route-circuit/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/express-route-circuit/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..75c6fe75a --- /dev/null +++ b/avm/1.1.0/res/network/express-route-circuit/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,99 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.expressroutecircuits-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nercwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + bandwidthInMbps: 50 + peeringLocation: 'Amsterdam' + serviceProviderName: 'Equinix' + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + skuFamily: 'MeteredData' + skuTier: 'Standard' + allowClassicOperations: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/express-route-circuit/version.json b/avm/1.1.0/res/network/express-route-circuit/version.json new file mode 100644 index 000000000..13669e660 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-circuit/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.4", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/express-route-gateway/README.md b/avm/1.1.0/res/network/express-route-gateway/README.md new file mode 100644 index 000000000..27da9983b --- /dev/null +++ b/avm/1.1.0/res/network/express-route-gateway/README.md @@ -0,0 +1,618 @@ +# Express Route Gateways `[Microsoft.Network/expressRouteGateways]` + +This module deploys an Express Route Gateway. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/expressRouteGateways` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/expressRouteGateways) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/express-route-gateway:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module expressRouteGateway 'br/public:avm/res/network/express-route-gateway:' = { + name: 'expressRouteGatewayDeployment' + params: { + // Required parameters + name: 'nergmin001' + virtualHubId: '' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nergmin001" + }, + "virtualHubId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-gateway:' + +// Required parameters +param name = 'nergmin001' +param virtualHubId = '' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module expressRouteGateway 'br/public:avm/res/network/express-route-gateway:' = { + name: 'expressRouteGatewayDeployment' + params: { + // Required parameters + name: 'nergmax001' + virtualHubId: '' + // Non-required parameters + autoScaleConfigurationBoundsMax: 3 + autoScaleConfigurationBoundsMin: 2 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '78ad6c3f-7f77-4d26-9576-dbd947241ef0' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + hello: 'world' + 'hidden-title': 'This is visible in the resource name' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nergmax001" + }, + "virtualHubId": { + "value": "" + }, + // Non-required parameters + "autoScaleConfigurationBoundsMax": { + "value": 3 + }, + "autoScaleConfigurationBoundsMin": { + "value": 2 + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "78ad6c3f-7f77-4d26-9576-dbd947241ef0", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "hello": "world", + "hidden-title": "This is visible in the resource name" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-gateway:' + +// Required parameters +param name = 'nergmax001' +param virtualHubId = '' +// Non-required parameters +param autoScaleConfigurationBoundsMax = 3 +param autoScaleConfigurationBoundsMin = 2 +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '78ad6c3f-7f77-4d26-9576-dbd947241ef0' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + hello: 'world' + 'hidden-title': 'This is visible in the resource name' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module expressRouteGateway 'br/public:avm/res/network/express-route-gateway:' = { + name: 'expressRouteGatewayDeployment' + params: { + // Required parameters + name: 'nergwaf001' + virtualHubId: '' + // Non-required parameters + autoScaleConfigurationBoundsMax: 3 + autoScaleConfigurationBoundsMin: 2 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + hello: 'world' + 'hidden-title': 'This is visible in the resource name' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nergwaf001" + }, + "virtualHubId": { + "value": "" + }, + // Non-required parameters + "autoScaleConfigurationBoundsMax": { + "value": 3 + }, + "autoScaleConfigurationBoundsMin": { + "value": 2 + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "tags": { + "value": { + "hello": "world", + "hidden-title": "This is visible in the resource name" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-gateway:' + +// Required parameters +param name = 'nergwaf001' +param virtualHubId = '' +// Non-required parameters +param autoScaleConfigurationBoundsMax = 3 +param autoScaleConfigurationBoundsMin = 2 +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + hello: 'world' + 'hidden-title': 'This is visible in the resource name' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Express Route Gateway. | +| [`virtualHubId`](#parameter-virtualhubid) | string | Resource ID of the Virtual Wan Hub. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowNonVirtualWanTraffic`](#parameter-allownonvirtualwantraffic) | bool | Configures this gateway to accept traffic from non Virtual WAN networks. | +| [`autoScaleConfigurationBoundsMax`](#parameter-autoscaleconfigurationboundsmax) | int | Maximum number of scale units deployed for ExpressRoute gateway. | +| [`autoScaleConfigurationBoundsMin`](#parameter-autoscaleconfigurationboundsmin) | int | Minimum number of scale units deployed for ExpressRoute gateway. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`expressRouteConnections`](#parameter-expressrouteconnections) | array | List of ExpressRoute connections to the ExpressRoute gateway. **Note:** This parameter will overwrite existing connections, including deleting any that are not provided. This is by-design behavior of the resource provider. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the Firewall policy resource. | + +### Parameter: `name` + +Name of the Express Route Gateway. + +- Required: Yes +- Type: string + +### Parameter: `virtualHubId` + +Resource ID of the Virtual Wan Hub. + +- Required: Yes +- Type: string + +### Parameter: `allowNonVirtualWanTraffic` + +Configures this gateway to accept traffic from non Virtual WAN networks. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `autoScaleConfigurationBoundsMax` + +Maximum number of scale units deployed for ExpressRoute gateway. + +- Required: No +- Type: int +- Default: `2` + +### Parameter: `autoScaleConfigurationBoundsMin` + +Minimum number of scale units deployed for ExpressRoute gateway. + +- Required: No +- Type: int +- Default: `2` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `expressRouteConnections` + +List of ExpressRoute connections to the ExpressRoute gateway. **Note:** This parameter will overwrite existing connections, including deleting any that are not provided. This is by-design behavior of the resource provider. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the Firewall policy resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the ExpressRoute Gateway. | +| `resourceGroupName` | string | The resource group of the ExpressRoute Gateway was deployed into. | +| `resourceId` | string | The resource ID of the ExpressRoute Gateway. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/express-route-gateway/main.bicep b/avm/1.1.0/res/network/express-route-gateway/main.bicep new file mode 100644 index 000000000..279ce19d4 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-gateway/main.bicep @@ -0,0 +1,183 @@ +metadata name = 'Express Route Gateways' +metadata description = 'This module deploys an Express Route Gateway.' + +@description('Required. Name of the Express Route Gateway.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the Firewall policy resource.') +param tags object? + +@description('Optional. Configures this gateway to accept traffic from non Virtual WAN networks.') +param allowNonVirtualWanTraffic bool = false + +@description('Optional. Maximum number of scale units deployed for ExpressRoute gateway.') +param autoScaleConfigurationBoundsMax int = 2 + +@description('Optional. Minimum number of scale units deployed for ExpressRoute gateway.') +param autoScaleConfigurationBoundsMin int = 2 + +@description('Optional. List of ExpressRoute connections to the ExpressRoute gateway. **Note:** This parameter will overwrite existing connections, including deleting any that are not provided. This is by-design behavior of the resource provider.') +param expressRouteConnections array = [] + +@description('Required. Resource ID of the Virtual Wan Hub.') +param virtualHubId string + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. The lock settings of the service.') +param lock lockType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-expressroutegateway.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource expressRouteGateway 'Microsoft.Network/expressRouteGateways@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + allowNonVirtualWanTraffic: allowNonVirtualWanTraffic + autoScaleConfiguration: { + bounds: { + max: autoScaleConfigurationBoundsMax + min: autoScaleConfigurationBoundsMin + } + } + expressRouteConnections: expressRouteConnections + virtualHub: { + id: virtualHubId + } + } +} + +resource expressRouteGateway_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: expressRouteGateway +} + +resource expressRouteGateway_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + expressRouteGateway.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: expressRouteGateway + } +] + +@description('The resource ID of the ExpressRoute Gateway.') +output resourceId string = expressRouteGateway.id + +@description('The resource group of the ExpressRoute Gateway was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the ExpressRoute Gateway.') +output name string = expressRouteGateway.name + +@description('The location the resource was deployed into.') +output location string = expressRouteGateway.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/express-route-gateway/main.json b/avm/1.1.0/res/network/express-route-gateway/main.json new file mode 100644 index 000000000..1bea4cd74 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-gateway/main.json @@ -0,0 +1,314 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "663228811603596945" + }, + "name": "Express Route Gateways", + "description": "This module deploys an Express Route Gateway." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Express Route Gateway." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the Firewall policy resource." + } + }, + "allowNonVirtualWanTraffic": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Configures this gateway to accept traffic from non Virtual WAN networks." + } + }, + "autoScaleConfigurationBoundsMax": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Optional. Maximum number of scale units deployed for ExpressRoute gateway." + } + }, + "autoScaleConfigurationBoundsMin": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Optional. Minimum number of scale units deployed for ExpressRoute gateway." + } + }, + "expressRouteConnections": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of ExpressRoute connections to the ExpressRoute gateway. **Note:** This parameter will overwrite existing connections, including deleting any that are not provided. This is by-design behavior of the resource provider." + } + }, + "virtualHubId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the Virtual Wan Hub." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-expressroutegateway.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "expressRouteGateway": { + "type": "Microsoft.Network/expressRouteGateways", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "allowNonVirtualWanTraffic": "[parameters('allowNonVirtualWanTraffic')]", + "autoScaleConfiguration": { + "bounds": { + "max": "[parameters('autoScaleConfigurationBoundsMax')]", + "min": "[parameters('autoScaleConfigurationBoundsMin')]" + } + }, + "expressRouteConnections": "[parameters('expressRouteConnections')]", + "virtualHub": { + "id": "[parameters('virtualHubId')]" + } + } + }, + "expressRouteGateway_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/expressRouteGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "expressRouteGateway" + ] + }, + "expressRouteGateway_roleAssignments": { + "copy": { + "name": "expressRouteGateway_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/expressRouteGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/expressRouteGateways', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "expressRouteGateway" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the ExpressRoute Gateway." + }, + "value": "[resourceId('Microsoft.Network/expressRouteGateways', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the ExpressRoute Gateway was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the ExpressRoute Gateway." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('expressRouteGateway', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/express-route-gateway/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/express-route-gateway/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..0e84400a0 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-gateway/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,27 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Required. The name of the virtual Hub to create.') +param virtualHubName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +resource virtualHub 'Microsoft.Network/virtualHubs@2023-04-01' = { + name: virtualHubName + location: location + properties: { + addressPrefix: '10.0.0.0/16' + virtualWan: { + id: virtualWan.id + } + } +} + +@description('The resource ID of the created Virtual Hub.') +output virtualHubResourceId string = virtualHub.id diff --git a/avm/1.1.0/res/network/express-route-gateway/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/express-route-gateway/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..7e3baf6a4 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-gateway/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,58 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.expressRouteGateway-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nergmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vwan-${serviceShort}' + virtualHubName: 'dep-${namePrefix}-hub-${serviceShort}' + location: resourceLocation + } +} +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + virtualHubId: nestedDependencies.outputs.virtualHubResourceId + } + dependsOn: [ + nestedDependencies + ] +} diff --git a/avm/1.1.0/res/network/express-route-gateway/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/express-route-gateway/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..acaa3b4df --- /dev/null +++ b/avm/1.1.0/res/network/express-route-gateway/tests/e2e/max/dependencies.bicep @@ -0,0 +1,38 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Required. The name of the virtual Hub to create.') +param virtualHubName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +resource virtualHub 'Microsoft.Network/virtualHubs@2023-04-01' = { + name: virtualHubName + location: location + properties: { + addressPrefix: '10.0.0.0/16' + virtualWan: { + id: virtualWan.id + } + } +} + +@description('The resource ID of the created Virtual Hub.') +output virtualHubResourceId string = virtualHub.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/express-route-gateway/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/express-route-gateway/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..5a8c49a60 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-gateway/tests/e2e/max/main.test.bicep @@ -0,0 +1,91 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.expressRouteGateway-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nergmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vwan-${serviceShort}' + virtualHubName: 'dep-${namePrefix}-hub-${serviceShort}' + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + tags: { + 'hidden-title': 'This is visible in the resource name' + hello: 'world' + } + autoScaleConfigurationBoundsMin: 2 + autoScaleConfigurationBoundsMax: 3 + virtualHubId: nestedDependencies.outputs.virtualHubResourceId + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '78ad6c3f-7f77-4d26-9576-dbd947241ef0' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + dependsOn: [ + nestedDependencies + ] +} diff --git a/avm/1.1.0/res/network/express-route-gateway/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/express-route-gateway/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..0e84400a0 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-gateway/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,27 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Required. The name of the virtual Hub to create.') +param virtualHubName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +resource virtualHub 'Microsoft.Network/virtualHubs@2023-04-01' = { + name: virtualHubName + location: location + properties: { + addressPrefix: '10.0.0.0/16' + virtualWan: { + id: virtualWan.id + } + } +} + +@description('The resource ID of the created Virtual Hub.') +output virtualHubResourceId string = virtualHub.id diff --git a/avm/1.1.0/res/network/express-route-gateway/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/express-route-gateway/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..c3056f8c0 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-gateway/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,68 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.expressRouteGateway-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nergwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vwan-${serviceShort}' + virtualHubName: 'dep-${namePrefix}-hub-${serviceShort}' + location: resourceLocation + } +} +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + tags: { + 'hidden-title': 'This is visible in the resource name' + hello: 'world' + } + autoScaleConfigurationBoundsMin: 2 + autoScaleConfigurationBoundsMax: 3 + virtualHubId: nestedDependencies.outputs.virtualHubResourceId + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + } + dependsOn: [ + nestedDependencies + ] +} diff --git a/avm/1.1.0/res/network/express-route-gateway/version.json b/avm/1.1.0/res/network/express-route-gateway/version.json new file mode 100644 index 000000000..7e1d3f415 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-gateway/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.7", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/express-route-port/README.md b/avm/1.1.0/res/network/express-route-port/README.md new file mode 100644 index 000000000..bd7c23ebb --- /dev/null +++ b/avm/1.1.0/res/network/express-route-port/README.md @@ -0,0 +1,725 @@ +# ExpressRoute Ports `[Microsoft.Network/ExpressRoutePorts]` + +This module deploys an Express Route Port resource used by Express Route Direct. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/ExpressRoutePorts` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/ExpressRoutePorts) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/express-route-port:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module expressRoutePort 'br/public:avm/res/network/express-route-port:' = { + name: 'expressRoutePortDeployment' + params: { + // Required parameters + bandwidthInGbps: 10 + name: 'nerpmin001' + peeringLocation: 'Airtel-Chennai2-CLS' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "bandwidthInGbps": { + "value": 10 + }, + "name": { + "value": "nerpmin001" + }, + "peeringLocation": { + "value": "Airtel-Chennai2-CLS" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-port:' + +// Required parameters +param bandwidthInGbps = 10 +param name = 'nerpmin001' +param peeringLocation = 'Airtel-Chennai2-CLS' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module expressRoutePort 'br/public:avm/res/network/express-route-port:' = { + name: 'expressRoutePortDeployment' + params: { + // Required parameters + bandwidthInGbps: 10 + name: 'nerpmax001' + peeringLocation: 'Airtel-Chennai2-CLS' + // Non-required parameters + billingType: 'MeteredData' + encapsulation: 'Dot1Q' + links: [ + { + name: 'link1' + properties: { + adminState: 'Disabled' + } + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'd7aa3dfa-6ba6-4ed8-b561-2164fbb1327e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "bandwidthInGbps": { + "value": 10 + }, + "name": { + "value": "nerpmax001" + }, + "peeringLocation": { + "value": "Airtel-Chennai2-CLS" + }, + // Non-required parameters + "billingType": { + "value": "MeteredData" + }, + "encapsulation": { + "value": "Dot1Q" + }, + "links": { + "value": [ + { + "name": "link1", + "properties": { + "adminState": "Disabled" + } + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "d7aa3dfa-6ba6-4ed8-b561-2164fbb1327e", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-port:' + +// Required parameters +param bandwidthInGbps = 10 +param name = 'nerpmax001' +param peeringLocation = 'Airtel-Chennai2-CLS' +// Non-required parameters +param billingType = 'MeteredData' +param encapsulation = 'Dot1Q' +param links = [ + { + name: 'link1' + properties: { + adminState: 'Disabled' + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'd7aa3dfa-6ba6-4ed8-b561-2164fbb1327e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module expressRoutePort 'br/public:avm/res/network/express-route-port:' = { + name: 'expressRoutePortDeployment' + params: { + // Required parameters + bandwidthInGbps: 10 + name: 'nerpwaf001' + peeringLocation: 'Airtel-Chennai2-CLS' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "bandwidthInGbps": { + "value": 10 + }, + "name": { + "value": "nerpwaf001" + }, + "peeringLocation": { + "value": "Airtel-Chennai2-CLS" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-port:' + +// Required parameters +param bandwidthInGbps = 10 +param name = 'nerpwaf001' +param peeringLocation = 'Airtel-Chennai2-CLS' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`bandwidthInGbps`](#parameter-bandwidthingbps) | int | This is the bandwidth in Gbps of the circuit being created. It must exactly match one of the available bandwidth offers List ExpressRoute Service Providers API call. | +| [`name`](#parameter-name) | string | This is the name of the ExpressRoute Port Resource. | +| [`peeringLocation`](#parameter-peeringlocation) | string | This is the name of the peering location and not the ARM resource location. It must exactly match one of the available peering locations from List ExpressRoute Service Providers API call. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`billingType`](#parameter-billingtype) | string | Chosen SKU family of ExpressRoute circuit. Choose from MeteredData or UnlimitedData SKU families. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`encapsulation`](#parameter-encapsulation) | string | Encapsulation method on physical ports. | +| [`links`](#parameter-links) | array | Properties of the ExpressRouteLink. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `bandwidthInGbps` + +This is the bandwidth in Gbps of the circuit being created. It must exactly match one of the available bandwidth offers List ExpressRoute Service Providers API call. + +- Required: Yes +- Type: int + +### Parameter: `name` + +This is the name of the ExpressRoute Port Resource. + +- Required: Yes +- Type: string + +### Parameter: `peeringLocation` + +This is the name of the peering location and not the ARM resource location. It must exactly match one of the available peering locations from List ExpressRoute Service Providers API call. + +- Required: Yes +- Type: string + +### Parameter: `billingType` + +Chosen SKU family of ExpressRoute circuit. Choose from MeteredData or UnlimitedData SKU families. + +- Required: No +- Type: string +- Default: `'MeteredData'` +- Allowed: + ```Bicep + [ + 'MeteredData' + 'UnlimitedData' + ] + ``` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `encapsulation` + +Encapsulation method on physical ports. + +- Required: No +- Type: string +- Default: `'Dot1Q'` +- Allowed: + ```Bicep + [ + 'Dot1Q' + 'QinQ' + ] + ``` + +### Parameter: `links` + +Properties of the ExpressRouteLink. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-linksname) | string | The name of the link to be created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`id`](#parameter-linksid) | string | Resource Id of the existing Link. | +| [`properties`](#parameter-linksproperties) | object | Properties of the Link. | + +### Parameter: `links.name` + +The name of the link to be created. + +- Required: Yes +- Type: string + +### Parameter: `links.id` + +Resource Id of the existing Link. + +- Required: No +- Type: string + +### Parameter: `links.properties` + +Properties of the Link. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`adminState`](#parameter-linkspropertiesadminstate) | string | Administrative state of the physical port. Must be set to 'Disabled' for initial deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`macSecConfig`](#parameter-linkspropertiesmacsecconfig) | object | MacSec Configuration of the link. | + +### Parameter: `links.properties.adminState` + +Administrative state of the physical port. Must be set to 'Disabled' for initial deployment. + +- Required: Yes +- Type: string + +### Parameter: `links.properties.macSecConfig` + +MacSec Configuration of the link. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`cakSecretIdentifier`](#parameter-linkspropertiesmacsecconfigcaksecretidentifier) | string | Keyvault Secret Identifier URL containing Mac security CAK key. | +| [`cipher`](#parameter-linkspropertiesmacsecconfigcipher) | string | Mac security cipher. | +| [`cknSecretIdentifier`](#parameter-linkspropertiesmacsecconfigcknsecretidentifier) | string | Keyvault Secret Identifier URL containing Mac security CKN key. | +| [`sciState`](#parameter-linkspropertiesmacsecconfigscistate) | string | Sci mode. | + +### Parameter: `links.properties.macSecConfig.cakSecretIdentifier` + +Keyvault Secret Identifier URL containing Mac security CAK key. + +- Required: Yes +- Type: string + +### Parameter: `links.properties.macSecConfig.cipher` + +Mac security cipher. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'GcmAes128' + 'GcmAes256' + 'GcmAesXpn128' + 'GcmAesXpn256' + ] + ``` + +### Parameter: `links.properties.macSecConfig.cknSecretIdentifier` + +Keyvault Secret Identifier URL containing Mac security CKN key. + +- Required: Yes +- Type: string + +### Parameter: `links.properties.macSecConfig.sciState` + +Sci mode. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the ExpressRoute Gateway. | +| `resourceGroupName` | string | The resource group of the ExpressRoute Gateway was deployed into. | +| `resourceId` | string | The resource ID of the ExpressRoute Gateway. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/express-route-port/main.bicep b/avm/1.1.0/res/network/express-route-port/main.bicep new file mode 100644 index 000000000..c06b135b6 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-port/main.bicep @@ -0,0 +1,180 @@ +metadata name = 'ExpressRoute Ports' +metadata description = 'This module deploys an Express Route Port resource used by Express Route Direct.' + +@description('Required. This is the name of the ExpressRoute Port Resource.') +param name string + +@description('Required. This is the bandwidth in Gbps of the circuit being created. It must exactly match one of the available bandwidth offers List ExpressRoute Service Providers API call.') +param bandwidthInGbps int + +@description('Optional. Chosen SKU family of ExpressRoute circuit. Choose from MeteredData or UnlimitedData SKU families.') +@allowed([ + 'MeteredData' + 'UnlimitedData' +]) +param billingType string = 'MeteredData' + +@description('Optional. Encapsulation method on physical ports.') +@allowed([ + 'Dot1Q' + 'QinQ' +]) +param encapsulation string = 'Dot1Q' + +@description('Optional. Properties of the ExpressRouteLink.') +param links linkType[]? + +@description('Required. This is the name of the peering location and not the ARM resource location. It must exactly match one of the available peering locations from List ExpressRoute Service Providers API call.') +param peeringLocation string + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-expressrouteport.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource expressRoutePort_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: expressRoutePort +} + +resource expressRoutePort 'Microsoft.Network/ExpressRoutePorts@2024-05-01' = { + name: name + location: location + tags: tags + properties: { + bandwidthInGbps: bandwidthInGbps + billingType: billingType + encapsulation: encapsulation + links: links ?? [] + peeringLocation: peeringLocation + } +} + +resource expressRoutePort_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(expressRoutePort.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condition is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: expressRoutePort + } +] + +@description('The resource ID of the ExpressRoute Gateway.') +output resourceId string = expressRoutePort.id + +@description('The resource group of the ExpressRoute Gateway was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the ExpressRoute Gateway.') +output name string = expressRoutePort.name + +@description('The location the resource was deployed into.') +output location string = expressRoutePort.location + +// =============== // +// Definitions // +// =============== // + +@export() +@description('The type for a link.') +type linkType = { + @description('Optional. Resource Id of the existing Link.') + id: string? + + @description('Required. The name of the link to be created.') + name: string + + @description('Optional. Properties of the Link.') + properties: { + @description('Required. Administrative state of the physical port. Must be set to \'Disabled\' for initial deployment.') + adminState: string + + @description('Optional. MacSec Configuration of the link.') + macSecConfig: { + @description('Required. Keyvault Secret Identifier URL containing Mac security CAK key.') + cakSecretIdentifier: string + + @description('Required. Mac security cipher.') + cipher: ('GcmAes128' | 'GcmAes256' | 'GcmAesXpn128' | 'GcmAesXpn256') + + @description('Required. Keyvault Secret Identifier URL containing Mac security CKN key.') + cknSecretIdentifier: string + + @description('Required. Sci mode.') + sciState: ('Enabled' | 'Disabled') + }? + }? +} diff --git a/avm/1.1.0/res/network/express-route-port/main.json b/avm/1.1.0/res/network/express-route-port/main.json new file mode 100644 index 000000000..859b8f17c --- /dev/null +++ b/avm/1.1.0/res/network/express-route-port/main.json @@ -0,0 +1,410 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "12646697926659678830" + }, + "name": "ExpressRoute Ports", + "description": "This module deploys an Express Route Port resource used by Express Route Direct." + }, + "definitions": { + "linkType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource Id of the existing Link." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the link to be created." + } + }, + "properties": { + "type": "object", + "properties": { + "adminState": { + "type": "string", + "metadata": { + "description": "Required. Administrative state of the physical port. Must be set to 'Disabled' for initial deployment." + } + }, + "macSecConfig": { + "type": "object", + "properties": { + "cakSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. Keyvault Secret Identifier URL containing Mac security CAK key." + } + }, + "cipher": { + "type": "string", + "allowedValues": [ + "GcmAes128", + "GcmAes256", + "GcmAesXpn128", + "GcmAesXpn256" + ], + "metadata": { + "description": "Required. Mac security cipher." + } + }, + "cknSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. Keyvault Secret Identifier URL containing Mac security CKN key." + } + }, + "sciState": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. Sci mode." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. MacSec Configuration of the link." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the Link." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a link." + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. This is the name of the ExpressRoute Port Resource." + } + }, + "bandwidthInGbps": { + "type": "int", + "metadata": { + "description": "Required. This is the bandwidth in Gbps of the circuit being created. It must exactly match one of the available bandwidth offers List ExpressRoute Service Providers API call." + } + }, + "billingType": { + "type": "string", + "defaultValue": "MeteredData", + "allowedValues": [ + "MeteredData", + "UnlimitedData" + ], + "metadata": { + "description": "Optional. Chosen SKU family of ExpressRoute circuit. Choose from MeteredData or UnlimitedData SKU families." + } + }, + "encapsulation": { + "type": "string", + "defaultValue": "Dot1Q", + "allowedValues": [ + "Dot1Q", + "QinQ" + ], + "metadata": { + "description": "Optional. Encapsulation method on physical ports." + } + }, + "links": { + "type": "array", + "items": { + "$ref": "#/definitions/linkType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Properties of the ExpressRouteLink." + } + }, + "peeringLocation": { + "type": "string", + "metadata": { + "description": "Required. This is the name of the peering location and not the ARM resource location. It must exactly match one of the available peering locations from List ExpressRoute Service Providers API call." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-expressrouteport.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "expressRoutePort_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/ExpressRoutePorts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "expressRoutePort" + ] + }, + "expressRoutePort": { + "type": "Microsoft.Network/ExpressRoutePorts", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "bandwidthInGbps": "[parameters('bandwidthInGbps')]", + "billingType": "[parameters('billingType')]", + "encapsulation": "[parameters('encapsulation')]", + "links": "[coalesce(parameters('links'), createArray())]", + "peeringLocation": "[parameters('peeringLocation')]" + } + }, + "expressRoutePort_roleAssignments": { + "copy": { + "name": "expressRoutePort_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/ExpressRoutePorts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/ExpressRoutePorts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "expressRoutePort" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the ExpressRoute Gateway." + }, + "value": "[resourceId('Microsoft.Network/ExpressRoutePorts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the ExpressRoute Gateway was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the ExpressRoute Gateway." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('expressRoutePort', '2024-05-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/express-route-port/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/express-route-port/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..22913a066 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-port/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,49 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.expressrouteports-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nerpmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + peeringLocation: 'Airtel-Chennai2-CLS' + bandwidthInGbps: 10 + } + } +] diff --git a/avm/1.1.0/res/network/express-route-port/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/express-route-port/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-port/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/express-route-port/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/express-route-port/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..81db35fdd --- /dev/null +++ b/avm/1.1.0/res/network/express-route-port/tests/e2e/max/main.test.bicep @@ -0,0 +1,95 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.expressrouteports-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nerpmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + peeringLocation: 'Airtel-Chennai2-CLS' + location: resourceLocation + bandwidthInGbps: 10 + billingType: 'MeteredData' + encapsulation: 'Dot1Q' + links: [ + { + name: 'link1' + properties: { + adminState: 'Disabled' + } + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'd7aa3dfa-6ba6-4ed8-b561-2164fbb1327e' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/express-route-port/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/express-route-port/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..e4845eb25 --- /dev/null +++ b/avm/1.1.0/res/network/express-route-port/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,49 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.expressrouteports-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nerpwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + peeringLocation: 'Airtel-Chennai2-CLS' + bandwidthInGbps: 10 + } + } +] diff --git a/avm/1.1.0/res/network/express-route-port/version.json b/avm/1.1.0/res/network/express-route-port/version.json new file mode 100644 index 000000000..daf1a794d --- /dev/null +++ b/avm/1.1.0/res/network/express-route-port/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.2", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/res/network/firewall-policy/README.md b/avm/1.1.0/res/network/firewall-policy/README.md new file mode 100644 index 000000000..304e1f975 --- /dev/null +++ b/avm/1.1.0/res/network/firewall-policy/README.md @@ -0,0 +1,1036 @@ +# Firewall Policies `[Microsoft.Network/firewallPolicies]` + +This module deploys a Firewall Policy. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/firewallPolicies` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/firewallPolicies) | +| `Microsoft.Network/firewallPolicies/ruleCollectionGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/firewallPolicies/ruleCollectionGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/firewall-policy:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = { + name: 'firewallPolicyDeployment' + params: { + // Required parameters + name: 'nfpmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nfpmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/firewall-policy:' + +// Required parameters +param name = 'nfpmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = { + name: 'firewallPolicyDeployment' + params: { + // Required parameters + name: 'nfpmax001' + // Non-required parameters + allowSqlRedirect: true + autoLearnPrivateRanges: 'Enabled' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + mode: 'Alert' + roleAssignments: [ + { + name: 'c1c7fa14-5a90-4932-8781-fa91318b8858' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ruleCollectionGroups: [ + { + name: 'rule-001' + priority: 5000 + ruleCollections: [ + { + action: { + type: 'Allow' + } + name: 'collection002' + priority: 5555 + ruleCollectionType: 'FirewallPolicyFilterRuleCollection' + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationFqdns: [] + destinationIpGroups: [] + destinationPorts: [ + '80' + ] + ipProtocols: [ + 'TCP' + 'UDP' + ] + name: 'rule002' + ruleType: 'NetworkRule' + sourceAddresses: [ + '*' + ] + sourceIpGroups: [] + } + ] + } + ] + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + tier: 'Premium' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nfpmax001" + }, + // Non-required parameters + "allowSqlRedirect": { + "value": true + }, + "autoLearnPrivateRanges": { + "value": "Enabled" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "mode": { + "value": "Alert" + }, + "roleAssignments": { + "value": [ + { + "name": "c1c7fa14-5a90-4932-8781-fa91318b8858", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "ruleCollectionGroups": { + "value": [ + { + "name": "rule-001", + "priority": 5000, + "ruleCollections": [ + { + "action": { + "type": "Allow" + }, + "name": "collection002", + "priority": 5555, + "ruleCollectionType": "FirewallPolicyFilterRuleCollection", + "rules": [ + { + "destinationAddresses": [ + "*" + ], + "destinationFqdns": [], + "destinationIpGroups": [], + "destinationPorts": [ + "80" + ], + "ipProtocols": [ + "TCP", + "UDP" + ], + "name": "rule002", + "ruleType": "NetworkRule", + "sourceAddresses": [ + "*" + ], + "sourceIpGroups": [] + } + ] + } + ] + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "tier": { + "value": "Premium" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/firewall-policy:' + +// Required parameters +param name = 'nfpmax001' +// Non-required parameters +param allowSqlRedirect = true +param autoLearnPrivateRanges = 'Enabled' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param mode = 'Alert' +param roleAssignments = [ + { + name: 'c1c7fa14-5a90-4932-8781-fa91318b8858' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param ruleCollectionGroups = [ + { + name: 'rule-001' + priority: 5000 + ruleCollections: [ + { + action: { + type: 'Allow' + } + name: 'collection002' + priority: 5555 + ruleCollectionType: 'FirewallPolicyFilterRuleCollection' + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationFqdns: [] + destinationIpGroups: [] + destinationPorts: [ + '80' + ] + ipProtocols: [ + 'TCP' + 'UDP' + ] + name: 'rule002' + ruleType: 'NetworkRule' + sourceAddresses: [ + '*' + ] + sourceIpGroups: [] + } + ] + } + ] + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param tier = 'Premium' +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = { + name: 'firewallPolicyDeployment' + params: { + // Required parameters + name: 'nfpwaf001' + // Non-required parameters + allowSqlRedirect: true + autoLearnPrivateRanges: 'Enabled' + location: '' + ruleCollectionGroups: [ + { + name: 'rule-001' + priority: 5000 + ruleCollections: [ + { + action: { + type: 'Allow' + } + name: 'collection002' + priority: 5555 + ruleCollectionType: 'FirewallPolicyFilterRuleCollection' + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationFqdns: [] + destinationIpGroups: [] + destinationPorts: [ + '80' + ] + ipProtocols: [ + 'TCP' + 'UDP' + ] + name: 'rule002' + ruleType: 'NetworkRule' + sourceAddresses: [ + '*' + ] + sourceIpGroups: [] + } + ] + } + ] + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + threatIntelMode: 'Deny' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nfpwaf001" + }, + // Non-required parameters + "allowSqlRedirect": { + "value": true + }, + "autoLearnPrivateRanges": { + "value": "Enabled" + }, + "location": { + "value": "" + }, + "ruleCollectionGroups": { + "value": [ + { + "name": "rule-001", + "priority": 5000, + "ruleCollections": [ + { + "action": { + "type": "Allow" + }, + "name": "collection002", + "priority": 5555, + "ruleCollectionType": "FirewallPolicyFilterRuleCollection", + "rules": [ + { + "destinationAddresses": [ + "*" + ], + "destinationFqdns": [], + "destinationIpGroups": [], + "destinationPorts": [ + "80" + ], + "ipProtocols": [ + "TCP", + "UDP" + ], + "name": "rule002", + "ruleType": "NetworkRule", + "sourceAddresses": [ + "*" + ], + "sourceIpGroups": [] + } + ] + } + ] + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "threatIntelMode": { + "value": "Deny" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/firewall-policy:' + +// Required parameters +param name = 'nfpwaf001' +// Non-required parameters +param allowSqlRedirect = true +param autoLearnPrivateRanges = 'Enabled' +param location = '' +param ruleCollectionGroups = [ + { + name: 'rule-001' + priority: 5000 + ruleCollections: [ + { + action: { + type: 'Allow' + } + name: 'collection002' + priority: 5555 + ruleCollectionType: 'FirewallPolicyFilterRuleCollection' + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationFqdns: [] + destinationIpGroups: [] + destinationPorts: [ + '80' + ] + ipProtocols: [ + 'TCP' + 'UDP' + ] + name: 'rule002' + ruleType: 'NetworkRule' + sourceAddresses: [ + '*' + ] + sourceIpGroups: [] + } + ] + } + ] + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param threatIntelMode = 'Deny' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Firewall Policy. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowSqlRedirect`](#parameter-allowsqlredirect) | bool | A flag to indicate if SQL Redirect traffic filtering is enabled. Turning on the flag requires no rule using port 11000-11999. | +| [`autoLearnPrivateRanges`](#parameter-autolearnprivateranges) | string | The operation mode for automatically learning private ranges to not be SNAT. | +| [`basePolicyResourceId`](#parameter-basepolicyresourceid) | string | Resource ID of the base policy. | +| [`bypassTrafficSettings`](#parameter-bypasstrafficsettings) | array | List of rules for traffic to bypass. | +| [`certificateName`](#parameter-certificatename) | string | Name of the CA certificate. | +| [`defaultWorkspaceId`](#parameter-defaultworkspaceid) | string | Default Log Analytics Resource ID for Firewall Policy Insights. | +| [`enableProxy`](#parameter-enableproxy) | bool | Enable DNS Proxy on Firewalls attached to the Firewall Policy. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`fqdns`](#parameter-fqdns) | array | List of FQDNs for the ThreatIntel Allowlist. | +| [`insightsIsEnabled`](#parameter-insightsisenabled) | bool | A flag to indicate if the insights are enabled on the policy. | +| [`ipAddresses`](#parameter-ipaddresses) | array | List of IP addresses for the ThreatIntel Allowlist. | +| [`keyVaultSecretId`](#parameter-keyvaultsecretid) | string | Secret ID of (base-64 encoded unencrypted PFX) Secret or Certificate object stored in KeyVault. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`mode`](#parameter-mode) | string | The configuring of intrusion detection. | +| [`privateRanges`](#parameter-privateranges) | array | List of private IP addresses/IP address ranges to not be SNAT. | +| [`retentionDays`](#parameter-retentiondays) | int | Number of days the insights should be enabled on the policy. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ruleCollectionGroups`](#parameter-rulecollectiongroups) | array | Rule collection groups. | +| [`servers`](#parameter-servers) | array | List of Custom DNS Servers. | +| [`signatureOverrides`](#parameter-signatureoverrides) | array | List of specific signatures states. | +| [`tags`](#parameter-tags) | object | Tags of the Firewall policy resource. | +| [`threatIntelMode`](#parameter-threatintelmode) | string | The operation mode for Threat Intel. | +| [`tier`](#parameter-tier) | string | Tier of Firewall Policy. | +| [`workspaces`](#parameter-workspaces) | array | List of workspaces for Firewall Policy Insights. | + +### Parameter: `name` + +Name of the Firewall Policy. + +- Required: Yes +- Type: string + +### Parameter: `allowSqlRedirect` + +A flag to indicate if SQL Redirect traffic filtering is enabled. Turning on the flag requires no rule using port 11000-11999. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `autoLearnPrivateRanges` + +The operation mode for automatically learning private ranges to not be SNAT. + +- Required: No +- Type: string +- Default: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `basePolicyResourceId` + +Resource ID of the base policy. + +- Required: No +- Type: string + +### Parameter: `bypassTrafficSettings` + +List of rules for traffic to bypass. + +- Required: No +- Type: array + +### Parameter: `certificateName` + +Name of the CA certificate. + +- Required: No +- Type: string + +### Parameter: `defaultWorkspaceId` + +Default Log Analytics Resource ID for Firewall Policy Insights. + +- Required: No +- Type: string + +### Parameter: `enableProxy` + +Enable DNS Proxy on Firewalls attached to the Firewall Policy. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `fqdns` + +List of FQDNs for the ThreatIntel Allowlist. + +- Required: No +- Type: array + +### Parameter: `insightsIsEnabled` + +A flag to indicate if the insights are enabled on the policy. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `ipAddresses` + +List of IP addresses for the ThreatIntel Allowlist. + +- Required: No +- Type: array + +### Parameter: `keyVaultSecretId` + +Secret ID of (base-64 encoded unencrypted PFX) Secret or Certificate object stored in KeyVault. + +- Required: No +- Type: string + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: Yes +- Type: array + +### Parameter: `mode` + +The configuring of intrusion detection. + +- Required: No +- Type: string +- Default: `'Off'` +- Allowed: + ```Bicep + [ + 'Alert' + 'Deny' + 'Off' + ] + ``` + +### Parameter: `privateRanges` + +List of private IP addresses/IP address ranges to not be SNAT. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `retentionDays` + +Number of days the insights should be enabled on the policy. + +- Required: No +- Type: int +- Default: `365` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ruleCollectionGroups` + +Rule collection groups. + +- Required: No +- Type: array + +### Parameter: `servers` + +List of Custom DNS Servers. + +- Required: No +- Type: array + +### Parameter: `signatureOverrides` + +List of specific signatures states. + +- Required: No +- Type: array + +### Parameter: `tags` + +Tags of the Firewall policy resource. + +- Required: No +- Type: object + +### Parameter: `threatIntelMode` + +The operation mode for Threat Intel. + +- Required: No +- Type: string +- Default: `'Off'` +- Allowed: + ```Bicep + [ + 'Alert' + 'Deny' + 'Off' + ] + ``` + +### Parameter: `tier` + +Tier of Firewall Policy. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Premium' + 'Standard' + ] + ``` + +### Parameter: `workspaces` + +List of workspaces for Firewall Policy Insights. + +- Required: No +- Type: array + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed firewall policy. | +| `resourceGroupName` | string | The resource group of the deployed firewall policy. | +| `resourceId` | string | The resource ID of the deployed firewall policy. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/firewall-policy/main.bicep b/avm/1.1.0/res/network/firewall-policy/main.bicep new file mode 100644 index 000000000..fe08b236d --- /dev/null +++ b/avm/1.1.0/res/network/firewall-policy/main.bicep @@ -0,0 +1,325 @@ +metadata name = 'Firewall Policies' +metadata description = 'This module deploys a Firewall Policy.' + +@description('Required. Name of the Firewall Policy.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the Firewall policy resource.') +param tags object? + +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType + +@description('Optional. Resource ID of the base policy.') +param basePolicyResourceId string? + +@description('Optional. Enable DNS Proxy on Firewalls attached to the Firewall Policy.') +param enableProxy bool = false + +@description('Optional. List of Custom DNS Servers.') +param servers array? + +@description('Optional. A flag to indicate if the insights are enabled on the policy.') +param insightsIsEnabled bool = false + +@description('Optional. Default Log Analytics Resource ID for Firewall Policy Insights.') +param defaultWorkspaceId string? + +@description('Optional. List of workspaces for Firewall Policy Insights.') +param workspaces array? + +@description('Optional. Number of days the insights should be enabled on the policy.') +param retentionDays int = 365 + +@description('Optional. List of rules for traffic to bypass.') +param bypassTrafficSettings array? + +@description('Optional. List of specific signatures states.') +param signatureOverrides array? + +@description('Optional. The configuring of intrusion detection.') +@allowed([ + 'Alert' + 'Deny' + 'Off' +]) +param mode string = 'Off' + +@description('Optional. Tier of Firewall Policy.') +@allowed([ + 'Premium' + 'Standard' + 'Basic' +]) +param tier string = 'Standard' + +@description('Optional. List of private IP addresses/IP address ranges to not be SNAT.') +param privateRanges array = [] + +@allowed([ + 'Disabled' + 'Enabled' +]) +@description('Optional. The operation mode for automatically learning private ranges to not be SNAT.') +param autoLearnPrivateRanges string = 'Disabled' + +@description('Optional. The operation mode for Threat Intel.') +@allowed([ + 'Alert' + 'Deny' + 'Off' +]) +param threatIntelMode string = 'Off' + +@description('Optional. A flag to indicate if SQL Redirect traffic filtering is enabled. Turning on the flag requires no rule using port 11000-11999.') +param allowSqlRedirect bool = false + +@description('Optional. List of FQDNs for the ThreatIntel Allowlist.') +param fqdns array? + +@description('Optional. List of IP addresses for the ThreatIntel Allowlist.') +param ipAddresses array? + +@description('Optional. Secret ID of (base-64 encoded unencrypted PFX) Secret or Certificate object stored in KeyVault.') +#disable-next-line secure-secrets-in-params // Not a secret +param keyVaultSecretId string? + +@description('Optional. Name of the CA certificate.') +param certificateName string? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Rule collection groups.') +param ruleCollectionGroups array? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: 'UserAssigned' + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-firewallpolicy.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource firewallPolicy 'Microsoft.Network/firewallPolicies@2023-04-01' = { + name: name + location: location + tags: tags + identity: identity + properties: { + basePolicy: !empty(basePolicyResourceId ?? '') + ? { + id: basePolicyResourceId + } + : null + dnsSettings: enableProxy + ? { + enableProxy: enableProxy + servers: servers ?? [] + } + : null + insights: insightsIsEnabled + ? { + isEnabled: insightsIsEnabled + logAnalyticsResources: { + defaultWorkspaceId: { + id: defaultWorkspaceId + } + workspaces: workspaces + } + retentionDays: retentionDays + } + : null + intrusionDetection: (mode != 'Off') + ? { + configuration: { + bypassTrafficSettings: bypassTrafficSettings + signatureOverrides: signatureOverrides + } + mode: mode + } + : null + sku: { + tier: tier + } + snat: !empty(privateRanges) + ? { + autoLearnPrivateRanges: autoLearnPrivateRanges + privateRanges: privateRanges + } + : null + sql: { + allowSqlRedirect: allowSqlRedirect + } + threatIntelMode: threatIntelMode + threatIntelWhitelist: { + fqdns: fqdns ?? [] + ipAddresses: ipAddresses ?? [] + } + transportSecurity: (!empty(keyVaultSecretId ?? []) || !empty(certificateName ?? '')) + ? { + certificateAuthority: { + keyVaultSecretId: keyVaultSecretId + name: certificateName + } + } + : null + } +} + +// When a FW policy uses a base policy and have more rule collection groups, +// they need to be deployed sequentially, otherwise the deployment would fail +// because of concurrent access to the base policy. +// The next line forces ARM to deploy them one after the other, so no race concition on the base policy will happen. +@batchSize(1) +module firewallPolicy_ruleCollectionGroups 'rule-collection-group/main.bicep' = [ + for (ruleCollectionGroup, index) in (ruleCollectionGroups ?? []): { + name: '${uniqueString(deployment().name, location)}-firewallPolicy_ruleCollectionGroups-${index}' + params: { + firewallPolicyName: firewallPolicy.name + name: ruleCollectionGroup.name + priority: ruleCollectionGroup.priority + ruleCollections: ruleCollectionGroup.ruleCollections + } + } +] + +resource firewallPolicy_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(firewallPolicy.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: firewallPolicy + } +] + +resource firewallPolicy_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: firewallPolicy +} + +@description('The name of the deployed firewall policy.') +output name string = firewallPolicy.name + +@description('The resource ID of the deployed firewall policy.') +output resourceId string = firewallPolicy.id + +@description('The resource group of the deployed firewall policy.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = firewallPolicy.location + +// =============== // +// Definitions // +// =============== // + +type managedIdentitiesType = { + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[] +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? diff --git a/avm/1.1.0/res/network/firewall-policy/main.json b/avm/1.1.0/res/network/firewall-policy/main.json new file mode 100644 index 000000000..4a72e2414 --- /dev/null +++ b/avm/1.1.0/res/network/firewall-policy/main.json @@ -0,0 +1,583 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12793095614224117013" + }, + "name": "Firewall Policies", + "description": "This module deploys a Firewall Policy." + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Firewall Policy." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the Firewall policy resource." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "basePolicyResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the base policy." + } + }, + "enableProxy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable DNS Proxy on Firewalls attached to the Firewall Policy." + } + }, + "servers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of Custom DNS Servers." + } + }, + "insightsIsEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A flag to indicate if the insights are enabled on the policy." + } + }, + "defaultWorkspaceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Default Log Analytics Resource ID for Firewall Policy Insights." + } + }, + "workspaces": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of workspaces for Firewall Policy Insights." + } + }, + "retentionDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. Number of days the insights should be enabled on the policy." + } + }, + "bypassTrafficSettings": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of rules for traffic to bypass." + } + }, + "signatureOverrides": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of specific signatures states." + } + }, + "mode": { + "type": "string", + "defaultValue": "Off", + "allowedValues": [ + "Alert", + "Deny", + "Off" + ], + "metadata": { + "description": "Optional. The configuring of intrusion detection." + } + }, + "tier": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Premium", + "Standard", + "Basic" + ], + "metadata": { + "description": "Optional. Tier of Firewall Policy." + } + }, + "privateRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of private IP addresses/IP address ranges to not be SNAT." + } + }, + "autoLearnPrivateRanges": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. The operation mode for automatically learning private ranges to not be SNAT." + } + }, + "threatIntelMode": { + "type": "string", + "defaultValue": "Off", + "allowedValues": [ + "Alert", + "Deny", + "Off" + ], + "metadata": { + "description": "Optional. The operation mode for Threat Intel." + } + }, + "allowSqlRedirect": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A flag to indicate if SQL Redirect traffic filtering is enabled. Turning on the flag requires no rule using port 11000-11999." + } + }, + "fqdns": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of FQDNs for the ThreatIntel Allowlist." + } + }, + "ipAddresses": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of IP addresses for the ThreatIntel Allowlist." + } + }, + "keyVaultSecretId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Secret ID of (base-64 encoded unencrypted PFX) Secret or Certificate object stored in KeyVault." + } + }, + "certificateName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the CA certificate." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "ruleCollectionGroups": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Rule collection groups." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', 'UserAssigned', 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-firewallpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "firewallPolicy": { + "type": "Microsoft.Network/firewallPolicies", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "basePolicy": "[if(not(empty(coalesce(parameters('basePolicyResourceId'), ''))), createObject('id', parameters('basePolicyResourceId')), null())]", + "dnsSettings": "[if(parameters('enableProxy'), createObject('enableProxy', parameters('enableProxy'), 'servers', coalesce(parameters('servers'), createArray())), null())]", + "insights": "[if(parameters('insightsIsEnabled'), createObject('isEnabled', parameters('insightsIsEnabled'), 'logAnalyticsResources', createObject('defaultWorkspaceId', createObject('id', parameters('defaultWorkspaceId')), 'workspaces', parameters('workspaces')), 'retentionDays', parameters('retentionDays')), null())]", + "intrusionDetection": "[if(not(equals(parameters('mode'), 'Off')), createObject('configuration', createObject('bypassTrafficSettings', parameters('bypassTrafficSettings'), 'signatureOverrides', parameters('signatureOverrides')), 'mode', parameters('mode')), null())]", + "sku": { + "tier": "[parameters('tier')]" + }, + "snat": "[if(not(empty(parameters('privateRanges'))), createObject('autoLearnPrivateRanges', parameters('autoLearnPrivateRanges'), 'privateRanges', parameters('privateRanges')), null())]", + "sql": { + "allowSqlRedirect": "[parameters('allowSqlRedirect')]" + }, + "threatIntelMode": "[parameters('threatIntelMode')]", + "threatIntelWhitelist": { + "fqdns": "[coalesce(parameters('fqdns'), createArray())]", + "ipAddresses": "[coalesce(parameters('ipAddresses'), createArray())]" + }, + "transportSecurity": "[if(or(not(empty(coalesce(parameters('keyVaultSecretId'), createArray()))), not(empty(coalesce(parameters('certificateName'), '')))), createObject('certificateAuthority', createObject('keyVaultSecretId', parameters('keyVaultSecretId'), 'name', parameters('certificateName'))), null())]" + } + }, + "firewallPolicy_roleAssignments": { + "copy": { + "name": "firewallPolicy_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/firewallPolicies/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/firewallPolicies', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "firewallPolicy" + ] + }, + "firewallPolicy_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/firewallPolicies/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "firewallPolicy" + ] + }, + "firewallPolicy_ruleCollectionGroups": { + "copy": { + "name": "firewallPolicy_ruleCollectionGroups", + "count": "[length(coalesce(parameters('ruleCollectionGroups'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-firewallPolicy_ruleCollectionGroups-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "firewallPolicyName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('ruleCollectionGroups'), createArray())[copyIndex()].name]" + }, + "priority": { + "value": "[coalesce(parameters('ruleCollectionGroups'), createArray())[copyIndex()].priority]" + }, + "ruleCollections": { + "value": "[coalesce(parameters('ruleCollectionGroups'), createArray())[copyIndex()].ruleCollections]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12754430700106125957" + }, + "name": "Firewall Policy Rule Collection Groups", + "description": "This module deploys a Firewall Policy Rule Collection Group." + }, + "parameters": { + "firewallPolicyName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Firewall Policy. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule collection group to deploy." + } + }, + "priority": { + "type": "int", + "metadata": { + "description": "Required. Priority of the Firewall Policy Rule Collection Group resource." + } + }, + "ruleCollections": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Group of Firewall Policy rule collections." + } + } + }, + "resources": { + "firewallPolicy": { + "existing": true, + "type": "Microsoft.Network/firewallPolicies", + "apiVersion": "2023-04-01", + "name": "[parameters('firewallPolicyName')]" + }, + "ruleCollectionGroup": { + "type": "Microsoft.Network/firewallPolicies/ruleCollectionGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('firewallPolicyName'), parameters('name'))]", + "properties": { + "priority": "[parameters('priority')]", + "ruleCollections": "[coalesce(parameters('ruleCollections'), createArray())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed rule collection group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed rule collection group." + }, + "value": "[resourceId('Microsoft.Network/firewallPolicies/ruleCollectionGroups', parameters('firewallPolicyName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed rule collection group." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "firewallPolicy" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed firewall policy." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed firewall policy." + }, + "value": "[resourceId('Microsoft.Network/firewallPolicies', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed firewall policy." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('firewallPolicy', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/firewall-policy/rule-collection-group/README.md b/avm/1.1.0/res/network/firewall-policy/rule-collection-group/README.md new file mode 100644 index 000000000..11d2af599 --- /dev/null +++ b/avm/1.1.0/res/network/firewall-policy/rule-collection-group/README.md @@ -0,0 +1,72 @@ +# Firewall Policy Rule Collection Groups `[Microsoft.Network/firewallPolicies/ruleCollectionGroups]` + +This module deploys a Firewall Policy Rule Collection Group. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/firewallPolicies/ruleCollectionGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/firewallPolicies/ruleCollectionGroups) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the rule collection group to deploy. | +| [`priority`](#parameter-priority) | int | Priority of the Firewall Policy Rule Collection Group resource. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`firewallPolicyName`](#parameter-firewallpolicyname) | string | The name of the parent Firewall Policy. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ruleCollections`](#parameter-rulecollections) | array | Group of Firewall Policy rule collections. | + +### Parameter: `name` + +The name of the rule collection group to deploy. + +- Required: Yes +- Type: string + +### Parameter: `priority` + +Priority of the Firewall Policy Rule Collection Group resource. + +- Required: Yes +- Type: int + +### Parameter: `firewallPolicyName` + +The name of the parent Firewall Policy. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `ruleCollections` + +Group of Firewall Policy rule collections. + +- Required: No +- Type: array + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed rule collection group. | +| `resourceGroupName` | string | The resource group of the deployed rule collection group. | +| `resourceId` | string | The resource ID of the deployed rule collection group. | diff --git a/avm/1.1.0/res/network/firewall-policy/rule-collection-group/main.bicep b/avm/1.1.0/res/network/firewall-policy/rule-collection-group/main.bicep new file mode 100644 index 000000000..201a93b6d --- /dev/null +++ b/avm/1.1.0/res/network/firewall-policy/rule-collection-group/main.bicep @@ -0,0 +1,36 @@ +metadata name = 'Firewall Policy Rule Collection Groups' +metadata description = 'This module deploys a Firewall Policy Rule Collection Group.' + +@description('Conditional. The name of the parent Firewall Policy. Required if the template is used in a standalone deployment.') +param firewallPolicyName string + +@description('Required. The name of the rule collection group to deploy.') +param name string + +@description('Required. Priority of the Firewall Policy Rule Collection Group resource.') +param priority int + +@description('Optional. Group of Firewall Policy rule collections.') +param ruleCollections array? + +resource firewallPolicy 'Microsoft.Network/firewallPolicies@2023-04-01' existing = { + name: firewallPolicyName +} + +resource ruleCollectionGroup 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2023-04-01' = { + name: name + parent: firewallPolicy + properties: { + priority: priority + ruleCollections: ruleCollections ?? [] + } +} + +@description('The name of the deployed rule collection group.') +output name string = ruleCollectionGroup.name + +@description('The resource ID of the deployed rule collection group.') +output resourceId string = ruleCollectionGroup.id + +@description('The resource group of the deployed rule collection group.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/network/firewall-policy/rule-collection-group/main.json b/avm/1.1.0/res/network/firewall-policy/rule-collection-group/main.json new file mode 100644 index 000000000..ba672d4a4 --- /dev/null +++ b/avm/1.1.0/res/network/firewall-policy/rule-collection-group/main.json @@ -0,0 +1,81 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12754430700106125957" + }, + "name": "Firewall Policy Rule Collection Groups", + "description": "This module deploys a Firewall Policy Rule Collection Group." + }, + "parameters": { + "firewallPolicyName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Firewall Policy. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule collection group to deploy." + } + }, + "priority": { + "type": "int", + "metadata": { + "description": "Required. Priority of the Firewall Policy Rule Collection Group resource." + } + }, + "ruleCollections": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Group of Firewall Policy rule collections." + } + } + }, + "resources": { + "firewallPolicy": { + "existing": true, + "type": "Microsoft.Network/firewallPolicies", + "apiVersion": "2023-04-01", + "name": "[parameters('firewallPolicyName')]" + }, + "ruleCollectionGroup": { + "type": "Microsoft.Network/firewallPolicies/ruleCollectionGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('firewallPolicyName'), parameters('name'))]", + "properties": { + "priority": "[parameters('priority')]", + "ruleCollections": "[coalesce(parameters('ruleCollections'), createArray())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed rule collection group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed rule collection group." + }, + "value": "[resourceId('Microsoft.Network/firewallPolicies/ruleCollectionGroups', parameters('firewallPolicyName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed rule collection group." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/firewall-policy/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/firewall-policy/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..f63c5d678 --- /dev/null +++ b/avm/1.1.0/res/network/firewall-policy/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.firewallpolicies-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nfpmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/network/firewall-policy/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/firewall-policy/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..544accb4a --- /dev/null +++ b/avm/1.1.0/res/network/firewall-policy/tests/e2e/max/dependencies.bicep @@ -0,0 +1,16 @@ +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/firewall-policy/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/firewall-policy/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..d84b91d97 --- /dev/null +++ b/avm/1.1.0/res/network/firewall-policy/tests/e2e/max/main.test.bicep @@ -0,0 +1,135 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.firewallpolicies-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nfpmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + tier: 'Premium' + mode: 'Alert' + ruleCollectionGroups: [ + { + name: '${namePrefix}-rule-001' + priority: 5000 + ruleCollections: [ + { + action: { + type: 'Allow' + } + name: 'collection002' + priority: 5555 + ruleCollectionType: 'FirewallPolicyFilterRuleCollection' + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationFqdns: [] + destinationIpGroups: [] + destinationPorts: [ + '80' + ] + ipProtocols: [ + 'TCP' + 'UDP' + ] + name: 'rule002' + ruleType: 'NetworkRule' + sourceAddresses: [ + '*' + ] + sourceIpGroups: [] + } + ] + } + ] + } + ] + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'c1c7fa14-5a90-4932-8781-fa91318b8858' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + allowSqlRedirect: true + autoLearnPrivateRanges: 'Enabled' + } + } +] diff --git a/avm/1.1.0/res/network/firewall-policy/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/firewall-policy/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..0462603a7 --- /dev/null +++ b/avm/1.1.0/res/network/firewall-policy/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,94 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.firewallpolicies-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nfpwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + ruleCollectionGroups: [ + { + name: '${namePrefix}-rule-001' + priority: 5000 + ruleCollections: [ + { + action: { + type: 'Allow' + } + name: 'collection002' + priority: 5555 + ruleCollectionType: 'FirewallPolicyFilterRuleCollection' + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationFqdns: [] + destinationIpGroups: [] + destinationPorts: [ + '80' + ] + ipProtocols: [ + 'TCP' + 'UDP' + ] + name: 'rule002' + ruleType: 'NetworkRule' + sourceAddresses: [ + '*' + ] + sourceIpGroups: [] + } + ] + } + ] + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + allowSqlRedirect: true + autoLearnPrivateRanges: 'Enabled' + threatIntelMode: 'Deny' + } + } +] diff --git a/avm/1.1.0/res/network/firewall-policy/version.json b/avm/1.1.0/res/network/firewall-policy/version.json new file mode 100644 index 000000000..729ac8767 --- /dev/null +++ b/avm/1.1.0/res/network/firewall-policy/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.2", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/front-door-web-application-firewall-policy/README.md b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/README.md new file mode 100644 index 000000000..45bfcccf8 --- /dev/null +++ b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/README.md @@ -0,0 +1,1196 @@ +# Front Door Web Application Firewall (WAF) Policies `[Microsoft.Network/FrontDoorWebApplicationFirewallPolicies]` + +This module deploys a Front Door Web Application Firewall (WAF) Policy. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/FrontDoorWebApplicationFirewallPolicies` | [2024-02-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-02-01/FrontDoorWebApplicationFirewallPolicies) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/front-door-web-application-firewall-policy:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-door-web-application-firewall-policy:' = { + name: 'frontDoorWebApplicationFirewallPolicyDeployment' + params: { + // Required parameters + name: 'nagwafpmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nagwafpmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/front-door-web-application-firewall-policy:' + +// Required parameters +param name = 'nagwafpmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-door-web-application-firewall-policy:' = { + name: 'frontDoorWebApplicationFirewallPolicyDeployment' + params: { + // Required parameters + name: 'nagwafpmax001' + // Non-required parameters + customRules: { + rules: [ + { + action: 'Block' + enabledState: 'Enabled' + matchConditions: [ + { + matchValue: [ + 'CH' + ] + matchVariable: 'RemoteAddr' + negateCondition: false + operator: 'GeoMatch' + selector: '' + transforms: [] + } + { + matchValue: [ + 'windows' + ] + matchVariable: 'RequestHeader' + negateCondition: false + operator: 'Contains' + selector: 'UserAgent' + transforms: [] + } + { + matchValue: [ + '?>' + '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedRules: { + managedRuleSets: [ + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '1.0' + } + ] + } + policySettings: { + customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==' + customBlockResponseStatusCode: 200 + mode: 'Prevention' + redirectUrl: 'http://www.bing.com' + } + roleAssignments: [ + { + name: 'bb049c96-2571-4a25-b760-444ab25d86ed' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + sku: 'Premium_AzureFrontDoor' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nagwafpmax001" + }, + // Non-required parameters + "customRules": { + "value": { + "rules": [ + { + "action": "Block", + "enabledState": "Enabled", + "matchConditions": [ + { + "matchValue": [ + "CH" + ], + "matchVariable": "RemoteAddr", + "negateCondition": false, + "operator": "GeoMatch", + "selector": "", + "transforms": [] + }, + { + "matchValue": [ + "windows" + ], + "matchVariable": "RequestHeader", + "negateCondition": false, + "operator": "Contains", + "selector": "UserAgent", + "transforms": [] + }, + { + "matchValue": [ + "?>", + "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedRules": { + "value": { + "managedRuleSets": [ + { + "ruleSetType": "Microsoft_BotManagerRuleSet", + "ruleSetVersion": "1.0" + } + ] + } + }, + "policySettings": { + "value": { + "customBlockResponseBody": "PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==", + "customBlockResponseStatusCode": 200, + "mode": "Prevention", + "redirectUrl": "http://www.bing.com" + } + }, + "roleAssignments": { + "value": [ + { + "name": "bb049c96-2571-4a25-b760-444ab25d86ed", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "sku": { + "value": "Premium_AzureFrontDoor" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/front-door-web-application-firewall-policy:' + +// Required parameters +param name = 'nagwafpmax001' +// Non-required parameters +param customRules = { + rules: [ + { + action: 'Block' + enabledState: 'Enabled' + matchConditions: [ + { + matchValue: [ + 'CH' + ] + matchVariable: 'RemoteAddr' + negateCondition: false + operator: 'GeoMatch' + selector: '' + transforms: [] + } + { + matchValue: [ + 'windows' + ] + matchVariable: 'RequestHeader' + negateCondition: false + operator: 'Contains' + selector: 'UserAgent' + transforms: [] + } + { + matchValue: [ + '?>' + '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedRules = { + managedRuleSets: [ + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '1.0' + } + ] +} +param policySettings = { + customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==' + customBlockResponseStatusCode: 200 + mode: 'Prevention' + redirectUrl: 'http://www.bing.com' +} +param roleAssignments = [ + { + name: 'bb049c96-2571-4a25-b760-444ab25d86ed' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sku = 'Premium_AzureFrontDoor' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-door-web-application-firewall-policy:' = { + name: 'frontDoorWebApplicationFirewallPolicyDeployment' + params: { + // Required parameters + name: 'nagwafpwaf001' + // Non-required parameters + customRules: { + rules: [ + { + action: 'Block' + enabledState: 'Enabled' + matchConditions: [ + { + matchValue: [ + 'CH' + ] + matchVariable: 'RemoteAddr' + negateCondition: false + operator: 'GeoMatch' + selector: '' + transforms: [] + } + { + matchValue: [ + 'windows' + ] + matchVariable: 'RequestHeader' + negateCondition: false + operator: 'Contains' + selector: 'UserAgent' + transforms: [] + } + { + matchValue: [ + '?>' + '' + managedRules: { + managedRuleSets: [ + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '1.0' + } + ] + } + policySettings: { + customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==' + customBlockResponseStatusCode: 200 + mode: 'Prevention' + redirectUrl: 'http://www.bing.com' + } + sku: 'Premium_AzureFrontDoor' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nagwafpwaf001" + }, + // Non-required parameters + "customRules": { + "value": { + "rules": [ + { + "action": "Block", + "enabledState": "Enabled", + "matchConditions": [ + { + "matchValue": [ + "CH" + ], + "matchVariable": "RemoteAddr", + "negateCondition": false, + "operator": "GeoMatch", + "selector": "", + "transforms": [] + }, + { + "matchValue": [ + "windows" + ], + "matchVariable": "RequestHeader", + "negateCondition": false, + "operator": "Contains", + "selector": "UserAgent", + "transforms": [] + }, + { + "matchValue": [ + "?>", + "" + }, + "managedRules": { + "value": { + "managedRuleSets": [ + { + "ruleSetType": "Microsoft_BotManagerRuleSet", + "ruleSetVersion": "1.0" + } + ] + } + }, + "policySettings": { + "value": { + "customBlockResponseBody": "PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==", + "customBlockResponseStatusCode": 200, + "mode": "Prevention", + "redirectUrl": "http://www.bing.com" + } + }, + "sku": { + "value": "Premium_AzureFrontDoor" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/front-door-web-application-firewall-policy:' + +// Required parameters +param name = 'nagwafpwaf001' +// Non-required parameters +param customRules = { + rules: [ + { + action: 'Block' + enabledState: 'Enabled' + matchConditions: [ + { + matchValue: [ + 'CH' + ] + matchVariable: 'RemoteAddr' + negateCondition: false + operator: 'GeoMatch' + selector: '' + transforms: [] + } + { + matchValue: [ + 'windows' + ] + matchVariable: 'RequestHeader' + negateCondition: false + operator: 'Contains' + selector: 'UserAgent' + transforms: [] + } + { + matchValue: [ + '?>' + '' +param managedRules = { + managedRuleSets: [ + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '1.0' + } + ] +} +param policySettings = { + customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==' + customBlockResponseStatusCode: 200 + mode: 'Prevention' + redirectUrl: 'http://www.bing.com' +} +param sku = 'Premium_AzureFrontDoor' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Front Door WAF policy. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`customRules`](#parameter-customrules) | object | The custom rules inside the policy. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedRules`](#parameter-managedrules) | object | Describes the managedRules structure. | +| [`policySettings`](#parameter-policysettings) | object | The PolicySettings for policy. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`sku`](#parameter-sku) | string | The pricing tier of the WAF profile. | +| [`tags`](#parameter-tags) | object | Resource tags. | + +### Parameter: `name` + +Name of the Front Door WAF policy. + +- Required: Yes +- Type: string + +### Parameter: `customRules` + +The custom rules inside the policy. + +- Required: No +- Type: object +- Default: + ```Bicep + { + rules: [ + { + action: 'Block' + enabledState: 'Enabled' + matchConditions: [ + { + matchValue: [ + 'ZZ' + ] + matchVariable: 'RemoteAddr' + negateCondition: true + operator: 'GeoMatch' + } + ] + name: 'ApplyGeoFilter' + priority: 100 + ruleType: 'MatchRule' + } + ] + } + ``` + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`rules`](#parameter-customrulesrules) | array | List of rules. | + +### Parameter: `customRules.rules` + +List of rules. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`action`](#parameter-customrulesrulesaction) | string | Describes what action to be applied when rule matches. | +| [`enabledState`](#parameter-customrulesrulesenabledstate) | string | Describes if the custom rule is in enabled or disabled state. | +| [`matchConditions`](#parameter-customrulesrulesmatchconditions) | array | List of match conditions. See https://learn.microsoft.com/en-us/azure/templates/microsoft.network/frontdoorwebapplicationfirewallpolicies#matchcondition for details. | +| [`name`](#parameter-customrulesrulesname) | string | Describes the name of the rule. | +| [`priority`](#parameter-customrulesrulespriority) | int | Describes priority of the rule. Rules with a lower value will be evaluated before rules with a higher value. | +| [`ruleType`](#parameter-customrulesrulesruletype) | string | Describes type of rule. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`rateLimitDurationInMinutes`](#parameter-customrulesrulesratelimitdurationinminutes) | int | Time window for resetting the rate limit count. Default is 1 minute. | +| [`rateLimitThreshold`](#parameter-customrulesrulesratelimitthreshold) | int | Number of allowed requests per client within the time window. | + +### Parameter: `customRules.rules.action` + +Describes what action to be applied when rule matches. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Allow' + 'Block' + 'Log' + 'Redirect' + ] + ``` + +### Parameter: `customRules.rules.enabledState` + +Describes if the custom rule is in enabled or disabled state. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `customRules.rules.matchConditions` + +List of match conditions. See https://learn.microsoft.com/en-us/azure/templates/microsoft.network/frontdoorwebapplicationfirewallpolicies#matchcondition for details. + +- Required: Yes +- Type: array + +### Parameter: `customRules.rules.name` + +Describes the name of the rule. + +- Required: Yes +- Type: string + +### Parameter: `customRules.rules.priority` + +Describes priority of the rule. Rules with a lower value will be evaluated before rules with a higher value. + +- Required: Yes +- Type: int + +### Parameter: `customRules.rules.ruleType` + +Describes type of rule. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'MatchRule' + 'RateLimitRule' + ] + ``` + +### Parameter: `customRules.rules.rateLimitDurationInMinutes` + +Time window for resetting the rate limit count. Default is 1 minute. + +- Required: No +- Type: int + +### Parameter: `customRules.rules.rateLimitThreshold` + +Number of allowed requests per client within the time window. + +- Required: No +- Type: int + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `'global'` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managedRules` + +Describes the managedRules structure. + +- Required: No +- Type: object +- Default: + ```Bicep + { + managedRuleSets: [ + { + exclusions: [] + ruleGroupOverrides: [] + ruleSetAction: 'Block' + ruleSetType: 'Microsoft_DefaultRuleSet' + ruleSetVersion: '2.1' + } + { + exclusions: [] + ruleGroupOverrides: [] + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '1.0' + } + ] + } + ``` + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`managedRuleSets`](#parameter-managedrulesmanagedrulesets) | array | List of rule sets. | + +### Parameter: `managedRules.managedRuleSets` + +List of rule sets. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ruleSetType`](#parameter-managedrulesmanagedrulesetsrulesettype) | string | Defines the rule set type to use. | +| [`ruleSetVersion`](#parameter-managedrulesmanagedrulesetsrulesetversion) | string | Defines the version of the rule set to use. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`exclusions`](#parameter-managedrulesmanagedrulesetsexclusions) | array | Describes the exclusions that are applied to all rules in the set. | +| [`ruleGroupOverrides`](#parameter-managedrulesmanagedrulesetsrulegroupoverrides) | array | Defines the rule group overrides to apply to the rule set. | +| [`ruleSetAction`](#parameter-managedrulesmanagedrulesetsrulesetaction) | string | Defines the rule set action. | + +### Parameter: `managedRules.managedRuleSets.ruleSetType` + +Defines the rule set type to use. + +- Required: Yes +- Type: string + +### Parameter: `managedRules.managedRuleSets.ruleSetVersion` + +Defines the version of the rule set to use. + +- Required: Yes +- Type: string + +### Parameter: `managedRules.managedRuleSets.exclusions` + +Describes the exclusions that are applied to all rules in the set. + +- Required: No +- Type: array + +### Parameter: `managedRules.managedRuleSets.ruleGroupOverrides` + +Defines the rule group overrides to apply to the rule set. + +- Required: No +- Type: array + +### Parameter: `managedRules.managedRuleSets.ruleSetAction` + +Defines the rule set action. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Block' + 'Log' + 'Redirect' + ] + ``` + +### Parameter: `policySettings` + +The PolicySettings for policy. + +- Required: No +- Type: object +- Default: + ```Bicep + { + enabledState: 'Enabled' + mode: 'Prevention' + } + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `sku` + +The pricing tier of the WAF profile. + +- Required: No +- Type: string +- Default: `'Standard_AzureFrontDoor'` +- Allowed: + ```Bicep + [ + 'Premium_AzureFrontDoor' + 'Standard_AzureFrontDoor' + ] + ``` + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the Front Door WAF policy. | +| `resourceGroupName` | string | The resource group the Front Door WAF policy was deployed into. | +| `resourceId` | string | The resource ID of the Front Door WAF policy. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/front-door-web-application-firewall-policy/main.bicep b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/main.bicep new file mode 100644 index 000000000..0a50f8883 --- /dev/null +++ b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/main.bicep @@ -0,0 +1,267 @@ +metadata name = 'Front Door Web Application Firewall (WAF) Policies' +metadata description = 'This module deploys a Front Door Web Application Firewall (WAF) Policy.' + +@description('Required. Name of the Front Door WAF policy.') +@minLength(1) +@maxLength(128) +param name string + +@description('Optional. Location for all resources.') +param location string = 'global' + +@allowed([ + 'Standard_AzureFrontDoor' + 'Premium_AzureFrontDoor' +]) +@description('Optional. The pricing tier of the WAF profile.') +param sku string = 'Standard_AzureFrontDoor' + +@description('Optional. Resource tags.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Describes the managedRules structure.') +param managedRules managedRulesType = { + managedRuleSets: [ + { + ruleSetType: 'Microsoft_DefaultRuleSet' + ruleSetVersion: '2.1' + ruleGroupOverrides: [] + exclusions: [] + ruleSetAction: 'Block' + } + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '1.0' + ruleGroupOverrides: [] + exclusions: [] + } + ] +} + +@description('Optional. The custom rules inside the policy.') +param customRules customRulesType = { + rules: [ + { + name: 'ApplyGeoFilter' + priority: 100 + enabledState: 'Enabled' + ruleType: 'MatchRule' + action: 'Block' + matchConditions: [ + { + matchVariable: 'RemoteAddr' + operator: 'GeoMatch' + negateCondition: true + matchValue: ['ZZ'] + } + ] + } + ] +} + +@description('Optional. The PolicySettings for policy.') +param policySettings object = { + enabledState: 'Enabled' + mode: 'Prevention' +} + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-frontdoorwebappfwpolicy.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource frontDoorWAFPolicy 'Microsoft.Network/FrontDoorWebApplicationFirewallPolicies@2024-02-01' = { + name: name + location: location + sku: { + name: sku + } + tags: tags + properties: { + customRules: customRules + managedRules: sku == 'Premium_AzureFrontDoor' ? managedRules : { managedRuleSets: [] } + policySettings: policySettings + } +} + +resource frontDoorWAFPolicy_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: frontDoorWAFPolicy +} + +resource frontDoorWAFPolicy_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + frontDoorWAFPolicy.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: frontDoorWAFPolicy + } +] + +@description('The name of the Front Door WAF policy.') +output name string = frontDoorWAFPolicy.name + +@description('The resource ID of the Front Door WAF policy.') +output resourceId string = frontDoorWAFPolicy.id + +@description('The resource group the Front Door WAF policy was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = frontDoorWAFPolicy.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type managedRulesType = { + @description('Optional. List of rule sets.') + managedRuleSets: managedRuleSetsType +} + +type managedRuleSetsType = { + @description('Required. Defines the rule set type to use.') + ruleSetType: string + + @description('Required. Defines the version of the rule set to use.') + ruleSetVersion: string + + @description('Optional. Defines the rule group overrides to apply to the rule set.') + ruleGroupOverrides: array? + + @description('Optional. Describes the exclusions that are applied to all rules in the set.') + exclusions: array? + + @description('Optional. Defines the rule set action.') + ruleSetAction: 'Block' | 'Log' | 'Redirect' | null +}[]? + +type customRulesType = { + @description('Optional. List of rules.') + rules: customRulesRuleType +} + +type customRulesRuleType = { + @description('Required. Describes what action to be applied when rule matches.') + action: 'Allow' | 'Block' | 'Log' | 'Redirect' + + @description('Required. Describes if the custom rule is in enabled or disabled state.') + enabledState: 'Enabled' | 'Disabled' + + @description('Required. List of match conditions. See https://learn.microsoft.com/en-us/azure/templates/microsoft.network/frontdoorwebapplicationfirewallpolicies#matchcondition for details.') + matchConditions: array + + @description('Required. Describes the name of the rule.') + name: string + + @description('Required. Describes priority of the rule. Rules with a lower value will be evaluated before rules with a higher value.') + priority: int + + @description('Optional. Time window for resetting the rate limit count. Default is 1 minute.') + rateLimitDurationInMinutes: int? + + @description('Optional. Number of allowed requests per client within the time window.') + rateLimitThreshold: int? + + @description('Required. Describes type of rule.') + ruleType: 'MatchRule' | 'RateLimitRule' +}[]? diff --git a/avm/1.1.0/res/network/front-door-web-application-firewall-policy/main.json b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/main.json new file mode 100644 index 000000000..5f391c01c --- /dev/null +++ b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/main.json @@ -0,0 +1,489 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "6443033391235327476" + }, + "name": "Front Door Web Application Firewall (WAF) Policies", + "description": "This module deploys a Front Door Web Application Firewall (WAF) Policy." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "managedRulesType": { + "type": "object", + "properties": { + "managedRuleSets": { + "$ref": "#/definitions/managedRuleSetsType", + "metadata": { + "description": "Optional. List of rule sets." + } + } + } + }, + "managedRuleSetsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleSetType": { + "type": "string", + "metadata": { + "description": "Required. Defines the rule set type to use." + } + }, + "ruleSetVersion": { + "type": "string", + "metadata": { + "description": "Required. Defines the version of the rule set to use." + } + }, + "ruleGroupOverrides": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Defines the rule group overrides to apply to the rule set." + } + }, + "exclusions": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Describes the exclusions that are applied to all rules in the set." + } + }, + "ruleSetAction": { + "type": "string", + "allowedValues": [ + "Block", + "Log", + "Redirect" + ], + "nullable": true, + "metadata": { + "description": "Optional. Defines the rule set action." + } + } + } + }, + "nullable": true + }, + "customRulesType": { + "type": "object", + "properties": { + "rules": { + "$ref": "#/definitions/customRulesRuleType", + "metadata": { + "description": "Optional. List of rules." + } + } + } + }, + "customRulesRuleType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "action": { + "type": "string", + "allowedValues": [ + "Allow", + "Block", + "Log", + "Redirect" + ], + "metadata": { + "description": "Required. Describes what action to be applied when rule matches." + } + }, + "enabledState": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. Describes if the custom rule is in enabled or disabled state." + } + }, + "matchConditions": { + "type": "array", + "metadata": { + "description": "Required. List of match conditions. See https://learn.microsoft.com/en-us/azure/templates/microsoft.network/frontdoorwebapplicationfirewallpolicies#matchcondition for details." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Describes the name of the rule." + } + }, + "priority": { + "type": "int", + "metadata": { + "description": "Required. Describes priority of the rule. Rules with a lower value will be evaluated before rules with a higher value." + } + }, + "rateLimitDurationInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Time window for resetting the rate limit count. Default is 1 minute." + } + }, + "rateLimitThreshold": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Number of allowed requests per client within the time window." + } + }, + "ruleType": { + "type": "string", + "allowedValues": [ + "MatchRule", + "RateLimitRule" + ], + "metadata": { + "description": "Required. Describes type of rule." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "metadata": { + "description": "Required. Name of the Front Door WAF policy." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "sku": { + "type": "string", + "defaultValue": "Standard_AzureFrontDoor", + "allowedValues": [ + "Standard_AzureFrontDoor", + "Premium_AzureFrontDoor" + ], + "metadata": { + "description": "Optional. The pricing tier of the WAF profile." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "managedRules": { + "$ref": "#/definitions/managedRulesType", + "defaultValue": { + "managedRuleSets": [ + { + "ruleSetType": "Microsoft_DefaultRuleSet", + "ruleSetVersion": "2.1", + "ruleGroupOverrides": [], + "exclusions": [], + "ruleSetAction": "Block" + }, + { + "ruleSetType": "Microsoft_BotManagerRuleSet", + "ruleSetVersion": "1.0", + "ruleGroupOverrides": [], + "exclusions": [] + } + ] + }, + "metadata": { + "description": "Optional. Describes the managedRules structure." + } + }, + "customRules": { + "$ref": "#/definitions/customRulesType", + "defaultValue": { + "rules": [ + { + "name": "ApplyGeoFilter", + "priority": 100, + "enabledState": "Enabled", + "ruleType": "MatchRule", + "action": "Block", + "matchConditions": [ + { + "matchVariable": "RemoteAddr", + "operator": "GeoMatch", + "negateCondition": true, + "matchValue": [ + "ZZ" + ] + } + ] + } + ] + }, + "metadata": { + "description": "Optional. The custom rules inside the policy." + } + }, + "policySettings": { + "type": "object", + "defaultValue": { + "enabledState": "Enabled", + "mode": "Prevention" + }, + "metadata": { + "description": "Optional. The PolicySettings for policy." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-frontdoorwebappfwpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "frontDoorWAFPolicy": { + "type": "Microsoft.Network/FrontDoorWebApplicationFirewallPolicies", + "apiVersion": "2024-02-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('sku')]" + }, + "tags": "[parameters('tags')]", + "properties": { + "customRules": "[parameters('customRules')]", + "managedRules": "[if(equals(parameters('sku'), 'Premium_AzureFrontDoor'), parameters('managedRules'), createObject('managedRuleSets', createArray()))]", + "policySettings": "[parameters('policySettings')]" + } + }, + "frontDoorWAFPolicy_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/FrontDoorWebApplicationFirewallPolicies/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "frontDoorWAFPolicy" + ] + }, + "frontDoorWAFPolicy_roleAssignments": { + "copy": { + "name": "frontDoorWAFPolicy_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/FrontDoorWebApplicationFirewallPolicies/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/FrontDoorWebApplicationFirewallPolicies', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "frontDoorWAFPolicy" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Front Door WAF policy." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Front Door WAF policy." + }, + "value": "[resourceId('Microsoft.Network/FrontDoorWebApplicationFirewallPolicies', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Front Door WAF policy was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('frontDoorWAFPolicy', '2024-02-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..7d3521080 --- /dev/null +++ b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.frontdoorWebApplicationFirewallPolicies-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nagwafpmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7b3d4e8fb --- /dev/null +++ b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..e513fcbed --- /dev/null +++ b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/max/main.test.bicep @@ -0,0 +1,151 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.frontdoorWebApplicationFirewallPolicies-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nagwafpmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + sku: 'Premium_AzureFrontDoor' + policySettings: { + mode: 'Prevention' + redirectUrl: 'http://www.bing.com' + customBlockResponseStatusCode: 200 + customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==' + } + customRules: { + rules: [ + { + name: 'CustomRule1' + priority: 2 + enabledState: 'Enabled' + action: 'Block' + ruleType: 'MatchRule' + rateLimitDurationInMinutes: 1 + rateLimitThreshold: 10 + matchConditions: [ + { + matchVariable: 'RemoteAddr' + selector: null + operator: 'GeoMatch' + negateCondition: false + transforms: [] + matchValue: [ + 'CH' + ] + } + { + matchVariable: 'RequestHeader' + selector: 'UserAgent' + operator: 'Contains' + negateCondition: false + transforms: [] + matchValue: [ + 'windows' + ] + } + { + matchVariable: 'QueryString' + operator: 'Contains' + negateCondition: false + transforms: [ + 'UrlDecode' + 'Lowercase' + ] + matchValue: [ + '' + ] + } + ] + } + ] + } + managedRules: { + managedRuleSets: [ + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '1.0' + } + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + roleAssignments: [ + { + name: 'bb049c96-2571-4a25-b760-444ab25d86ed' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..ecbe09e12 --- /dev/null +++ b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,116 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.frontdoorWebApplicationFirewallPolicies-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nagwafpwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + sku: 'Premium_AzureFrontDoor' + policySettings: { + mode: 'Prevention' + redirectUrl: 'http://www.bing.com' + customBlockResponseStatusCode: 200 + customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==' + } + customRules: { + rules: [ + { + name: 'CustomRule1' + priority: 2 + enabledState: 'Enabled' + action: 'Block' + ruleType: 'MatchRule' + rateLimitDurationInMinutes: 1 + rateLimitThreshold: 10 + matchConditions: [ + { + matchVariable: 'RemoteAddr' + selector: null + operator: 'GeoMatch' + negateCondition: false + transforms: [] + matchValue: [ + 'CH' + ] + } + { + matchVariable: 'RequestHeader' + selector: 'UserAgent' + operator: 'Contains' + negateCondition: false + transforms: [] + matchValue: [ + 'windows' + ] + } + { + matchVariable: 'QueryString' + operator: 'Contains' + negateCondition: false + transforms: [ + 'UrlDecode' + 'Lowercase' + ] + matchValue: [ + '' + ] + } + ] + } + ] + } + managedRules: { + managedRuleSets: [ + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '1.0' + } + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/front-door-web-application-firewall-policy/version.json b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/version.json new file mode 100644 index 000000000..c177b1bb5 --- /dev/null +++ b/avm/1.1.0/res/network/front-door-web-application-firewall-policy/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/front-door/README.md b/avm/1.1.0/res/network/front-door/README.md new file mode 100644 index 000000000..443abc845 --- /dev/null +++ b/avm/1.1.0/res/network/front-door/README.md @@ -0,0 +1,1643 @@ +# Azure Front Doors `[Microsoft.Network/frontDoors]` + +This module deploys an Azure Front Door. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/frontDoors` | [2021-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2021-06-01/frontDoors) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/front-door:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module frontDoor 'br/public:avm/res/network/front-door:' = { + name: 'frontDoorDeployment' + params: { + // Required parameters + backendPools: [ + { + name: 'backendPool' + properties: { + backends: [ + { + address: 'biceptest.local' + backendHostHeader: 'backendAddress' + enabledState: 'Enabled' + httpPort: 80 + httpsPort: 443 + priority: 1 + weight: 50 + } + ] + HealthProbeSettings: { + id: '' + } + LoadBalancingSettings: { + id: '' + } + } + } + ] + frontendEndpoints: [ + { + name: 'frontEnd' + properties: { + hostName: '' + sessionAffinityEnabledState: 'Disabled' + sessionAffinityTtlSeconds: 60 + } + } + ] + healthProbeSettings: [ + { + name: 'heathProbe' + properties: { + intervalInSeconds: 60 + path: '/' + protocol: 'Https' + } + } + ] + loadBalancingSettings: [ + { + name: 'loadBalancer' + properties: { + additionalLatencyMilliseconds: 0 + sampleSize: 50 + successfulSamplesRequired: 1 + } + } + ] + name: '' + routingRules: [ + { + name: 'routingRule' + properties: { + acceptedProtocols: [ + 'Https' + ] + enabledState: 'Enabled' + frontendEndpoints: [ + { + id: '' + } + ] + patternsToMatch: [ + '/*' + ] + routeConfiguration: { + '@odata.type': '#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration' + backendPool: { + id: '' + } + } + } + } + ] + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "backendPools": { + "value": [ + { + "name": "backendPool", + "properties": { + "backends": [ + { + "address": "biceptest.local", + "backendHostHeader": "backendAddress", + "enabledState": "Enabled", + "httpPort": 80, + "httpsPort": 443, + "priority": 1, + "weight": 50 + } + ], + "HealthProbeSettings": { + "id": "" + }, + "LoadBalancingSettings": { + "id": "" + } + } + } + ] + }, + "frontendEndpoints": { + "value": [ + { + "name": "frontEnd", + "properties": { + "hostName": "", + "sessionAffinityEnabledState": "Disabled", + "sessionAffinityTtlSeconds": 60 + } + } + ] + }, + "healthProbeSettings": { + "value": [ + { + "name": "heathProbe", + "properties": { + "intervalInSeconds": 60, + "path": "/", + "protocol": "Https" + } + } + ] + }, + "loadBalancingSettings": { + "value": [ + { + "name": "loadBalancer", + "properties": { + "additionalLatencyMilliseconds": 0, + "sampleSize": 50, + "successfulSamplesRequired": 1 + } + } + ] + }, + "name": { + "value": "" + }, + "routingRules": { + "value": [ + { + "name": "routingRule", + "properties": { + "acceptedProtocols": [ + "Https" + ], + "enabledState": "Enabled", + "frontendEndpoints": [ + { + "id": "" + } + ], + "patternsToMatch": [ + "/*" + ], + "routeConfiguration": { + "@odata.type": "#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration", + "backendPool": { + "id": "" + } + } + } + } + ] + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/front-door:' + +// Required parameters +param backendPools = [ + { + name: 'backendPool' + properties: { + backends: [ + { + address: 'biceptest.local' + backendHostHeader: 'backendAddress' + enabledState: 'Enabled' + httpPort: 80 + httpsPort: 443 + priority: 1 + weight: 50 + } + ] + HealthProbeSettings: { + id: '' + } + LoadBalancingSettings: { + id: '' + } + } + } +] +param frontendEndpoints = [ + { + name: 'frontEnd' + properties: { + hostName: '' + sessionAffinityEnabledState: 'Disabled' + sessionAffinityTtlSeconds: 60 + } + } +] +param healthProbeSettings = [ + { + name: 'heathProbe' + properties: { + intervalInSeconds: 60 + path: '/' + protocol: 'Https' + } + } +] +param loadBalancingSettings = [ + { + name: 'loadBalancer' + properties: { + additionalLatencyMilliseconds: 0 + sampleSize: 50 + successfulSamplesRequired: 1 + } + } +] +param name = '' +param routingRules = [ + { + name: 'routingRule' + properties: { + acceptedProtocols: [ + 'Https' + ] + enabledState: 'Enabled' + frontendEndpoints: [ + { + id: '' + } + ] + patternsToMatch: [ + '/*' + ] + routeConfiguration: { + '@odata.type': '#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration' + backendPool: { + id: '' + } + } + } + } +] +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module frontDoor 'br/public:avm/res/network/front-door:' = { + name: 'frontDoorDeployment' + params: { + // Required parameters + backendPools: [ + { + name: 'backendPool' + properties: { + backends: [ + { + address: 'biceptest.local' + backendHostHeader: 'backendAddress' + enabledState: 'Enabled' + httpPort: 80 + httpsPort: 443 + priority: 1 + privateLinkAlias: '' + privateLinkApprovalMessage: '' + privateLinkLocation: '' + weight: 50 + } + ] + HealthProbeSettings: { + id: '' + } + LoadBalancingSettings: { + id: '' + } + } + } + ] + frontendEndpoints: [ + { + name: 'frontEnd' + properties: { + hostName: '' + sessionAffinityEnabledState: 'Disabled' + sessionAffinityTtlSeconds: 60 + } + } + ] + healthProbeSettings: [ + { + name: 'heathProbe' + properties: { + enabledState: '' + healthProbeMethod: '' + intervalInSeconds: 60 + path: '/' + protocol: 'Https' + } + } + ] + loadBalancingSettings: [ + { + name: 'loadBalancer' + properties: { + additionalLatencyMilliseconds: 0 + sampleSize: 50 + successfulSamplesRequired: 1 + } + } + ] + name: '' + routingRules: [ + { + name: 'routingRule' + properties: { + acceptedProtocols: [ + 'Http' + 'Https' + ] + enabledState: 'Enabled' + frontendEndpoints: [ + { + id: '' + } + ] + patternsToMatch: [ + '/*' + ] + routeConfiguration: { + '@odata.type': '#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration' + backendPool: { + id: '' + } + forwardingProtocol: 'MatchRequest' + } + } + } + ] + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'FrontdoorAccessLog' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + enforceCertificateNameCheck: 'Disabled' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'b2c1ef5f-3422-4a49-8e55-7789fe980b64' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + sendRecvTimeoutSeconds: 10 + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "backendPools": { + "value": [ + { + "name": "backendPool", + "properties": { + "backends": [ + { + "address": "biceptest.local", + "backendHostHeader": "backendAddress", + "enabledState": "Enabled", + "httpPort": 80, + "httpsPort": 443, + "priority": 1, + "privateLinkAlias": "", + "privateLinkApprovalMessage": "", + "privateLinkLocation": "", + "weight": 50 + } + ], + "HealthProbeSettings": { + "id": "" + }, + "LoadBalancingSettings": { + "id": "" + } + } + } + ] + }, + "frontendEndpoints": { + "value": [ + { + "name": "frontEnd", + "properties": { + "hostName": "", + "sessionAffinityEnabledState": "Disabled", + "sessionAffinityTtlSeconds": 60 + } + } + ] + }, + "healthProbeSettings": { + "value": [ + { + "name": "heathProbe", + "properties": { + "enabledState": "", + "healthProbeMethod": "", + "intervalInSeconds": 60, + "path": "/", + "protocol": "Https" + } + } + ] + }, + "loadBalancingSettings": { + "value": [ + { + "name": "loadBalancer", + "properties": { + "additionalLatencyMilliseconds": 0, + "sampleSize": 50, + "successfulSamplesRequired": 1 + } + } + ] + }, + "name": { + "value": "" + }, + "routingRules": { + "value": [ + { + "name": "routingRule", + "properties": { + "acceptedProtocols": [ + "Http", + "Https" + ], + "enabledState": "Enabled", + "frontendEndpoints": [ + { + "id": "" + } + ], + "patternsToMatch": [ + "/*" + ], + "routeConfiguration": { + "@odata.type": "#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration", + "backendPool": { + "id": "" + }, + "forwardingProtocol": "MatchRequest" + } + } + } + ] + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "logCategoriesAndGroups": [ + { + "category": "FrontdoorAccessLog" + } + ], + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "enforceCertificateNameCheck": { + "value": "Disabled" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "b2c1ef5f-3422-4a49-8e55-7789fe980b64", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "sendRecvTimeoutSeconds": { + "value": 10 + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/front-door:' + +// Required parameters +param backendPools = [ + { + name: 'backendPool' + properties: { + backends: [ + { + address: 'biceptest.local' + backendHostHeader: 'backendAddress' + enabledState: 'Enabled' + httpPort: 80 + httpsPort: 443 + priority: 1 + privateLinkAlias: '' + privateLinkApprovalMessage: '' + privateLinkLocation: '' + weight: 50 + } + ] + HealthProbeSettings: { + id: '' + } + LoadBalancingSettings: { + id: '' + } + } + } +] +param frontendEndpoints = [ + { + name: 'frontEnd' + properties: { + hostName: '' + sessionAffinityEnabledState: 'Disabled' + sessionAffinityTtlSeconds: 60 + } + } +] +param healthProbeSettings = [ + { + name: 'heathProbe' + properties: { + enabledState: '' + healthProbeMethod: '' + intervalInSeconds: 60 + path: '/' + protocol: 'Https' + } + } +] +param loadBalancingSettings = [ + { + name: 'loadBalancer' + properties: { + additionalLatencyMilliseconds: 0 + sampleSize: 50 + successfulSamplesRequired: 1 + } + } +] +param name = '' +param routingRules = [ + { + name: 'routingRule' + properties: { + acceptedProtocols: [ + 'Http' + 'Https' + ] + enabledState: 'Enabled' + frontendEndpoints: [ + { + id: '' + } + ] + patternsToMatch: [ + '/*' + ] + routeConfiguration: { + '@odata.type': '#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration' + backendPool: { + id: '' + } + forwardingProtocol: 'MatchRequest' + } + } + } +] +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'FrontdoorAccessLog' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enforceCertificateNameCheck = 'Disabled' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'b2c1ef5f-3422-4a49-8e55-7789fe980b64' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sendRecvTimeoutSeconds = 10 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module frontDoor 'br/public:avm/res/network/front-door:' = { + name: 'frontDoorDeployment' + params: { + // Required parameters + backendPools: [ + { + name: 'backendPool' + properties: { + backends: [ + { + address: 'biceptest.local' + backendHostHeader: 'backendAddress' + enabledState: 'Enabled' + httpPort: 80 + httpsPort: 443 + priority: 1 + privateLinkAlias: '' + privateLinkApprovalMessage: '' + privateLinkLocation: '' + weight: 50 + } + ] + HealthProbeSettings: { + id: '' + } + LoadBalancingSettings: { + id: '' + } + } + } + ] + frontendEndpoints: [ + { + name: 'frontEnd' + properties: { + hostName: '' + sessionAffinityEnabledState: 'Disabled' + sessionAffinityTtlSeconds: 60 + } + } + ] + healthProbeSettings: [ + { + name: 'heathProbe' + properties: { + enabledState: 'Enabled' + healthProbeMethod: 'HEAD' + intervalInSeconds: 60 + path: '/healthz' + protocol: 'Https' + } + } + ] + loadBalancingSettings: [ + { + name: 'loadBalancer' + properties: { + additionalLatencyMilliseconds: 0 + sampleSize: 50 + successfulSamplesRequired: 1 + } + } + ] + name: '' + routingRules: [ + { + name: 'routingRule' + properties: { + acceptedProtocols: [ + 'Http' + 'Https' + ] + enabledState: 'Enabled' + frontendEndpoints: [ + { + id: '' + } + ] + patternsToMatch: [ + '/*' + ] + routeConfiguration: { + '@odata.type': '#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration' + backendPool: { + id: '' + } + forwardingProtocol: 'MatchRequest' + } + } + } + ] + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + enforceCertificateNameCheck: 'Disabled' + location: '' + sendRecvTimeoutSeconds: 10 + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "backendPools": { + "value": [ + { + "name": "backendPool", + "properties": { + "backends": [ + { + "address": "biceptest.local", + "backendHostHeader": "backendAddress", + "enabledState": "Enabled", + "httpPort": 80, + "httpsPort": 443, + "priority": 1, + "privateLinkAlias": "", + "privateLinkApprovalMessage": "", + "privateLinkLocation": "", + "weight": 50 + } + ], + "HealthProbeSettings": { + "id": "" + }, + "LoadBalancingSettings": { + "id": "" + } + } + } + ] + }, + "frontendEndpoints": { + "value": [ + { + "name": "frontEnd", + "properties": { + "hostName": "", + "sessionAffinityEnabledState": "Disabled", + "sessionAffinityTtlSeconds": 60 + } + } + ] + }, + "healthProbeSettings": { + "value": [ + { + "name": "heathProbe", + "properties": { + "enabledState": "Enabled", + "healthProbeMethod": "HEAD", + "intervalInSeconds": 60, + "path": "/healthz", + "protocol": "Https" + } + } + ] + }, + "loadBalancingSettings": { + "value": [ + { + "name": "loadBalancer", + "properties": { + "additionalLatencyMilliseconds": 0, + "sampleSize": 50, + "successfulSamplesRequired": 1 + } + } + ] + }, + "name": { + "value": "" + }, + "routingRules": { + "value": [ + { + "name": "routingRule", + "properties": { + "acceptedProtocols": [ + "Http", + "Https" + ], + "enabledState": "Enabled", + "frontendEndpoints": [ + { + "id": "" + } + ], + "patternsToMatch": [ + "/*" + ], + "routeConfiguration": { + "@odata.type": "#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration", + "backendPool": { + "id": "" + }, + "forwardingProtocol": "MatchRequest" + } + } + } + ] + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "enforceCertificateNameCheck": { + "value": "Disabled" + }, + "location": { + "value": "" + }, + "sendRecvTimeoutSeconds": { + "value": 10 + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/front-door:' + +// Required parameters +param backendPools = [ + { + name: 'backendPool' + properties: { + backends: [ + { + address: 'biceptest.local' + backendHostHeader: 'backendAddress' + enabledState: 'Enabled' + httpPort: 80 + httpsPort: 443 + priority: 1 + privateLinkAlias: '' + privateLinkApprovalMessage: '' + privateLinkLocation: '' + weight: 50 + } + ] + HealthProbeSettings: { + id: '' + } + LoadBalancingSettings: { + id: '' + } + } + } +] +param frontendEndpoints = [ + { + name: 'frontEnd' + properties: { + hostName: '' + sessionAffinityEnabledState: 'Disabled' + sessionAffinityTtlSeconds: 60 + } + } +] +param healthProbeSettings = [ + { + name: 'heathProbe' + properties: { + enabledState: 'Enabled' + healthProbeMethod: 'HEAD' + intervalInSeconds: 60 + path: '/healthz' + protocol: 'Https' + } + } +] +param loadBalancingSettings = [ + { + name: 'loadBalancer' + properties: { + additionalLatencyMilliseconds: 0 + sampleSize: 50 + successfulSamplesRequired: 1 + } + } +] +param name = '' +param routingRules = [ + { + name: 'routingRule' + properties: { + acceptedProtocols: [ + 'Http' + 'Https' + ] + enabledState: 'Enabled' + frontendEndpoints: [ + { + id: '' + } + ] + patternsToMatch: [ + '/*' + ] + routeConfiguration: { + '@odata.type': '#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration' + backendPool: { + id: '' + } + forwardingProtocol: 'MatchRequest' + } + } + } +] +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enforceCertificateNameCheck = 'Disabled' +param location = '' +param sendRecvTimeoutSeconds = 10 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backendPools`](#parameter-backendpools) | array | Backend address pool of the frontdoor resource. | +| [`frontendEndpoints`](#parameter-frontendendpoints) | array | Frontend endpoints of the frontdoor resource. | +| [`healthProbeSettings`](#parameter-healthprobesettings) | array | Heath probe settings of the frontdoor resource. | +| [`loadBalancingSettings`](#parameter-loadbalancingsettings) | array | Load balancing settings of the frontdoor resource. | +| [`name`](#parameter-name) | string | The name of the frontDoor. | +| [`routingRules`](#parameter-routingrules) | array | Routing rules settings of the frontdoor resource. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enabledState`](#parameter-enabledstate) | string | State of the frontdoor resource. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`enforceCertificateNameCheck`](#parameter-enforcecertificatenamecheck) | string | Enforce certificate name check of the frontdoor resource. | +| [`friendlyName`](#parameter-friendlyname) | string | Friendly name of the frontdoor resource. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`sendRecvTimeoutSeconds`](#parameter-sendrecvtimeoutseconds) | int | Certificate name check time of the frontdoor resource. | +| [`tags`](#parameter-tags) | object | Resource tags. | + +### Parameter: `backendPools` + +Backend address pool of the frontdoor resource. + +- Required: Yes +- Type: array + +### Parameter: `frontendEndpoints` + +Frontend endpoints of the frontdoor resource. + +- Required: Yes +- Type: array + +### Parameter: `healthProbeSettings` + +Heath probe settings of the frontdoor resource. + +- Required: Yes +- Type: array + +### Parameter: `loadBalancingSettings` + +Load balancing settings of the frontdoor resource. + +- Required: Yes +- Type: array + +### Parameter: `name` + +The name of the frontDoor. + +- Required: Yes +- Type: string + +### Parameter: `routingRules` + +Routing rules settings of the frontdoor resource. + +- Required: Yes +- Type: array + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enabledState` + +State of the frontdoor resource. + +- Required: No +- Type: string +- Default: `'Enabled'` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enforceCertificateNameCheck` + +Enforce certificate name check of the frontdoor resource. + +- Required: No +- Type: string +- Default: `'Disabled'` + +### Parameter: `friendlyName` + +Friendly name of the frontdoor resource. + +- Required: No +- Type: string + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `sendRecvTimeoutSeconds` + +Certificate name check time of the frontdoor resource. + +- Required: No +- Type: int +- Default: `240` +- MaxValue: 240 + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object +- MaxValue: 240 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the front door. | +| `resourceGroupName` | string | The resource group the front door was deployed into. | +| `resourceId` | string | The resource ID of the front door. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/front-door/main.bicep b/avm/1.1.0/res/network/front-door/main.bicep new file mode 100644 index 000000000..eed09a685 --- /dev/null +++ b/avm/1.1.0/res/network/front-door/main.bicep @@ -0,0 +1,267 @@ +metadata name = 'Azure Front Doors' +metadata description = 'This module deploys an Azure Front Door.' + +@description('Required. The name of the frontDoor.') +@minLength(5) +@maxLength(64) +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Resource tags.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Required. Backend address pool of the frontdoor resource.') +param backendPools array + +@description('Optional. Enforce certificate name check of the frontdoor resource.') +param enforceCertificateNameCheck string = 'Disabled' + +@description('Optional. Certificate name check time of the frontdoor resource.') +@maxValue(240) +param sendRecvTimeoutSeconds int = 240 + +@description('Optional. State of the frontdoor resource.') +param enabledState string = 'Enabled' + +@description('Optional. Friendly name of the frontdoor resource.') +param friendlyName string? + +@description('Required. Frontend endpoints of the frontdoor resource.') +param frontendEndpoints array + +@description('Required. Heath probe settings of the frontdoor resource.') +param healthProbeSettings array + +@description('Required. Load balancing settings of the frontdoor resource.') +param loadBalancingSettings array + +@description('Required. Routing rules settings of the frontdoor resource.') +param routingRules array + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-frontdoor.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource frontDoor 'Microsoft.Network/frontDoors@2021-06-01' = { + name: name + location: 'global' + tags: tags + properties: { + backendPools: backendPools + backendPoolsSettings: { + enforceCertificateNameCheck: enforceCertificateNameCheck + sendRecvTimeoutSeconds: sendRecvTimeoutSeconds + } + enabledState: enabledState + friendlyName: friendlyName ?? '' + frontendEndpoints: frontendEndpoints + healthProbeSettings: healthProbeSettings + loadBalancingSettings: loadBalancingSettings + routingRules: routingRules + } +} + +resource frontDoor_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: frontDoor +} + +resource frontDoor_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: frontDoor + } +] + +resource frontDoor_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(frontDoor.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: frontDoor + } +] + +@description('The name of the front door.') +output name string = frontDoor.name + +@description('The resource ID of the front door.') +output resourceId string = frontDoor.id + +@description('The resource group the front door was deployed into.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/front-door/main.json b/avm/1.1.0/res/network/front-door/main.json new file mode 100644 index 000000000..a395192a9 --- /dev/null +++ b/avm/1.1.0/res/network/front-door/main.json @@ -0,0 +1,501 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15109325313185095632" + }, + "name": "Azure Front Doors", + "description": "This module deploys an Azure Front Door." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 5, + "maxLength": 64, + "metadata": { + "description": "Required. The name of the frontDoor." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "backendPools": { + "type": "array", + "metadata": { + "description": "Required. Backend address pool of the frontdoor resource." + } + }, + "enforceCertificateNameCheck": { + "type": "string", + "defaultValue": "Disabled", + "metadata": { + "description": "Optional. Enforce certificate name check of the frontdoor resource." + } + }, + "sendRecvTimeoutSeconds": { + "type": "int", + "defaultValue": 240, + "maxValue": 240, + "metadata": { + "description": "Optional. Certificate name check time of the frontdoor resource." + } + }, + "enabledState": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Optional. State of the frontdoor resource." + } + }, + "friendlyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Friendly name of the frontdoor resource." + } + }, + "frontendEndpoints": { + "type": "array", + "metadata": { + "description": "Required. Frontend endpoints of the frontdoor resource." + } + }, + "healthProbeSettings": { + "type": "array", + "metadata": { + "description": "Required. Heath probe settings of the frontdoor resource." + } + }, + "loadBalancingSettings": { + "type": "array", + "metadata": { + "description": "Required. Load balancing settings of the frontdoor resource." + } + }, + "routingRules": { + "type": "array", + "metadata": { + "description": "Required. Routing rules settings of the frontdoor resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-frontdoor.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "frontDoor": { + "type": "Microsoft.Network/frontDoors", + "apiVersion": "2021-06-01", + "name": "[parameters('name')]", + "location": "global", + "tags": "[parameters('tags')]", + "properties": { + "backendPools": "[parameters('backendPools')]", + "backendPoolsSettings": { + "enforceCertificateNameCheck": "[parameters('enforceCertificateNameCheck')]", + "sendRecvTimeoutSeconds": "[parameters('sendRecvTimeoutSeconds')]" + }, + "enabledState": "[parameters('enabledState')]", + "friendlyName": "[coalesce(parameters('friendlyName'), '')]", + "frontendEndpoints": "[parameters('frontendEndpoints')]", + "healthProbeSettings": "[parameters('healthProbeSettings')]", + "loadBalancingSettings": "[parameters('loadBalancingSettings')]", + "routingRules": "[parameters('routingRules')]" + } + }, + "frontDoor_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/frontDoors/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "frontDoor" + ] + }, + "frontDoor_diagnosticSettings": { + "copy": { + "name": "frontDoor_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/frontDoors/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "frontDoor" + ] + }, + "frontDoor_roleAssignments": { + "copy": { + "name": "frontDoor_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/frontDoors/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/frontDoors', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "frontDoor" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the front door." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the front door." + }, + "value": "[resourceId('Microsoft.Network/frontDoors', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the front door was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/front-door/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/front-door/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..fc0f9d4be --- /dev/null +++ b/avm/1.1.0/res/network/front-door/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,127 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.frontdoors-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nfdmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // +var resourceName = '${namePrefix}${serviceShort}001' +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: resourceName + location: resourceLocation + frontendEndpoints: [ + { + name: 'frontEnd' + properties: { + hostName: '${resourceName}.${environment().suffixes.azureFrontDoorEndpointSuffix}' + sessionAffinityEnabledState: 'Disabled' + sessionAffinityTtlSeconds: 60 + } + } + ] + healthProbeSettings: [ + { + name: 'heathProbe' + properties: { + intervalInSeconds: 60 + path: '/' + protocol: 'Https' + } + } + ] + loadBalancingSettings: [ + { + name: 'loadBalancer' + properties: { + additionalLatencyMilliseconds: 0 + sampleSize: 50 + successfulSamplesRequired: 1 + } + } + ] + routingRules: [ + { + name: 'routingRule' + properties: { + acceptedProtocols: [ + 'Https' + ] + enabledState: 'Enabled' + frontendEndpoints: [ + { + id: '${resourceGroup.id}/providers/Microsoft.Network/frontDoors/${resourceName}/FrontendEndpoints/frontEnd' + } + ] + patternsToMatch: [ + '/*' + ] + routeConfiguration: { + '@odata.type': '#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration' + backendPool: { + id: '${resourceGroup.id}/providers/Microsoft.Network/frontDoors/${resourceName}/BackendPools/backendPool' + } + } + } + } + ] + backendPools: [ + { + name: 'backendPool' + properties: { + backends: [ + { + address: 'biceptest.local' + backendHostHeader: 'backendAddress' + enabledState: 'Enabled' + httpPort: 80 + httpsPort: 443 + priority: 1 + weight: 50 + } + ] + HealthProbeSettings: { + id: '${resourceGroup.id}/providers/Microsoft.Network/frontDoors/${resourceName}/HealthProbeSettings/heathProbe' + } + LoadBalancingSettings: { + id: '${resourceGroup.id}/providers/Microsoft.Network/frontDoors/${resourceName}/LoadBalancingSettings/loadBalancer' + } + } + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/front-door/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/front-door/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/network/front-door/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/front-door/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/front-door/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..ffa8339a7 --- /dev/null +++ b/avm/1.1.0/res/network/front-door/tests/e2e/max/main.test.bicep @@ -0,0 +1,209 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.frontdoors-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nfdmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // +var resourceName = '${namePrefix}${serviceShort}001' +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: resourceName + location: resourceLocation + backendPools: [ + { + name: 'backendPool' + properties: { + backends: [ + { + address: 'biceptest.local' + backendHostHeader: 'backendAddress' + enabledState: 'Enabled' + httpPort: 80 + httpsPort: 443 + priority: 1 + privateLinkAlias: '' + privateLinkApprovalMessage: '' + privateLinkLocation: '' + weight: 50 + } + ] + HealthProbeSettings: { + id: '${resourceGroup.id}/providers/Microsoft.Network/frontDoors/${resourceName}/HealthProbeSettings/heathProbe' + } + LoadBalancingSettings: { + id: '${resourceGroup.id}/providers/Microsoft.Network/frontDoors/${resourceName}/LoadBalancingSettings/loadBalancer' + } + } + } + ] + enforceCertificateNameCheck: 'Disabled' + frontendEndpoints: [ + { + name: 'frontEnd' + properties: { + hostName: '${resourceName}.${environment().suffixes.azureFrontDoorEndpointSuffix}' + sessionAffinityEnabledState: 'Disabled' + sessionAffinityTtlSeconds: 60 + } + } + ] + healthProbeSettings: [ + { + name: 'heathProbe' + properties: { + enabledState: '' + healthProbeMethod: '' + intervalInSeconds: 60 + path: '/' + protocol: 'Https' + } + } + ] + loadBalancingSettings: [ + { + name: 'loadBalancer' + properties: { + additionalLatencyMilliseconds: 0 + sampleSize: 50 + successfulSamplesRequired: 1 + } + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + routingRules: [ + { + name: 'routingRule' + properties: { + acceptedProtocols: [ + 'Http' + 'Https' + ] + enabledState: 'Enabled' + frontendEndpoints: [ + { + id: '${resourceGroup.id}/providers/Microsoft.Network/frontDoors/${resourceName}/FrontendEndpoints/frontEnd' + } + ] + patternsToMatch: [ + '/*' + ] + routeConfiguration: { + '@odata.type': '#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration' + backendPool: { + id: '${resourceGroup.id}/providers/Microsoft.Network/frontDoors/${resourceName}/BackendPools/backendPool' + } + forwardingProtocol: 'MatchRequest' + } + } + } + ] + sendRecvTimeoutSeconds: 10 + roleAssignments: [ + { + name: 'b2c1ef5f-3422-4a49-8e55-7789fe980b64' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + logCategoriesAndGroups: [ + { + category: 'FrontdoorAccessLog' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/front-door/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/front-door/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..dcd573148 --- /dev/null +++ b/avm/1.1.0/res/network/front-door/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,163 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.frontdoors-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nfdwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// Diagnostics +// ============ +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // +var resourceName = '${namePrefix}${serviceShort}001' +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: resourceName + location: resourceLocation + backendPools: [ + { + name: 'backendPool' + properties: { + backends: [ + { + address: 'biceptest.local' + backendHostHeader: 'backendAddress' + enabledState: 'Enabled' + httpPort: 80 + httpsPort: 443 + priority: 1 + privateLinkAlias: '' + privateLinkApprovalMessage: '' + privateLinkLocation: '' + weight: 50 + } + ] + HealthProbeSettings: { + id: '${resourceGroup.id}/providers/Microsoft.Network/frontDoors/${resourceName}/HealthProbeSettings/heathProbe' + } + LoadBalancingSettings: { + id: '${resourceGroup.id}/providers/Microsoft.Network/frontDoors/${resourceName}/LoadBalancingSettings/loadBalancer' + } + } + } + ] + enforceCertificateNameCheck: 'Disabled' + frontendEndpoints: [ + { + name: 'frontEnd' + properties: { + hostName: '${resourceName}.${environment().suffixes.azureFrontDoorEndpointSuffix}' + sessionAffinityEnabledState: 'Disabled' + sessionAffinityTtlSeconds: 60 + } + } + ] + healthProbeSettings: [ + { + name: 'heathProbe' + properties: { + enabledState: 'Enabled' + healthProbeMethod: 'HEAD' + intervalInSeconds: 60 + path: '/healthz' + protocol: 'Https' + } + } + ] + loadBalancingSettings: [ + { + name: 'loadBalancer' + properties: { + additionalLatencyMilliseconds: 0 + sampleSize: 50 + successfulSamplesRequired: 1 + } + } + ] + routingRules: [ + { + name: 'routingRule' + properties: { + acceptedProtocols: [ + 'Http' + 'Https' + ] + enabledState: 'Enabled' + frontendEndpoints: [ + { + id: '${resourceGroup.id}/providers/Microsoft.Network/frontDoors/${resourceName}/FrontendEndpoints/frontEnd' + } + ] + patternsToMatch: [ + '/*' + ] + routeConfiguration: { + '@odata.type': '#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration' + backendPool: { + id: '${resourceGroup.id}/providers/Microsoft.Network/frontDoors/${resourceName}/BackendPools/backendPool' + } + forwardingProtocol: 'MatchRequest' + } + } + } + ] + sendRecvTimeoutSeconds: 10 + diagnosticSettings: [ + { + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/front-door/version.json b/avm/1.1.0/res/network/front-door/version.json new file mode 100644 index 000000000..c177b1bb5 --- /dev/null +++ b/avm/1.1.0/res/network/front-door/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/ip-group/README.md b/avm/1.1.0/res/network/ip-group/README.md new file mode 100644 index 000000000..d8c0ac67b --- /dev/null +++ b/avm/1.1.0/res/network/ip-group/README.md @@ -0,0 +1,568 @@ +# IP Groups `[Microsoft.Network/ipGroups]` + +This module deploys an IP Group. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/ipGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/ipGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/ip-group:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module ipGroup 'br/public:avm/res/network/ip-group:' = { + name: 'ipGroupDeployment' + params: { + // Required parameters + name: 'nigmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nigmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/ip-group:' + +// Required parameters +param name = 'nigmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module ipGroup 'br/public:avm/res/network/ip-group:' = { + name: 'ipGroupDeployment' + params: { + // Required parameters + name: 'nigmax001' + // Non-required parameters + ipAddresses: [ + '10.0.0.1' + '10.0.0.2' + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '26438d40-c8be-4229-ba65-800cf4e49dc8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nigmax001" + }, + // Non-required parameters + "ipAddresses": { + "value": [ + "10.0.0.1", + "10.0.0.2" + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "26438d40-c8be-4229-ba65-800cf4e49dc8", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/ip-group:' + +// Required parameters +param name = 'nigmax001' +// Non-required parameters +param ipAddresses = [ + '10.0.0.1' + '10.0.0.2' +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '26438d40-c8be-4229-ba65-800cf4e49dc8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module ipGroup 'br/public:avm/res/network/ip-group:' = { + name: 'ipGroupDeployment' + params: { + // Required parameters + name: 'nigwaf001' + // Non-required parameters + ipAddresses: [ + '10.0.0.1' + '10.0.0.2' + ] + location: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nigwaf001" + }, + // Non-required parameters + "ipAddresses": { + "value": [ + "10.0.0.1", + "10.0.0.2" + ] + }, + "location": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/ip-group:' + +// Required parameters +param name = 'nigwaf001' +// Non-required parameters +param ipAddresses = [ + '10.0.0.1' + '10.0.0.2' +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the IP Group. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`ipAddresses`](#parameter-ipaddresses) | array | IpAddresses/IpAddressPrefixes in the IP Group resource. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Resource tags. | + +### Parameter: `name` + +The name of the IP Group. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `ipAddresses` + +IpAddresses/IpAddressPrefixes in the IP Group resource. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'IPAM Pool Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the IP group. | +| `resourceGroupName` | string | The resource group of the IP group was deployed into. | +| `resourceId` | string | The resource ID of the IP group. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/ip-group/main.bicep b/avm/1.1.0/res/network/ip-group/main.bicep new file mode 100644 index 000000000..c44792ca3 --- /dev/null +++ b/avm/1.1.0/res/network/ip-group/main.bicep @@ -0,0 +1,158 @@ +metadata name = 'IP Groups' +metadata description = 'This module deploys an IP Group.' + +@description('Required. The name of the IP Group.') +@minLength(1) +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. IpAddresses/IpAddressPrefixes in the IP Group resource.') +param ipAddresses array = [] + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Resource tags.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'IPAM Pool Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7b3e853f-ad5d-4fb5-a7b8-56a3581c7037' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-ipgroup.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource ipGroup 'Microsoft.Network/ipGroups@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + ipAddresses: ipAddresses + } +} + +resource ipGroup_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: ipGroup +} + +resource ipGroup_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(ipGroup.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: ipGroup + } +] + +@description('The resource ID of the IP group.') +output resourceId string = ipGroup.id + +@description('The resource group of the IP group was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the IP group.') +output name string = ipGroup.name + +@description('The location the resource was deployed into.') +output location string = ipGroup.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/ip-group/main.json b/avm/1.1.0/res/network/ip-group/main.json new file mode 100644 index 000000000..dcbdbc9a2 --- /dev/null +++ b/avm/1.1.0/res/network/ip-group/main.json @@ -0,0 +1,278 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "8393527758650223467" + }, + "name": "IP Groups", + "description": "This module deploys an IP Group." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. The name of the IP Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "ipAddresses": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. IpAddresses/IpAddressPrefixes in the IP Group resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "IPAM Pool Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7b3e853f-ad5d-4fb5-a7b8-56a3581c7037')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-ipgroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "ipGroup": { + "type": "Microsoft.Network/ipGroups", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "ipAddresses": "[parameters('ipAddresses')]" + } + }, + "ipGroup_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/ipGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "ipGroup" + ] + }, + "ipGroup_roleAssignments": { + "copy": { + "name": "ipGroup_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/ipGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/ipGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "ipGroup" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the IP group." + }, + "value": "[resourceId('Microsoft.Network/ipGroups', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the IP group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the IP group." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('ipGroup', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/ip-group/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/ip-group/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..fd0de68ed --- /dev/null +++ b/avm/1.1.0/res/network/ip-group/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.ipgroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nigmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/network/ip-group/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/ip-group/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/network/ip-group/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/ip-group/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/ip-group/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..fa0d52fb0 --- /dev/null +++ b/avm/1.1.0/res/network/ip-group/tests/e2e/max/main.test.bicep @@ -0,0 +1,92 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.ipgroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nigmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + ipAddresses: [ + '10.0.0.1' + '10.0.0.2' + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '26438d40-c8be-4229-ba65-800cf4e49dc8' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/ip-group/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/ip-group/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..35516eff9 --- /dev/null +++ b/avm/1.1.0/res/network/ip-group/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,57 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.ipgroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nigwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + ipAddresses: [ + '10.0.0.1' + '10.0.0.2' + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/ip-group/version.json b/avm/1.1.0/res/network/ip-group/version.json new file mode 100644 index 000000000..1c035df49 --- /dev/null +++ b/avm/1.1.0/res/network/ip-group/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.2", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/load-balancer/README.md b/avm/1.1.0/res/network/load-balancer/README.md new file mode 100644 index 000000000..51bbc3fbd --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/README.md @@ -0,0 +1,2167 @@ +# Load Balancers `[Microsoft.Network/loadBalancers]` + +This module deploys a Load Balancer. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Notes](#Notes) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/loadBalancers` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/loadBalancers) | +| `Microsoft.Network/loadBalancers/backendAddressPools` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/loadBalancers/backendAddressPools) | +| `Microsoft.Network/loadBalancers/inboundNatRules` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/loadBalancers/inboundNatRules) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/load-balancer:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using external load balancer parameter](#example-2-using-external-load-balancer-parameter) +- [Using internal load balancer parameter](#example-3-using-internal-load-balancer-parameter) +- [Using large parameter set](#example-4-using-large-parameter-set) +- [WAF-aligned](#example-5-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module loadBalancer 'br/public:avm/res/network/load-balancer:' = { + name: 'loadBalancerDeployment' + params: { + // Required parameters + frontendIPConfigurations: [ + { + name: 'publicIPConfig1' + publicIPAddressId: '' + } + ] + name: 'nlbmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "frontendIPConfigurations": { + "value": [ + { + "name": "publicIPConfig1", + "publicIPAddressId": "" + } + ] + }, + "name": { + "value": "nlbmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/load-balancer:' + +// Required parameters +param frontendIPConfigurations = [ + { + name: 'publicIPConfig1' + publicIPAddressId: '' + } +] +param name = 'nlbmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using external load balancer parameter_ + +This instance deploys the module with an externally facing load balancer. + + +

+ +via Bicep module + +```bicep +module loadBalancer 'br/public:avm/res/network/load-balancer:' = { + name: 'loadBalancerDeployment' + params: { + // Required parameters + frontendIPConfigurations: [ + { + name: 'publicIPConfig1' + publicIPAddressId: '' + } + ] + name: 'nlbext001' + // Non-required parameters + backendAddressPools: [ + { + name: 'backendAddressPool1' + } + { + name: 'backendAddressPool2' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + inboundNatRules: [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendPort: 3389 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 3389 + name: 'inboundNatRule2' + } + ] + loadBalancingRules: [ + { + backendAddressPoolName: 'backendAddressPool1' + backendPort: 80 + disableOutboundSnat: true + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 80 + idleTimeoutInMinutes: 5 + loadDistribution: 'Default' + name: 'publicIPLBRule1' + probeName: 'probe1' + protocol: 'Tcp' + } + { + backendAddressPoolName: 'backendAddressPool2' + backendPort: 8080 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 8080 + loadDistribution: 'Default' + name: 'publicIPLBRule2' + probeName: 'probe2' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + outboundRules: [ + { + allocatedOutboundPorts: 63984 + backendAddressPoolName: 'backendAddressPool1' + frontendIPConfigurationName: 'publicIPConfig1' + name: 'outboundRule1' + } + ] + probes: [ + { + intervalInSeconds: 10 + name: 'probe1' + numberOfProbes: 5 + port: 80 + protocol: 'Http' + requestPath: '/http-probe' + } + { + name: 'probe2' + port: 443 + protocol: 'Https' + requestPath: '/https-probe' + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "frontendIPConfigurations": { + "value": [ + { + "name": "publicIPConfig1", + "publicIPAddressId": "" + } + ] + }, + "name": { + "value": "nlbext001" + }, + // Non-required parameters + "backendAddressPools": { + "value": [ + { + "name": "backendAddressPool1" + }, + { + "name": "backendAddressPool2" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "inboundNatRules": { + "value": [ + { + "backendPort": 443, + "enableFloatingIP": false, + "enableTcpReset": false, + "frontendIPConfigurationName": "publicIPConfig1", + "frontendPort": 443, + "idleTimeoutInMinutes": 4, + "name": "inboundNatRule1", + "protocol": "Tcp" + }, + { + "backendPort": 3389, + "frontendIPConfigurationName": "publicIPConfig1", + "frontendPort": 3389, + "name": "inboundNatRule2" + } + ] + }, + "loadBalancingRules": { + "value": [ + { + "backendAddressPoolName": "backendAddressPool1", + "backendPort": 80, + "disableOutboundSnat": true, + "enableFloatingIP": false, + "enableTcpReset": false, + "frontendIPConfigurationName": "publicIPConfig1", + "frontendPort": 80, + "idleTimeoutInMinutes": 5, + "loadDistribution": "Default", + "name": "publicIPLBRule1", + "probeName": "probe1", + "protocol": "Tcp" + }, + { + "backendAddressPoolName": "backendAddressPool2", + "backendPort": 8080, + "frontendIPConfigurationName": "publicIPConfig1", + "frontendPort": 8080, + "loadDistribution": "Default", + "name": "publicIPLBRule2", + "probeName": "probe2" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "outboundRules": { + "value": [ + { + "allocatedOutboundPorts": 63984, + "backendAddressPoolName": "backendAddressPool1", + "frontendIPConfigurationName": "publicIPConfig1", + "name": "outboundRule1" + } + ] + }, + "probes": { + "value": [ + { + "intervalInSeconds": 10, + "name": "probe1", + "numberOfProbes": 5, + "port": 80, + "protocol": "Http", + "requestPath": "/http-probe" + }, + { + "name": "probe2", + "port": 443, + "protocol": "Https", + "requestPath": "/https-probe" + } + ] + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/load-balancer:' + +// Required parameters +param frontendIPConfigurations = [ + { + name: 'publicIPConfig1' + publicIPAddressId: '' + } +] +param name = 'nlbext001' +// Non-required parameters +param backendAddressPools = [ + { + name: 'backendAddressPool1' + } + { + name: 'backendAddressPool2' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param inboundNatRules = [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendPort: 3389 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 3389 + name: 'inboundNatRule2' + } +] +param loadBalancingRules = [ + { + backendAddressPoolName: 'backendAddressPool1' + backendPort: 80 + disableOutboundSnat: true + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 80 + idleTimeoutInMinutes: 5 + loadDistribution: 'Default' + name: 'publicIPLBRule1' + probeName: 'probe1' + protocol: 'Tcp' + } + { + backendAddressPoolName: 'backendAddressPool2' + backendPort: 8080 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 8080 + loadDistribution: 'Default' + name: 'publicIPLBRule2' + probeName: 'probe2' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param outboundRules = [ + { + allocatedOutboundPorts: 63984 + backendAddressPoolName: 'backendAddressPool1' + frontendIPConfigurationName: 'publicIPConfig1' + name: 'outboundRule1' + } +] +param probes = [ + { + intervalInSeconds: 10 + name: 'probe1' + numberOfProbes: 5 + port: 80 + protocol: 'Http' + requestPath: '/http-probe' + } + { + name: 'probe2' + port: 443 + protocol: 'Https' + requestPath: '/https-probe' + } +] +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _Using internal load balancer parameter_ + +This instance deploys the module with the minimum set of required parameters to deploy an internal load balancer. + + +

+ +via Bicep module + +```bicep +module loadBalancer 'br/public:avm/res/network/load-balancer:' = { + name: 'loadBalancerDeployment' + params: { + // Required parameters + frontendIPConfigurations: [ + { + name: 'privateIPConfig1' + subnetId: '' + } + ] + name: 'nlbint001' + // Non-required parameters + backendAddressPools: [ + { + name: 'servers' + } + ] + inboundNatRules: [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendPort: 3389 + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 3389 + name: 'inboundNatRule2' + } + ] + loadBalancingRules: [ + { + backendAddressPoolName: 'servers' + backendPort: 0 + disableOutboundSnat: true + enableFloatingIP: true + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 0 + idleTimeoutInMinutes: 4 + loadDistribution: 'Default' + name: 'privateIPLBRule1' + probeName: 'probe1' + protocol: 'All' + } + ] + location: '' + probes: [ + { + intervalInSeconds: 5 + name: 'probe1' + numberOfProbes: 2 + port: '62000' + protocol: 'Tcp' + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + skuName: 'Standard' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "frontendIPConfigurations": { + "value": [ + { + "name": "privateIPConfig1", + "subnetId": "" + } + ] + }, + "name": { + "value": "nlbint001" + }, + // Non-required parameters + "backendAddressPools": { + "value": [ + { + "name": "servers" + } + ] + }, + "inboundNatRules": { + "value": [ + { + "backendPort": 443, + "enableFloatingIP": false, + "enableTcpReset": false, + "frontendIPConfigurationName": "privateIPConfig1", + "frontendPort": 443, + "idleTimeoutInMinutes": 4, + "name": "inboundNatRule1", + "protocol": "Tcp" + }, + { + "backendPort": 3389, + "frontendIPConfigurationName": "privateIPConfig1", + "frontendPort": 3389, + "name": "inboundNatRule2" + } + ] + }, + "loadBalancingRules": { + "value": [ + { + "backendAddressPoolName": "servers", + "backendPort": 0, + "disableOutboundSnat": true, + "enableFloatingIP": true, + "enableTcpReset": false, + "frontendIPConfigurationName": "privateIPConfig1", + "frontendPort": 0, + "idleTimeoutInMinutes": 4, + "loadDistribution": "Default", + "name": "privateIPLBRule1", + "probeName": "probe1", + "protocol": "All" + } + ] + }, + "location": { + "value": "" + }, + "probes": { + "value": [ + { + "intervalInSeconds": 5, + "name": "probe1", + "numberOfProbes": 2, + "port": "62000", + "protocol": "Tcp" + } + ] + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "skuName": { + "value": "Standard" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/load-balancer:' + +// Required parameters +param frontendIPConfigurations = [ + { + name: 'privateIPConfig1' + subnetId: '' + } +] +param name = 'nlbint001' +// Non-required parameters +param backendAddressPools = [ + { + name: 'servers' + } +] +param inboundNatRules = [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendPort: 3389 + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 3389 + name: 'inboundNatRule2' + } +] +param loadBalancingRules = [ + { + backendAddressPoolName: 'servers' + backendPort: 0 + disableOutboundSnat: true + enableFloatingIP: true + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 0 + idleTimeoutInMinutes: 4 + loadDistribution: 'Default' + name: 'privateIPLBRule1' + probeName: 'probe1' + protocol: 'All' + } +] +param location = '' +param probes = [ + { + intervalInSeconds: 5 + name: 'probe1' + numberOfProbes: 2 + port: '62000' + protocol: 'Tcp' + } +] +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuName = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 4: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module loadBalancer 'br/public:avm/res/network/load-balancer:' = { + name: 'loadBalancerDeployment' + params: { + // Required parameters + frontendIPConfigurations: [ + { + name: 'publicIPConfig1' + publicIPAddressId: '' + } + ] + name: 'nlbmax001' + // Non-required parameters + backendAddressPools: [ + { + name: 'backendAddressPool1' + } + { + name: 'backendAddressPool2' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + inboundNatRules: [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendPort: 3389 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 3389 + name: 'inboundNatRule2' + } + ] + loadBalancingRules: [ + { + backendAddressPoolName: 'backendAddressPool1' + backendPort: 80 + disableOutboundSnat: true + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 80 + idleTimeoutInMinutes: 5 + loadDistribution: 'Default' + name: 'publicIPLBRule1' + probeName: 'probe1' + protocol: 'Tcp' + } + { + backendAddressPoolName: 'backendAddressPool2' + backendPort: 8080 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 8080 + loadDistribution: 'Default' + name: 'publicIPLBRule2' + probeName: 'probe2' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + outboundRules: [ + { + allocatedOutboundPorts: 63984 + backendAddressPoolName: 'backendAddressPool1' + frontendIPConfigurationName: 'publicIPConfig1' + name: 'outboundRule1' + } + ] + probes: [ + { + intervalInSeconds: 10 + name: 'probe1' + numberOfProbes: 5 + port: 80 + protocol: 'Tcp' + } + { + name: 'probe2' + port: 443 + protocol: 'Https' + requestPath: '/' + } + ] + roleAssignments: [ + { + name: '3a5b2a4a-3584-4d6b-9cf0-ceb1e4f88a5d' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "frontendIPConfigurations": { + "value": [ + { + "name": "publicIPConfig1", + "publicIPAddressId": "" + } + ] + }, + "name": { + "value": "nlbmax001" + }, + // Non-required parameters + "backendAddressPools": { + "value": [ + { + "name": "backendAddressPool1" + }, + { + "name": "backendAddressPool2" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "logCategoriesAndGroups": [ + { + "categoryGroup": "allLogs" + } + ], + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "inboundNatRules": { + "value": [ + { + "backendPort": 443, + "enableFloatingIP": false, + "enableTcpReset": false, + "frontendIPConfigurationName": "publicIPConfig1", + "frontendPort": 443, + "idleTimeoutInMinutes": 4, + "name": "inboundNatRule1", + "protocol": "Tcp" + }, + { + "backendPort": 3389, + "frontendIPConfigurationName": "publicIPConfig1", + "frontendPort": 3389, + "name": "inboundNatRule2" + } + ] + }, + "loadBalancingRules": { + "value": [ + { + "backendAddressPoolName": "backendAddressPool1", + "backendPort": 80, + "disableOutboundSnat": true, + "enableFloatingIP": false, + "enableTcpReset": false, + "frontendIPConfigurationName": "publicIPConfig1", + "frontendPort": 80, + "idleTimeoutInMinutes": 5, + "loadDistribution": "Default", + "name": "publicIPLBRule1", + "probeName": "probe1", + "protocol": "Tcp" + }, + { + "backendAddressPoolName": "backendAddressPool2", + "backendPort": 8080, + "frontendIPConfigurationName": "publicIPConfig1", + "frontendPort": 8080, + "loadDistribution": "Default", + "name": "publicIPLBRule2", + "probeName": "probe2" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "outboundRules": { + "value": [ + { + "allocatedOutboundPorts": 63984, + "backendAddressPoolName": "backendAddressPool1", + "frontendIPConfigurationName": "publicIPConfig1", + "name": "outboundRule1" + } + ] + }, + "probes": { + "value": [ + { + "intervalInSeconds": 10, + "name": "probe1", + "numberOfProbes": 5, + "port": 80, + "protocol": "Tcp" + }, + { + "name": "probe2", + "port": 443, + "protocol": "Https", + "requestPath": "/" + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "3a5b2a4a-3584-4d6b-9cf0-ceb1e4f88a5d", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/load-balancer:' + +// Required parameters +param frontendIPConfigurations = [ + { + name: 'publicIPConfig1' + publicIPAddressId: '' + } +] +param name = 'nlbmax001' +// Non-required parameters +param backendAddressPools = [ + { + name: 'backendAddressPool1' + } + { + name: 'backendAddressPool2' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param inboundNatRules = [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendPort: 3389 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 3389 + name: 'inboundNatRule2' + } +] +param loadBalancingRules = [ + { + backendAddressPoolName: 'backendAddressPool1' + backendPort: 80 + disableOutboundSnat: true + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 80 + idleTimeoutInMinutes: 5 + loadDistribution: 'Default' + name: 'publicIPLBRule1' + probeName: 'probe1' + protocol: 'Tcp' + } + { + backendAddressPoolName: 'backendAddressPool2' + backendPort: 8080 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 8080 + loadDistribution: 'Default' + name: 'publicIPLBRule2' + probeName: 'probe2' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param outboundRules = [ + { + allocatedOutboundPorts: 63984 + backendAddressPoolName: 'backendAddressPool1' + frontendIPConfigurationName: 'publicIPConfig1' + name: 'outboundRule1' + } +] +param probes = [ + { + intervalInSeconds: 10 + name: 'probe1' + numberOfProbes: 5 + port: 80 + protocol: 'Tcp' + } + { + name: 'probe2' + port: 443 + protocol: 'Https' + requestPath: '/' + } +] +param roleAssignments = [ + { + name: '3a5b2a4a-3584-4d6b-9cf0-ceb1e4f88a5d' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 5: _WAF-aligned_ + +This instance deploys the module with the minimum set of required parameters to deploy a WAF-aligned internal load balancer. + + +

+ +via Bicep module + +```bicep +module loadBalancer 'br/public:avm/res/network/load-balancer:' = { + name: 'loadBalancerDeployment' + params: { + // Required parameters + frontendIPConfigurations: [ + { + name: 'privateIPConfig1' + subnetId: '' + zones: [ + 1 + 2 + 3 + ] + } + ] + name: 'nlbwaf001' + // Non-required parameters + backendAddressPools: [ + { + name: 'servers' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + inboundNatRules: [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendAddressPoolName: 'servers' + backendPort: 3389 + frontendIPConfigurationName: 'privateIPConfig1' + frontendPortRangeEnd: 5010 + frontendPortRangeStart: 5000 + loadDistribution: 'Default' + name: 'inboundNatRule2' + probeName: 'probe2' + } + ] + loadBalancingRules: [ + { + backendAddressPoolName: 'servers' + backendPort: 0 + disableOutboundSnat: true + enableFloatingIP: true + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 0 + idleTimeoutInMinutes: 4 + loadDistribution: 'Default' + name: 'privateIPLBRule1' + probeName: 'probe1' + protocol: 'All' + } + ] + location: '' + probes: [ + { + intervalInSeconds: 5 + name: 'probe1' + numberOfProbes: 2 + port: '62000' + protocol: 'Tcp' + } + ] + skuName: 'Standard' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "frontendIPConfigurations": { + "value": [ + { + "name": "privateIPConfig1", + "subnetId": "", + "zones": [ + 1, + 2, + 3 + ] + } + ] + }, + "name": { + "value": "nlbwaf001" + }, + // Non-required parameters + "backendAddressPools": { + "value": [ + { + "name": "servers" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "inboundNatRules": { + "value": [ + { + "backendPort": 443, + "enableFloatingIP": false, + "enableTcpReset": false, + "frontendIPConfigurationName": "privateIPConfig1", + "frontendPort": 443, + "idleTimeoutInMinutes": 4, + "name": "inboundNatRule1", + "protocol": "Tcp" + }, + { + "backendAddressPoolName": "servers", + "backendPort": 3389, + "frontendIPConfigurationName": "privateIPConfig1", + "frontendPortRangeEnd": 5010, + "frontendPortRangeStart": 5000, + "loadDistribution": "Default", + "name": "inboundNatRule2", + "probeName": "probe2" + } + ] + }, + "loadBalancingRules": { + "value": [ + { + "backendAddressPoolName": "servers", + "backendPort": 0, + "disableOutboundSnat": true, + "enableFloatingIP": true, + "enableTcpReset": false, + "frontendIPConfigurationName": "privateIPConfig1", + "frontendPort": 0, + "idleTimeoutInMinutes": 4, + "loadDistribution": "Default", + "name": "privateIPLBRule1", + "probeName": "probe1", + "protocol": "All" + } + ] + }, + "location": { + "value": "" + }, + "probes": { + "value": [ + { + "intervalInSeconds": 5, + "name": "probe1", + "numberOfProbes": 2, + "port": "62000", + "protocol": "Tcp" + } + ] + }, + "skuName": { + "value": "Standard" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/load-balancer:' + +// Required parameters +param frontendIPConfigurations = [ + { + name: 'privateIPConfig1' + subnetId: '' + zones: [ + 1 + 2 + 3 + ] + } +] +param name = 'nlbwaf001' +// Non-required parameters +param backendAddressPools = [ + { + name: 'servers' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param inboundNatRules = [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendAddressPoolName: 'servers' + backendPort: 3389 + frontendIPConfigurationName: 'privateIPConfig1' + frontendPortRangeEnd: 5010 + frontendPortRangeStart: 5000 + loadDistribution: 'Default' + name: 'inboundNatRule2' + probeName: 'probe2' + } +] +param loadBalancingRules = [ + { + backendAddressPoolName: 'servers' + backendPort: 0 + disableOutboundSnat: true + enableFloatingIP: true + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 0 + idleTimeoutInMinutes: 4 + loadDistribution: 'Default' + name: 'privateIPLBRule1' + probeName: 'probe1' + protocol: 'All' + } +] +param location = '' +param probes = [ + { + intervalInSeconds: 5 + name: 'probe1' + numberOfProbes: 2 + port: '62000' + protocol: 'Tcp' + } +] +param skuName = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`frontendIPConfigurations`](#parameter-frontendipconfigurations) | array | Array of objects containing all frontend IP configurations. | +| [`name`](#parameter-name) | string | The Proximity Placement Groups Name. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backendAddressPools`](#parameter-backendaddresspools) | array | Collection of backend address pools used by a load balancer. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`inboundNatRules`](#parameter-inboundnatrules) | array | Collection of inbound NAT Rules used by a load balancer. Defining inbound NAT rules on your load balancer is mutually exclusive with defining an inbound NAT pool. Inbound NAT pools are referenced from virtual machine scale sets. NICs that are associated with individual virtual machines cannot reference an Inbound NAT pool. They have to reference individual inbound NAT rules. | +| [`loadBalancingRules`](#parameter-loadbalancingrules) | array | Array of objects containing all load balancing rules. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`outboundRules`](#parameter-outboundrules) | array | The outbound rules. | +| [`probes`](#parameter-probes) | array | Array of objects containing all probes, these are references in the load balancing rules. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`skuName`](#parameter-skuname) | string | Name of a load balancer SKU. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `frontendIPConfigurations` + +Array of objects containing all frontend IP configurations. + +- Required: Yes +- Type: array + +### Parameter: `name` + +The Proximity Placement Groups Name. + +- Required: Yes +- Type: string + +### Parameter: `backendAddressPools` + +Collection of backend address pools used by a load balancer. + +- Required: No +- Type: array + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `inboundNatRules` + +Collection of inbound NAT Rules used by a load balancer. Defining inbound NAT rules on your load balancer is mutually exclusive with defining an inbound NAT pool. Inbound NAT pools are referenced from virtual machine scale sets. NICs that are associated with individual virtual machines cannot reference an Inbound NAT pool. They have to reference individual inbound NAT rules. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `loadBalancingRules` + +Array of objects containing all load balancing rules. + +- Required: No +- Type: array + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `outboundRules` + +The outbound rules. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `probes` + +Array of objects containing all probes, these are references in the load balancing rules. + +- Required: No +- Type: array + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `skuName` + +Name of a load balancer SKU. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Standard' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `backendpools` | array | The backend address pools available in the load balancer. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the load balancer. | +| `resourceGroupName` | string | The resource group the load balancer was deployed into. | +| `resourceId` | string | The resource ID of the load balancer. | + +## Notes + +### Parameter Usage: `backendAddressPools` + +

+ +Parameter JSON format + +```json +"backendAddressPools": { + "value": [ + { + "name": "p_hub-bfw-server-bepool", + "properties": { + "loadBalancerBackendAddresses": [ + { + "name": "iacs-sh-main-pd-01-euw-rg-network_awefwa01p-nic-int-01ipconfig-internal", + "properties": { + "virtualNetwork": { + "id": "[reference(variables('deploymentVNET')).outputs.vNetResourceId.value]" + }, + "ipAddress": "172.22.232.5" + } + }, + { + "name": "iacs-sh-main-pd-01-euw-rg-network_awefwa01p-ha-nic-int-01ipconfig-internal", + "properties": { + "virtualNetwork": { + "id": "[reference(variables('deploymentVNET')).outputs.vNetResourceId.value]" + }, + "ipAddress": "172.22.232.6" + } + } + ] + } + } + ] +} +``` + +
+ +
+ +Bicep format + +```bicep +backendAddressPools: [ + { + name: 'p_hub-bfw-server-bepool' + properties: { + loadBalancerBackendAddresses: [ + { + name: 'iacs-sh-main-pd-01-euw-rg-network_awefwa01p-nic-int-01ipconfig-internal' + properties: { + virtualNetwork: { + id: '[reference(variables('deploymentVNET')).outputs.vNetResourceId.value]' + } + ipAddress: '172.22.232.5' + } + } + { + name: 'iacs-sh-main-pd-01-euw-rg-network_awefwa01p-ha-nic-int-01ipconfig-internal' + properties: { + virtualNetwork: { + id: '[reference(variables('deploymentVNET')).outputs.vNetResourceId.value]' + } + ipAddress: '172.22.232.6' + } + } + ] + } + } +] +``` + +
+

+ +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/load-balancer/backend-address-pool/README.md b/avm/1.1.0/res/network/load-balancer/backend-address-pool/README.md new file mode 100644 index 000000000..f97b23d09 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/backend-address-pool/README.md @@ -0,0 +1,100 @@ +# Load Balancer Backend Address Pools `[Microsoft.Network/loadBalancers/backendAddressPools]` + +This module deploys a Load Balancer Backend Address Pools. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/loadBalancers/backendAddressPools` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/loadBalancers/backendAddressPools) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the backend address pool. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`loadBalancerName`](#parameter-loadbalancername) | string | The name of the parent load balancer. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`drainPeriodInSeconds`](#parameter-drainperiodinseconds) | int | Amount of seconds Load Balancer waits for before sending RESET to client and backend address. if value is 0 then this property will be set to null. Subscription must register the feature Microsoft.Network/SLBAllowConnectionDraining before using this property. | +| [`loadBalancerBackendAddresses`](#parameter-loadbalancerbackendaddresses) | array | An array of backend addresses. | +| [`syncMode`](#parameter-syncmode) | string | Backend address synchronous mode for the backend pool. | +| [`tunnelInterfaces`](#parameter-tunnelinterfaces) | array | An array of gateway load balancer tunnel interfaces. | + +### Parameter: `name` + +The name of the backend address pool. + +- Required: Yes +- Type: string + +### Parameter: `loadBalancerName` + +The name of the parent load balancer. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `drainPeriodInSeconds` + +Amount of seconds Load Balancer waits for before sending RESET to client and backend address. if value is 0 then this property will be set to null. Subscription must register the feature Microsoft.Network/SLBAllowConnectionDraining before using this property. + +- Required: No +- Type: int +- Default: `0` + +### Parameter: `loadBalancerBackendAddresses` + +An array of backend addresses. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `syncMode` + +Backend address synchronous mode for the backend pool. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Automatic' + 'Manual' + ] + ``` + +### Parameter: `tunnelInterfaces` + +An array of gateway load balancer tunnel interfaces. + +- Required: No +- Type: array +- Default: `[]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the backend address pool. | +| `resourceGroupName` | string | The resource group the backend address pool was deployed into. | +| `resourceId` | string | The resource ID of the backend address pool. | diff --git a/avm/1.1.0/res/network/load-balancer/backend-address-pool/main.bicep b/avm/1.1.0/res/network/load-balancer/backend-address-pool/main.bicep new file mode 100644 index 000000000..6eb1a810d --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/backend-address-pool/main.bicep @@ -0,0 +1,49 @@ +metadata name = 'Load Balancer Backend Address Pools' +metadata description = 'This module deploys a Load Balancer Backend Address Pools.' + +@description('Conditional. The name of the parent load balancer. Required if the template is used in a standalone deployment.') +param loadBalancerName string + +@description('Required. The name of the backend address pool.') +param name string + +@description('Optional. An array of backend addresses.') +param loadBalancerBackendAddresses array = [] + +@description('Optional. An array of gateway load balancer tunnel interfaces.') +param tunnelInterfaces array = [] + +@description('Optional. Amount of seconds Load Balancer waits for before sending RESET to client and backend address. if value is 0 then this property will be set to null. Subscription must register the feature Microsoft.Network/SLBAllowConnectionDraining before using this property.') +param drainPeriodInSeconds int = 0 + +@allowed([ + '' + 'Automatic' + 'Manual' +]) +@description('Optional. Backend address synchronous mode for the backend pool.') +param syncMode string = '' + +resource loadBalancer 'Microsoft.Network/loadBalancers@2023-11-01' existing = { + name: loadBalancerName +} + +resource backendAddressPool 'Microsoft.Network/loadBalancers/backendAddressPools@2023-11-01' = { + name: name + properties: { + loadBalancerBackendAddresses: loadBalancerBackendAddresses + tunnelInterfaces: tunnelInterfaces + drainPeriodInSeconds: drainPeriodInSeconds != 0 ? drainPeriodInSeconds : null + syncMode: !empty(syncMode) ? syncMode : null + } + parent: loadBalancer +} + +@description('The name of the backend address pool.') +output name string = backendAddressPool.name + +@description('The resource ID of the backend address pool.') +output resourceId string = backendAddressPool.id + +@description('The resource group the backend address pool was deployed into.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/network/load-balancer/backend-address-pool/main.json b/avm/1.1.0/res/network/load-balancer/backend-address-pool/main.json new file mode 100644 index 000000000..3e9e8de75 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/backend-address-pool/main.json @@ -0,0 +1,96 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "1858226960694905370" + }, + "name": "Load Balancer Backend Address Pools", + "description": "This module deploys a Load Balancer Backend Address Pools." + }, + "parameters": { + "loadBalancerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent load balancer. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the backend address pool." + } + }, + "loadBalancerBackendAddresses": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of backend addresses." + } + }, + "tunnelInterfaces": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of gateway load balancer tunnel interfaces." + } + }, + "drainPeriodInSeconds": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Amount of seconds Load Balancer waits for before sending RESET to client and backend address. if value is 0 then this property will be set to null. Subscription must register the feature Microsoft.Network/SLBAllowConnectionDraining before using this property." + } + }, + "syncMode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Automatic", + "Manual" + ], + "metadata": { + "description": "Optional. Backend address synchronous mode for the backend pool." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/loadBalancers/backendAddressPools", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('loadBalancerName'), parameters('name'))]", + "properties": { + "loadBalancerBackendAddresses": "[parameters('loadBalancerBackendAddresses')]", + "tunnelInterfaces": "[parameters('tunnelInterfaces')]", + "drainPeriodInSeconds": "[if(not(equals(parameters('drainPeriodInSeconds'), 0)), parameters('drainPeriodInSeconds'), null())]", + "syncMode": "[if(not(empty(parameters('syncMode'))), parameters('syncMode'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backend address pool." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the backend address pool." + }, + "value": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('loadBalancerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the backend address pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/load-balancer/inbound-nat-rule/README.md b/avm/1.1.0/res/network/load-balancer/inbound-nat-rule/README.md new file mode 100644 index 000000000..dc017f754 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/inbound-nat-rule/README.md @@ -0,0 +1,178 @@ +# Load Balancer Inbound NAT Rules `[Microsoft.Network/loadBalancers/inboundNatRules]` + +This module deploys a Load Balancer Inbound NAT Rules. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/loadBalancers/inboundNatRules` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/loadBalancers/inboundNatRules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backendPort`](#parameter-backendport) | int | The port used for the internal endpoint. | +| [`frontendIPConfigurationName`](#parameter-frontendipconfigurationname) | string | The name of the frontend IP address to set for the inbound NAT rule. | +| [`name`](#parameter-name) | string | The name of the inbound NAT rule. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`frontendPort`](#parameter-frontendport) | int | The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Required if FrontendPortRangeStart and FrontendPortRangeEnd are not specified. | +| [`frontendPortRangeStart`](#parameter-frontendportrangestart) | int | The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Required if FrontendPort is not specified. | +| [`loadBalancerName`](#parameter-loadbalancername) | string | The name of the parent load balancer. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backendAddressPoolName`](#parameter-backendaddresspoolname) | string | Name of the backend address pool. | +| [`enableFloatingIP`](#parameter-enablefloatingip) | bool | Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint. | +| [`enableTcpReset`](#parameter-enabletcpreset) | bool | Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP. | +| [`idleTimeoutInMinutes`](#parameter-idletimeoutinminutes) | int | The timeout for the TCP idle connection. The value can be set between 4 and 30 minutes. The default value is 4 minutes. This element is only used when the protocol is set to TCP. | +| [`protocol`](#parameter-protocol) | string | The transport protocol for the endpoint. | + +**Conditonal parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`frontendPortRangeEnd`](#parameter-frontendportrangeend) | int | The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Required if FrontendPort is not specified. | + +### Parameter: `backendPort` + +The port used for the internal endpoint. + +- Required: Yes +- Type: int +- MinValue: 0 +- MaxValue: 65535 + +### Parameter: `frontendIPConfigurationName` + +The name of the frontend IP address to set for the inbound NAT rule. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 65535 + +### Parameter: `name` + +The name of the inbound NAT rule. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 65535 + +### Parameter: `frontendPort` + +The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Required if FrontendPortRangeStart and FrontendPortRangeEnd are not specified. + +- Required: No +- Type: int +- MinValue: 0 +- MaxValue: 65534 + +### Parameter: `frontendPortRangeStart` + +The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Required if FrontendPort is not specified. + +- Required: No +- Type: int +- MinValue: 0 +- MaxValue: 65534 + +### Parameter: `loadBalancerName` + +The name of the parent load balancer. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 65534 + +### Parameter: `backendAddressPoolName` + +Name of the backend address pool. + +- Required: No +- Type: string +- Default: `''` +- MinValue: 0 +- MaxValue: 65534 + +### Parameter: `enableFloatingIP` + +Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 0 +- MaxValue: 65534 + +### Parameter: `enableTcpReset` + +Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 0 +- MaxValue: 65534 + +### Parameter: `idleTimeoutInMinutes` + +The timeout for the TCP idle connection. The value can be set between 4 and 30 minutes. The default value is 4 minutes. This element is only used when the protocol is set to TCP. + +- Required: No +- Type: int +- Default: `4` +- MinValue: 0 +- MaxValue: 65534 + +### Parameter: `protocol` + +The transport protocol for the endpoint. + +- Required: No +- Type: string +- Default: `'Tcp'` +- Allowed: + ```Bicep + [ + 'All' + 'Tcp' + 'Udp' + ] + ``` +- MinValue: 0 +- MaxValue: 65534 + +### Parameter: `frontendPortRangeEnd` + +The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Required if FrontendPort is not specified. + +- Required: No +- Type: int +- MinValue: 0 +- MaxValue: 65534 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the inbound NAT rule. | +| `resourceGroupName` | string | The resource group the inbound NAT rule was deployed into. | +| `resourceId` | string | The resource ID of the inbound NAT rule. | diff --git a/avm/1.1.0/res/network/load-balancer/inbound-nat-rule/main.bicep b/avm/1.1.0/res/network/load-balancer/inbound-nat-rule/main.bicep new file mode 100644 index 000000000..b7b638020 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/inbound-nat-rule/main.bicep @@ -0,0 +1,87 @@ +metadata name = 'Load Balancer Inbound NAT Rules' +metadata description = 'This module deploys a Load Balancer Inbound NAT Rules.' + +@description('Conditional. The name of the parent load balancer. Required if the template is used in a standalone deployment.') +param loadBalancerName string + +@description('Required. The name of the inbound NAT rule.') +param name string + +@description('Conditional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Required if FrontendPortRangeStart and FrontendPortRangeEnd are not specified.') +@minValue(0) +@maxValue(65534) +param frontendPort int? + +@description('Required. The port used for the internal endpoint.') +@minValue(0) +@maxValue(65535) +param backendPort int + +@description('Optional. Name of the backend address pool.') +param backendAddressPoolName string = '' + +@description('Optional. Configures a virtual machine\'s endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can\'t be changed after you create the endpoint.') +param enableFloatingIP bool = false + +@description('Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP.') +param enableTcpReset bool = false + +@description('Required. The name of the frontend IP address to set for the inbound NAT rule.') +param frontendIPConfigurationName string + +@description('Conditonal. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Required if FrontendPort is not specified.') +@minValue(0) +@maxValue(65534) +param frontendPortRangeEnd int? + +@description('Conditional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Required if FrontendPort is not specified.') +@minValue(0) +@maxValue(65534) +param frontendPortRangeStart int? + +@description('Optional. The timeout for the TCP idle connection. The value can be set between 4 and 30 minutes. The default value is 4 minutes. This element is only used when the protocol is set to TCP.') +param idleTimeoutInMinutes int = 4 + +@description('Optional. The transport protocol for the endpoint.') +@allowed([ + 'All' + 'Tcp' + 'Udp' +]) +param protocol string = 'Tcp' + +resource loadBalancer 'Microsoft.Network/loadBalancers@2023-11-01' existing = { + name: loadBalancerName +} + +resource inboundNatRule 'Microsoft.Network/loadBalancers/inboundNatRules@2023-11-01' = { + name: name + properties: { + frontendPort: frontendPort + backendPort: backendPort + backendAddressPool: !empty(backendAddressPoolName) + ? { + id: '${loadBalancer.id}/backendAddressPools/${backendAddressPoolName}' + } + : null + enableFloatingIP: enableFloatingIP + enableTcpReset: enableTcpReset + frontendIPConfiguration: { + id: '${loadBalancer.id}/frontendIPConfigurations/${frontendIPConfigurationName}' + } + frontendPortRangeStart: frontendPortRangeStart + frontendPortRangeEnd: frontendPortRangeEnd + idleTimeoutInMinutes: idleTimeoutInMinutes + protocol: protocol + } + parent: loadBalancer +} + +@description('The name of the inbound NAT rule.') +output name string = inboundNatRule.name + +@description('The resource ID of the inbound NAT rule.') +output resourceId string = inboundNatRule.id + +@description('The resource group the inbound NAT rule was deployed into.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/network/load-balancer/inbound-nat-rule/main.json b/avm/1.1.0/res/network/load-balancer/inbound-nat-rule/main.json new file mode 100644 index 000000000..e8cba0d5b --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/inbound-nat-rule/main.json @@ -0,0 +1,159 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "16950982858394467575" + }, + "name": "Load Balancer Inbound NAT Rules", + "description": "This module deploys a Load Balancer Inbound NAT Rules." + }, + "parameters": { + "loadBalancerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent load balancer. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the inbound NAT rule." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 65534, + "metadata": { + "description": "Conditional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Required if FrontendPortRangeStart and FrontendPortRangeEnd are not specified." + } + }, + "backendPort": { + "type": "int", + "minValue": 0, + "maxValue": 65535, + "metadata": { + "description": "Required. The port used for the internal endpoint." + } + }, + "backendAddressPoolName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the backend address pool." + } + }, + "enableFloatingIP": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfigurationName": { + "type": "string", + "metadata": { + "description": "Required. The name of the frontend IP address to set for the inbound NAT rule." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 65534, + "metadata": { + "description": "Conditonal. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Required if FrontendPort is not specified." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 65534, + "metadata": { + "description": "Conditional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Required if FrontendPort is not specified." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The timeout for the TCP idle connection. The value can be set between 4 and 30 minutes. The default value is 4 minutes. This element is only used when the protocol is set to TCP." + } + }, + "protocol": { + "type": "string", + "defaultValue": "Tcp", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Optional. The transport protocol for the endpoint." + } + } + }, + "resources": { + "loadBalancer": { + "existing": true, + "type": "Microsoft.Network/loadBalancers", + "apiVersion": "2023-11-01", + "name": "[parameters('loadBalancerName')]" + }, + "inboundNatRule": { + "type": "Microsoft.Network/loadBalancers/inboundNatRules", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('loadBalancerName'), parameters('name'))]", + "properties": { + "frontendPort": "[parameters('frontendPort')]", + "backendPort": "[parameters('backendPort')]", + "backendAddressPool": "[if(not(empty(parameters('backendAddressPoolName'))), createObject('id', format('{0}/backendAddressPools/{1}', resourceId('Microsoft.Network/loadBalancers', parameters('loadBalancerName')), parameters('backendAddressPoolName'))), null())]", + "enableFloatingIP": "[parameters('enableFloatingIP')]", + "enableTcpReset": "[parameters('enableTcpReset')]", + "frontendIPConfiguration": { + "id": "[format('{0}/frontendIPConfigurations/{1}', resourceId('Microsoft.Network/loadBalancers', parameters('loadBalancerName')), parameters('frontendIPConfigurationName'))]" + }, + "frontendPortRangeStart": "[parameters('frontendPortRangeStart')]", + "frontendPortRangeEnd": "[parameters('frontendPortRangeEnd')]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "protocol": "[parameters('protocol')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the inbound NAT rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the inbound NAT rule." + }, + "value": "[resourceId('Microsoft.Network/loadBalancers/inboundNatRules', parameters('loadBalancerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the inbound NAT rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/load-balancer/main.bicep b/avm/1.1.0/res/network/load-balancer/main.bicep new file mode 100644 index 000000000..a96079c4f --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/main.bicep @@ -0,0 +1,456 @@ +metadata name = 'Load Balancers' +metadata description = 'This module deploys a Load Balancer.' + +// ================ // +// Parameters // +// ================ // + +@description('Required. The Proximity Placement Groups Name.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Name of a load balancer SKU.') +@allowed([ + 'Basic' + 'Standard' +]) +param skuName string = 'Standard' + +@description('Required. Array of objects containing all frontend IP configurations.') +@minLength(1) +param frontendIPConfigurations array + +@description('Optional. Collection of backend address pools used by a load balancer.') +param backendAddressPools array? + +@description('Optional. Array of objects containing all load balancing rules.') +param loadBalancingRules array? + +@description('Optional. Array of objects containing all probes, these are references in the load balancing rules.') +param probes array? + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Collection of inbound NAT Rules used by a load balancer. Defining inbound NAT rules on your load balancer is mutually exclusive with defining an inbound NAT pool. Inbound NAT pools are referenced from virtual machine scale sets. NICs that are associated with individual virtual machines cannot reference an Inbound NAT pool. They have to reference individual inbound NAT rules.') +param inboundNatRules array = [] + +@description('Optional. The outbound rules.') +param outboundRules array = [] + +// =========== // +// Variables // +// =========== // + +var frontendIPConfigurationsVar = [ + for (frontendIPConfiguration, index) in frontendIPConfigurations: { + name: frontendIPConfiguration.name + properties: { + subnet: contains(frontendIPConfiguration, 'subnetId') && !empty(frontendIPConfiguration.subnetId) + ? { + id: frontendIPConfiguration.subnetId + } + : null + publicIPAddress: contains(frontendIPConfiguration, 'publicIPAddressId') && !empty(frontendIPConfiguration.publicIPAddressId) + ? { + id: frontendIPConfiguration.publicIPAddressId + } + : null + privateIPAddress: contains(frontendIPConfiguration, 'privateIPAddress') && !empty(frontendIPConfiguration.privateIPAddress) + ? frontendIPConfiguration.privateIPAddress + : null + privateIPAddressVersion: contains(frontendIPConfiguration, 'privateIPAddressVersion') + ? frontendIPConfiguration.privateIPAddressVersion + : 'IPv4' + privateIPAllocationMethod: contains(frontendIPConfiguration, 'subnetId') && !empty(frontendIPConfiguration.subnetId) + ? (contains(frontendIPConfiguration, 'privateIPAddress') ? 'Static' : 'Dynamic') + : null + gatewayLoadBalancer: contains(frontendIPConfiguration, 'gatewayLoadBalancer') && !empty(frontendIPConfiguration.gatewayLoadBalancer) + ? { + id: frontendIPConfiguration.gatewayLoadBalancer + } + : null + publicIPPrefix: contains(frontendIPConfiguration, 'publicIPPrefix') && !empty(frontendIPConfiguration.publicIPPrefix) + ? { + id: frontendIPConfiguration.publicIPPrefix + } + : null + } + zones: contains(frontendIPConfiguration, 'zones') + ? map(frontendIPConfiguration.zones, zone => string(zone)) + : !empty(frontendIPConfiguration.?subnetResourceId) + ? [ + '1' + '2' + '3' + ] + : null + } +] + +var loadBalancingRulesVar = [ + for loadBalancingRule in (loadBalancingRules ?? []): { + name: loadBalancingRule.name + properties: { + backendAddressPool: { + id: az.resourceId( + 'Microsoft.Network/loadBalancers/backendAddressPools', + name, + loadBalancingRule.backendAddressPoolName + ) + } + backendPort: loadBalancingRule.backendPort + disableOutboundSnat: contains(loadBalancingRule, 'disableOutboundSnat') + ? loadBalancingRule.disableOutboundSnat + : true + enableFloatingIP: contains(loadBalancingRule, 'enableFloatingIP') ? loadBalancingRule.enableFloatingIP : false + enableTcpReset: contains(loadBalancingRule, 'enableTcpReset') ? loadBalancingRule.enableTcpReset : false + frontendIPConfiguration: { + id: az.resourceId( + 'Microsoft.Network/loadBalancers/frontendIPConfigurations', + name, + loadBalancingRule.frontendIPConfigurationName + ) + } + frontendPort: loadBalancingRule.frontendPort + idleTimeoutInMinutes: contains(loadBalancingRule, 'idleTimeoutInMinutes') + ? loadBalancingRule.idleTimeoutInMinutes + : 4 + loadDistribution: contains(loadBalancingRule, 'loadDistribution') ? loadBalancingRule.loadDistribution : 'Default' + probe: { + id: '${az.resourceId('Microsoft.Network/loadBalancers', name)}/probes/${loadBalancingRule.probeName}' + } + protocol: contains(loadBalancingRule, 'protocol') ? loadBalancingRule.protocol : 'Tcp' + } + } +] + +var outboundRulesVar = [ + for outboundRule in outboundRules: { + name: outboundRule.name + properties: { + frontendIPConfigurations: [ + { + id: az.resourceId( + 'Microsoft.Network/loadBalancers/frontendIPConfigurations', + name, + outboundRule.frontendIPConfigurationName + ) + } + ] + backendAddressPool: { + id: az.resourceId( + 'Microsoft.Network/loadBalancers/backendAddressPools', + name, + outboundRule.backendAddressPoolName + ) + } + protocol: contains(outboundRule, 'protocol') ? outboundRule.protocol : 'All' + allocatedOutboundPorts: contains(outboundRule, 'allocatedOutboundPorts') + ? outboundRule.allocatedOutboundPorts + : 63984 + enableTcpReset: contains(outboundRule, 'enableTcpReset') ? outboundRule.enableTcpReset : true + idleTimeoutInMinutes: contains(outboundRule, 'idleTimeoutInMinutes') ? outboundRule.idleTimeoutInMinutes : 4 + } + } +] + +var probesVar = [ + for probe in (probes ?? []): { + name: probe.name + properties: { + protocol: contains(probe, 'protocol') ? probe.protocol : 'Tcp' + requestPath: toLower(probe.protocol) != 'tcp' ? probe.requestPath : null + port: contains(probe, 'port') ? probe.port : 80 + intervalInSeconds: contains(probe, 'intervalInSeconds') ? probe.intervalInSeconds : 5 + numberOfProbes: contains(probe, 'numberOfProbes') ? probe.numberOfProbes : 2 + } + } +] + +var backendAddressPoolNames = [ + for backendAddressPool in (backendAddressPools ?? []): { + name: backendAddressPool.name + } +] + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +// ============ // +// Dependencies // +// ============ // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-loadbalancer.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource loadBalancer 'Microsoft.Network/loadBalancers@2023-11-01' = { + name: name + location: location + tags: tags + sku: { + name: skuName + } + properties: { + frontendIPConfigurations: frontendIPConfigurationsVar + loadBalancingRules: loadBalancingRulesVar + backendAddressPools: backendAddressPoolNames + outboundRules: outboundRulesVar + probes: probesVar + } +} + +module loadBalancer_backendAddressPools 'backend-address-pool/main.bicep' = [ + for (backendAddressPool, index) in backendAddressPools ?? []: { + name: '${uniqueString(deployment().name, location)}-loadBalancer-backendAddressPools-${index}' + params: { + loadBalancerName: loadBalancer.name + name: backendAddressPool.name + tunnelInterfaces: contains(backendAddressPool, 'tunnelInterfaces') && !empty(backendAddressPool.tunnelInterfaces) + ? backendAddressPool.tunnelInterfaces + : [] + loadBalancerBackendAddresses: contains(backendAddressPool, 'loadBalancerBackendAddresses') && !empty(backendAddressPool.loadBalancerBackendAddresses) + ? backendAddressPool.loadBalancerBackendAddresses + : [] + drainPeriodInSeconds: contains(backendAddressPool, 'drainPeriodInSeconds') + ? backendAddressPool.drainPeriodInSeconds + : 0 + } + } +] + +module loadBalancer_inboundNATRules 'inbound-nat-rule/main.bicep' = [ + for (inboundNATRule, index) in inboundNatRules: { + name: '${uniqueString(deployment().name, location)}-LoadBalancer-inboundNatRules-${index}' + params: { + loadBalancerName: loadBalancer.name + name: inboundNATRule.name + frontendIPConfigurationName: inboundNATRule.frontendIPConfigurationName + frontendPort: inboundNATRule.?frontendPort + backendPort: inboundNATRule.backendPort + backendAddressPoolName: inboundNATRule.?backendAddressPoolName + enableFloatingIP: inboundNATRule.?enableFloatingIP + enableTcpReset: inboundNATRule.?enableTcpReset + frontendPortRangeEnd: inboundNATRule.?frontendPortRangeEnd + frontendPortRangeStart: inboundNATRule.?frontendPortRangeStart + idleTimeoutInMinutes: inboundNATRule.?idleTimeoutInMinutes + protocol: inboundNATRule.?protocol + } + dependsOn: [ + loadBalancer_backendAddressPools + ] + } +] + +resource loadBalancer_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: loadBalancer +} + +resource loadBalancer_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: loadBalancer + } +] + +resource loadBalancer_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(loadBalancer.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: loadBalancer + } +] + +// =========== // +// Outputs // +// =========== // + +@description('The name of the load balancer.') +output name string = loadBalancer.name + +@description('The resource ID of the load balancer.') +output resourceId string = loadBalancer.id + +@description('The resource group the load balancer was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The backend address pools available in the load balancer.') +output backendpools array = loadBalancer.properties.backendAddressPools + +@description('The location the resource was deployed into.') +output location string = loadBalancer.location + +// ================ // +// Definitions // +// ================ // + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/load-balancer/main.json b/avm/1.1.0/res/network/load-balancer/main.json new file mode 100644 index 000000000..da4d836f8 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/main.json @@ -0,0 +1,930 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "761519156622598447" + }, + "name": "Load Balancers", + "description": "This module deploys a Load Balancer." + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Proximity Placement Groups Name." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a load balancer SKU." + } + }, + "frontendIPConfigurations": { + "type": "array", + "minLength": 1, + "metadata": { + "description": "Required. Array of objects containing all frontend IP configurations." + } + }, + "backendAddressPools": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Collection of backend address pools used by a load balancer." + } + }, + "loadBalancingRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Array of objects containing all load balancing rules." + } + }, + "probes": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Array of objects containing all probes, these are references in the load balancing rules." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "inboundNatRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Collection of inbound NAT Rules used by a load balancer. Defining inbound NAT rules on your load balancer is mutually exclusive with defining an inbound NAT pool. Inbound NAT pools are referenced from virtual machine scale sets. NICs that are associated with individual virtual machines cannot reference an Inbound NAT pool. They have to reference individual inbound NAT rules." + } + }, + "outboundRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The outbound rules." + } + } + }, + "variables": { + "copy": [ + { + "name": "frontendIPConfigurationsVar", + "count": "[length(parameters('frontendIPConfigurations'))]", + "input": { + "name": "[parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].name]", + "properties": { + "subnet": "[if(and(contains(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')], 'subnetId'), not(empty(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].subnetId))), createObject('id', parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].subnetId), null())]", + "publicIPAddress": "[if(and(contains(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')], 'publicIPAddressId'), not(empty(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].publicIPAddressId))), createObject('id', parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].publicIPAddressId), null())]", + "privateIPAddress": "[if(and(contains(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')], 'privateIPAddress'), not(empty(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].privateIPAddress))), parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].privateIPAddress, null())]", + "privateIPAddressVersion": "[if(contains(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')], 'privateIPAddressVersion'), parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].privateIPAddressVersion, 'IPv4')]", + "privateIPAllocationMethod": "[if(and(contains(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')], 'subnetId'), not(empty(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].subnetId))), if(contains(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')], 'privateIPAddress'), 'Static', 'Dynamic'), null())]", + "gatewayLoadBalancer": "[if(and(contains(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')], 'gatewayLoadBalancer'), not(empty(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].gatewayLoadBalancer))), createObject('id', parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].gatewayLoadBalancer), null())]", + "publicIPPrefix": "[if(and(contains(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')], 'publicIPPrefix'), not(empty(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].publicIPPrefix))), createObject('id', parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].publicIPPrefix), null())]" + }, + "zones": "[if(contains(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')], 'zones'), map(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')].zones, lambda('zone', string(lambdaVariables('zone')))), if(not(empty(tryGet(parameters('frontendIPConfigurations')[copyIndex('frontendIPConfigurationsVar')], 'subnetResourceId'))), createArray('1', '2', '3'), null()))]" + } + }, + { + "name": "loadBalancingRulesVar", + "count": "[length(coalesce(parameters('loadBalancingRules'), createArray()))]", + "input": { + "name": "[coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')].name]", + "properties": { + "backendAddressPool": { + "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')].backendAddressPoolName)]" + }, + "backendPort": "[coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')].backendPort]", + "disableOutboundSnat": "[if(contains(coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')], 'disableOutboundSnat'), coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')].disableOutboundSnat, true())]", + "enableFloatingIP": "[if(contains(coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')], 'enableFloatingIP'), coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')].enableFloatingIP, false())]", + "enableTcpReset": "[if(contains(coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')], 'enableTcpReset'), coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')].enableTcpReset, false())]", + "frontendIPConfiguration": { + "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')].frontendIPConfigurationName)]" + }, + "frontendPort": "[coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')].frontendPort]", + "idleTimeoutInMinutes": "[if(contains(coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')], 'idleTimeoutInMinutes'), coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')].idleTimeoutInMinutes, 4)]", + "loadDistribution": "[if(contains(coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')], 'loadDistribution'), coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')].loadDistribution, 'Default')]", + "probe": { + "id": "[format('{0}/probes/{1}', resourceId('Microsoft.Network/loadBalancers', parameters('name')), coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')].probeName)]" + }, + "protocol": "[if(contains(coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')], 'protocol'), coalesce(parameters('loadBalancingRules'), createArray())[copyIndex('loadBalancingRulesVar')].protocol, 'Tcp')]" + } + } + }, + { + "name": "outboundRulesVar", + "count": "[length(parameters('outboundRules'))]", + "input": { + "name": "[parameters('outboundRules')[copyIndex('outboundRulesVar')].name]", + "properties": { + "frontendIPConfigurations": [ + { + "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', parameters('name'), parameters('outboundRules')[copyIndex('outboundRulesVar')].frontendIPConfigurationName)]" + } + ], + "backendAddressPool": { + "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('name'), parameters('outboundRules')[copyIndex('outboundRulesVar')].backendAddressPoolName)]" + }, + "protocol": "[if(contains(parameters('outboundRules')[copyIndex('outboundRulesVar')], 'protocol'), parameters('outboundRules')[copyIndex('outboundRulesVar')].protocol, 'All')]", + "allocatedOutboundPorts": "[if(contains(parameters('outboundRules')[copyIndex('outboundRulesVar')], 'allocatedOutboundPorts'), parameters('outboundRules')[copyIndex('outboundRulesVar')].allocatedOutboundPorts, 63984)]", + "enableTcpReset": "[if(contains(parameters('outboundRules')[copyIndex('outboundRulesVar')], 'enableTcpReset'), parameters('outboundRules')[copyIndex('outboundRulesVar')].enableTcpReset, true())]", + "idleTimeoutInMinutes": "[if(contains(parameters('outboundRules')[copyIndex('outboundRulesVar')], 'idleTimeoutInMinutes'), parameters('outboundRules')[copyIndex('outboundRulesVar')].idleTimeoutInMinutes, 4)]" + } + } + }, + { + "name": "probesVar", + "count": "[length(coalesce(parameters('probes'), createArray()))]", + "input": { + "name": "[coalesce(parameters('probes'), createArray())[copyIndex('probesVar')].name]", + "properties": { + "protocol": "[if(contains(coalesce(parameters('probes'), createArray())[copyIndex('probesVar')], 'protocol'), coalesce(parameters('probes'), createArray())[copyIndex('probesVar')].protocol, 'Tcp')]", + "requestPath": "[if(not(equals(toLower(coalesce(parameters('probes'), createArray())[copyIndex('probesVar')].protocol), 'tcp')), coalesce(parameters('probes'), createArray())[copyIndex('probesVar')].requestPath, null())]", + "port": "[if(contains(coalesce(parameters('probes'), createArray())[copyIndex('probesVar')], 'port'), coalesce(parameters('probes'), createArray())[copyIndex('probesVar')].port, 80)]", + "intervalInSeconds": "[if(contains(coalesce(parameters('probes'), createArray())[copyIndex('probesVar')], 'intervalInSeconds'), coalesce(parameters('probes'), createArray())[copyIndex('probesVar')].intervalInSeconds, 5)]", + "numberOfProbes": "[if(contains(coalesce(parameters('probes'), createArray())[copyIndex('probesVar')], 'numberOfProbes'), coalesce(parameters('probes'), createArray())[copyIndex('probesVar')].numberOfProbes, 2)]" + } + } + }, + { + "name": "backendAddressPoolNames", + "count": "[length(coalesce(parameters('backendAddressPools'), createArray()))]", + "input": { + "name": "[coalesce(parameters('backendAddressPools'), createArray())[copyIndex('backendAddressPoolNames')].name]" + } + }, + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-loadbalancer.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "loadBalancer": { + "type": "Microsoft.Network/loadBalancers", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "properties": { + "frontendIPConfigurations": "[variables('frontendIPConfigurationsVar')]", + "loadBalancingRules": "[variables('loadBalancingRulesVar')]", + "backendAddressPools": "[variables('backendAddressPoolNames')]", + "outboundRules": "[variables('outboundRulesVar')]", + "probes": "[variables('probesVar')]" + } + }, + "loadBalancer_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/loadBalancers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "loadBalancer" + ] + }, + "loadBalancer_diagnosticSettings": { + "copy": { + "name": "loadBalancer_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/loadBalancers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "loadBalancer" + ] + }, + "loadBalancer_roleAssignments": { + "copy": { + "name": "loadBalancer_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/loadBalancers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/loadBalancers', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "loadBalancer" + ] + }, + "loadBalancer_backendAddressPools": { + "copy": { + "name": "loadBalancer_backendAddressPools", + "count": "[length(coalesce(parameters('backendAddressPools'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-loadBalancer-backendAddressPools-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "loadBalancerName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('backendAddressPools'), createArray())[copyIndex()].name]" + }, + "tunnelInterfaces": "[if(and(contains(coalesce(parameters('backendAddressPools'), createArray())[copyIndex()], 'tunnelInterfaces'), not(empty(coalesce(parameters('backendAddressPools'), createArray())[copyIndex()].tunnelInterfaces))), createObject('value', coalesce(parameters('backendAddressPools'), createArray())[copyIndex()].tunnelInterfaces), createObject('value', createArray()))]", + "loadBalancerBackendAddresses": "[if(and(contains(coalesce(parameters('backendAddressPools'), createArray())[copyIndex()], 'loadBalancerBackendAddresses'), not(empty(coalesce(parameters('backendAddressPools'), createArray())[copyIndex()].loadBalancerBackendAddresses))), createObject('value', coalesce(parameters('backendAddressPools'), createArray())[copyIndex()].loadBalancerBackendAddresses), createObject('value', createArray()))]", + "drainPeriodInSeconds": "[if(contains(coalesce(parameters('backendAddressPools'), createArray())[copyIndex()], 'drainPeriodInSeconds'), createObject('value', coalesce(parameters('backendAddressPools'), createArray())[copyIndex()].drainPeriodInSeconds), createObject('value', 0))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "1858226960694905370" + }, + "name": "Load Balancer Backend Address Pools", + "description": "This module deploys a Load Balancer Backend Address Pools." + }, + "parameters": { + "loadBalancerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent load balancer. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the backend address pool." + } + }, + "loadBalancerBackendAddresses": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of backend addresses." + } + }, + "tunnelInterfaces": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of gateway load balancer tunnel interfaces." + } + }, + "drainPeriodInSeconds": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Amount of seconds Load Balancer waits for before sending RESET to client and backend address. if value is 0 then this property will be set to null. Subscription must register the feature Microsoft.Network/SLBAllowConnectionDraining before using this property." + } + }, + "syncMode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Automatic", + "Manual" + ], + "metadata": { + "description": "Optional. Backend address synchronous mode for the backend pool." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/loadBalancers/backendAddressPools", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('loadBalancerName'), parameters('name'))]", + "properties": { + "loadBalancerBackendAddresses": "[parameters('loadBalancerBackendAddresses')]", + "tunnelInterfaces": "[parameters('tunnelInterfaces')]", + "drainPeriodInSeconds": "[if(not(equals(parameters('drainPeriodInSeconds'), 0)), parameters('drainPeriodInSeconds'), null())]", + "syncMode": "[if(not(empty(parameters('syncMode'))), parameters('syncMode'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backend address pool." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the backend address pool." + }, + "value": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', parameters('loadBalancerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the backend address pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "loadBalancer" + ] + }, + "loadBalancer_inboundNATRules": { + "copy": { + "name": "loadBalancer_inboundNATRules", + "count": "[length(parameters('inboundNatRules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LoadBalancer-inboundNatRules-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "loadBalancerName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('inboundNatRules')[copyIndex()].name]" + }, + "frontendIPConfigurationName": { + "value": "[parameters('inboundNatRules')[copyIndex()].frontendIPConfigurationName]" + }, + "frontendPort": { + "value": "[tryGet(parameters('inboundNatRules')[copyIndex()], 'frontendPort')]" + }, + "backendPort": { + "value": "[parameters('inboundNatRules')[copyIndex()].backendPort]" + }, + "backendAddressPoolName": { + "value": "[tryGet(parameters('inboundNatRules')[copyIndex()], 'backendAddressPoolName')]" + }, + "enableFloatingIP": { + "value": "[tryGet(parameters('inboundNatRules')[copyIndex()], 'enableFloatingIP')]" + }, + "enableTcpReset": { + "value": "[tryGet(parameters('inboundNatRules')[copyIndex()], 'enableTcpReset')]" + }, + "frontendPortRangeEnd": { + "value": "[tryGet(parameters('inboundNatRules')[copyIndex()], 'frontendPortRangeEnd')]" + }, + "frontendPortRangeStart": { + "value": "[tryGet(parameters('inboundNatRules')[copyIndex()], 'frontendPortRangeStart')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(parameters('inboundNatRules')[copyIndex()], 'idleTimeoutInMinutes')]" + }, + "protocol": { + "value": "[tryGet(parameters('inboundNatRules')[copyIndex()], 'protocol')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "16950982858394467575" + }, + "name": "Load Balancer Inbound NAT Rules", + "description": "This module deploys a Load Balancer Inbound NAT Rules." + }, + "parameters": { + "loadBalancerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent load balancer. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the inbound NAT rule." + } + }, + "frontendPort": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 65534, + "metadata": { + "description": "Conditional. The port for the external endpoint. Port numbers for each rule must be unique within the Load Balancer. Required if FrontendPortRangeStart and FrontendPortRangeEnd are not specified." + } + }, + "backendPort": { + "type": "int", + "minValue": 0, + "maxValue": 65535, + "metadata": { + "description": "Required. The port used for the internal endpoint." + } + }, + "backendAddressPoolName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the backend address pool." + } + }, + "enableFloatingIP": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Configures a virtual machine's endpoint for the floating IP capability required to configure a SQL AlwaysOn Availability Group. This setting is required when using the SQL AlwaysOn Availability Groups in SQL server. This setting can't be changed after you create the endpoint." + } + }, + "enableTcpReset": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Receive bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination. This element is only used when the protocol is set to TCP." + } + }, + "frontendIPConfigurationName": { + "type": "string", + "metadata": { + "description": "Required. The name of the frontend IP address to set for the inbound NAT rule." + } + }, + "frontendPortRangeEnd": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 65534, + "metadata": { + "description": "Conditonal. The port range end for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeStart. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Required if FrontendPort is not specified." + } + }, + "frontendPortRangeStart": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 65534, + "metadata": { + "description": "Conditional. The port range start for the external endpoint. This property is used together with BackendAddressPool and FrontendPortRangeEnd. Individual inbound NAT rule port mappings will be created for each backend address from BackendAddressPool. Required if FrontendPort is not specified." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The timeout for the TCP idle connection. The value can be set between 4 and 30 minutes. The default value is 4 minutes. This element is only used when the protocol is set to TCP." + } + }, + "protocol": { + "type": "string", + "defaultValue": "Tcp", + "allowedValues": [ + "All", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Optional. The transport protocol for the endpoint." + } + } + }, + "resources": { + "loadBalancer": { + "existing": true, + "type": "Microsoft.Network/loadBalancers", + "apiVersion": "2023-11-01", + "name": "[parameters('loadBalancerName')]" + }, + "inboundNatRule": { + "type": "Microsoft.Network/loadBalancers/inboundNatRules", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('loadBalancerName'), parameters('name'))]", + "properties": { + "frontendPort": "[parameters('frontendPort')]", + "backendPort": "[parameters('backendPort')]", + "backendAddressPool": "[if(not(empty(parameters('backendAddressPoolName'))), createObject('id', format('{0}/backendAddressPools/{1}', resourceId('Microsoft.Network/loadBalancers', parameters('loadBalancerName')), parameters('backendAddressPoolName'))), null())]", + "enableFloatingIP": "[parameters('enableFloatingIP')]", + "enableTcpReset": "[parameters('enableTcpReset')]", + "frontendIPConfiguration": { + "id": "[format('{0}/frontendIPConfigurations/{1}', resourceId('Microsoft.Network/loadBalancers', parameters('loadBalancerName')), parameters('frontendIPConfigurationName'))]" + }, + "frontendPortRangeStart": "[parameters('frontendPortRangeStart')]", + "frontendPortRangeEnd": "[parameters('frontendPortRangeEnd')]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "protocol": "[parameters('protocol')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the inbound NAT rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the inbound NAT rule." + }, + "value": "[resourceId('Microsoft.Network/loadBalancers/inboundNatRules', parameters('loadBalancerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the inbound NAT rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "loadBalancer", + "loadBalancer_backendAddressPools" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the load balancer." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the load balancer." + }, + "value": "[resourceId('Microsoft.Network/loadBalancers', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the load balancer was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "backendpools": { + "type": "array", + "metadata": { + "description": "The backend address pools available in the load balancer." + }, + "value": "[reference('loadBalancer').backendAddressPools]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('loadBalancer', '2023-11-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/load-balancer/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/load-balancer/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..54ec47a19 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,25 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +resource publicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id diff --git a/avm/1.1.0/res/network/load-balancer/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/load-balancer/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..e342a4e89 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,77 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.loadbalancers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nlbmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}03' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + frontendIPConfigurations: [ + { + name: 'publicIPConfig1' + publicIPAddressId: nestedDependencies.outputs.publicIPResourceId + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/load-balancer/tests/e2e/external/dependencies.bicep b/avm/1.1.0/res/network/load-balancer/tests/e2e/external/dependencies.bicep new file mode 100644 index 000000000..c54f364b8 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/tests/e2e/external/dependencies.bicep @@ -0,0 +1,36 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource publicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/load-balancer/tests/e2e/external/main.test.bicep b/avm/1.1.0/res/network/load-balancer/tests/e2e/external/main.test.bicep new file mode 100644 index 000000000..3ca8a9b98 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/tests/e2e/external/main.test.bicep @@ -0,0 +1,196 @@ +targetScope = 'subscription' + +metadata name = 'Using external load balancer parameter' +metadata description = 'This instance deploys the module with an externally facing load balancer.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.loadbalancers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nlbext' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + frontendIPConfigurations: [ + { + name: 'publicIPConfig1' + publicIPAddressId: nestedDependencies.outputs.publicIPResourceId + } + ] + backendAddressPools: [ + { + name: 'backendAddressPool1' + } + { + name: 'backendAddressPool2' + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + inboundNatRules: [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendPort: 3389 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 3389 + name: 'inboundNatRule2' + } + ] + loadBalancingRules: [ + { + backendAddressPoolName: 'backendAddressPool1' + backendPort: 80 + disableOutboundSnat: true + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 80 + idleTimeoutInMinutes: 5 + loadDistribution: 'Default' + name: 'publicIPLBRule1' + probeName: 'probe1' + protocol: 'Tcp' + } + { + backendAddressPoolName: 'backendAddressPool2' + backendPort: 8080 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 8080 + loadDistribution: 'Default' + name: 'publicIPLBRule2' + probeName: 'probe2' + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + outboundRules: [ + { + allocatedOutboundPorts: 63984 + backendAddressPoolName: 'backendAddressPool1' + frontendIPConfigurationName: 'publicIPConfig1' + name: 'outboundRule1' + } + ] + probes: [ + { + intervalInSeconds: 10 + name: 'probe1' + numberOfProbes: 5 + port: 80 + protocol: 'Http' + requestPath: '/http-probe' + } + { + name: 'probe2' + port: 443 + protocol: 'Https' + requestPath: '/https-probe' + } + ] + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/load-balancer/tests/e2e/internal/dependencies.bicep b/avm/1.1.0/res/network/load-balancer/tests/e2e/internal/dependencies.bicep new file mode 100644 index 000000000..e5b8f3fe0 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/tests/e2e/internal/dependencies.bicep @@ -0,0 +1,41 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/load-balancer/tests/e2e/internal/main.test.bicep b/avm/1.1.0/res/network/load-balancer/tests/e2e/internal/main.test.bicep new file mode 100644 index 000000000..8a5795806 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/tests/e2e/internal/main.test.bicep @@ -0,0 +1,138 @@ +targetScope = 'subscription' + +metadata name = 'Using internal load balancer parameter' +metadata description = 'This instance deploys the module with the minimum set of required parameters to deploy an internal load balancer.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.loadbalancers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nlbint' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + frontendIPConfigurations: [ + { + name: 'privateIPConfig1' + subnetId: nestedDependencies.outputs.subnetResourceId + } + ] + backendAddressPools: [ + { + name: 'servers' + } + ] + inboundNatRules: [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendPort: 3389 + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 3389 + name: 'inboundNatRule2' + } + ] + skuName: 'Standard' + loadBalancingRules: [ + { + backendAddressPoolName: 'servers' + backendPort: 0 + disableOutboundSnat: true + enableFloatingIP: true + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 0 + idleTimeoutInMinutes: 4 + loadDistribution: 'Default' + name: 'privateIPLBRule1' + probeName: 'probe1' + protocol: 'All' + } + ] + probes: [ + { + intervalInSeconds: 5 + name: 'probe1' + numberOfProbes: 2 + port: '62000' + protocol: 'Tcp' + } + ] + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/load-balancer/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/load-balancer/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..c54f364b8 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/tests/e2e/max/dependencies.bicep @@ -0,0 +1,36 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource publicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/load-balancer/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/load-balancer/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..aedecd6e8 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/tests/e2e/max/main.test.bicep @@ -0,0 +1,202 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.loadbalancers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nlbmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + frontendIPConfigurations: [ + { + name: 'publicIPConfig1' + publicIPAddressId: nestedDependencies.outputs.publicIPResourceId + } + ] + backendAddressPools: [ + { + name: 'backendAddressPool1' + } + { + name: 'backendAddressPool2' + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + inboundNatRules: [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendPort: 3389 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 3389 + name: 'inboundNatRule2' + } + ] + loadBalancingRules: [ + { + backendAddressPoolName: 'backendAddressPool1' + backendPort: 80 + disableOutboundSnat: true + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 80 + idleTimeoutInMinutes: 5 + loadDistribution: 'Default' + name: 'publicIPLBRule1' + probeName: 'probe1' + protocol: 'Tcp' + } + { + backendAddressPoolName: 'backendAddressPool2' + backendPort: 8080 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 8080 + loadDistribution: 'Default' + name: 'publicIPLBRule2' + probeName: 'probe2' + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + outboundRules: [ + { + allocatedOutboundPorts: 63984 + backendAddressPoolName: 'backendAddressPool1' + frontendIPConfigurationName: 'publicIPConfig1' + name: 'outboundRule1' + } + ] + probes: [ + { + intervalInSeconds: 10 + name: 'probe1' + numberOfProbes: 5 + port: 80 + protocol: 'Tcp' + } + { + name: 'probe2' + port: 443 + protocol: 'Https' + requestPath: '/' + } + ] + roleAssignments: [ + { + name: '3a5b2a4a-3584-4d6b-9cf0-ceb1e4f88a5d' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/load-balancer/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/load-balancer/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..e5b8f3fe0 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,41 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/load-balancer/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/load-balancer/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..a989ed1eb --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,155 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module with the minimum set of required parameters to deploy a WAF-aligned internal load balancer.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.loadbalancers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nlbwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + frontendIPConfigurations: [ + { + name: 'privateIPConfig1' + subnetId: nestedDependencies.outputs.subnetResourceId + zones: [ + 1 + 2 + 3 + ] + } + ] + backendAddressPools: [ + { + name: 'servers' + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + inboundNatRules: [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendAddressPoolName: 'servers' + backendPort: 3389 + frontendIPConfigurationName: 'privateIPConfig1' + frontendPortRangeStart: 5000 + frontendPortRangeEnd: 5010 + loadDistribution: 'Default' + name: 'inboundNatRule2' + probeName: 'probe2' + } + ] + skuName: 'Standard' + loadBalancingRules: [ + { + backendAddressPoolName: 'servers' + backendPort: 0 + disableOutboundSnat: true + enableFloatingIP: true + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 0 + idleTimeoutInMinutes: 4 + loadDistribution: 'Default' + name: 'privateIPLBRule1' + probeName: 'probe1' + protocol: 'All' + } + ] + probes: [ + { + intervalInSeconds: 5 + name: 'probe1' + numberOfProbes: 2 + port: '62000' + protocol: 'Tcp' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/load-balancer/version.json b/avm/1.1.0/res/network/load-balancer/version.json new file mode 100644 index 000000000..13669e660 --- /dev/null +++ b/avm/1.1.0/res/network/load-balancer/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.4", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/local-network-gateway/README.md b/avm/1.1.0/res/network/local-network-gateway/README.md new file mode 100644 index 000000000..eeac57706 --- /dev/null +++ b/avm/1.1.0/res/network/local-network-gateway/README.md @@ -0,0 +1,665 @@ +# Local Network Gateways `[Microsoft.Network/localNetworkGateways]` + +This module deploys a Local Network Gateway. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/localNetworkGateways` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/localNetworkGateways) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/local-network-gateway:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module localNetworkGateway 'br/public:avm/res/network/local-network-gateway:' = { + name: 'localNetworkGatewayDeployment' + params: { + // Required parameters + localAddressPrefixes: [ + '192.168.1.0/24' + ] + localGatewayPublicIpAddress: '8.8.8.8' + name: 'nlngmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "localAddressPrefixes": { + "value": [ + "192.168.1.0/24" + ] + }, + "localGatewayPublicIpAddress": { + "value": "8.8.8.8" + }, + "name": { + "value": "nlngmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/local-network-gateway:' + +// Required parameters +param localAddressPrefixes = [ + '192.168.1.0/24' +] +param localGatewayPublicIpAddress = '8.8.8.8' +param name = 'nlngmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module localNetworkGateway 'br/public:avm/res/network/local-network-gateway:' = { + name: 'localNetworkGatewayDeployment' + params: { + // Required parameters + localAddressPrefixes: [ + '192.168.1.0/24' + ] + localGatewayPublicIpAddress: '8.8.8.8' + name: 'nlngmax001' + // Non-required parameters + localAsn: '65123' + localBgpPeeringAddress: '192.168.1.5' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'd14a9fe8-2358-434a-a715-3d10978088cc' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "localAddressPrefixes": { + "value": [ + "192.168.1.0/24" + ] + }, + "localGatewayPublicIpAddress": { + "value": "8.8.8.8" + }, + "name": { + "value": "nlngmax001" + }, + // Non-required parameters + "localAsn": { + "value": "65123" + }, + "localBgpPeeringAddress": { + "value": "192.168.1.5" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "d14a9fe8-2358-434a-a715-3d10978088cc", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/local-network-gateway:' + +// Required parameters +param localAddressPrefixes = [ + '192.168.1.0/24' +] +param localGatewayPublicIpAddress = '8.8.8.8' +param name = 'nlngmax001' +// Non-required parameters +param localAsn = '65123' +param localBgpPeeringAddress = '192.168.1.5' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'd14a9fe8-2358-434a-a715-3d10978088cc' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module localNetworkGateway 'br/public:avm/res/network/local-network-gateway:' = { + name: 'localNetworkGatewayDeployment' + params: { + // Required parameters + localAddressPrefixes: [ + '192.168.1.0/24' + ] + localGatewayPublicIpAddress: '8.8.8.8' + name: 'nlngwaf001' + // Non-required parameters + localAsn: '65123' + localBgpPeeringAddress: '192.168.1.5' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "localAddressPrefixes": { + "value": [ + "192.168.1.0/24" + ] + }, + "localGatewayPublicIpAddress": { + "value": "8.8.8.8" + }, + "name": { + "value": "nlngwaf001" + }, + // Non-required parameters + "localAsn": { + "value": "65123" + }, + "localBgpPeeringAddress": { + "value": "192.168.1.5" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/local-network-gateway:' + +// Required parameters +param localAddressPrefixes = [ + '192.168.1.0/24' +] +param localGatewayPublicIpAddress = '8.8.8.8' +param name = 'nlngwaf001' +// Non-required parameters +param localAsn = '65123' +param localBgpPeeringAddress = '192.168.1.5' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`localAddressPrefixes`](#parameter-localaddressprefixes) | array | List of the local (on-premises) IP address ranges. | +| [`localGatewayPublicIpAddress`](#parameter-localgatewaypublicipaddress) | string | Public IP of the local gateway. | +| [`name`](#parameter-name) | string | Name of the Local Network Gateway. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`fqdn`](#parameter-fqdn) | string | FQDN of local network gateway. | +| [`localAsn`](#parameter-localasn) | string | The BGP speaker's ASN. Not providing this value will automatically disable BGP on this Local Network Gateway resource. | +| [`localBgpPeeringAddress`](#parameter-localbgppeeringaddress) | string | The BGP peering address and BGP identifier of this BGP speaker. Not providing this value will automatically disable BGP on this Local Network Gateway resource. | +| [`localPeerWeight`](#parameter-localpeerweight) | string | The weight added to routes learned from this BGP speaker. This will only take effect if both the localAsn and the localBgpPeeringAddress values are provided. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `localAddressPrefixes` + +List of the local (on-premises) IP address ranges. + +- Required: Yes +- Type: array + +### Parameter: `localGatewayPublicIpAddress` + +Public IP of the local gateway. + +- Required: Yes +- Type: string + +### Parameter: `name` + +Name of the Local Network Gateway. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `fqdn` + +FQDN of local network gateway. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `localAsn` + +The BGP speaker's ASN. Not providing this value will automatically disable BGP on this Local Network Gateway resource. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `localBgpPeeringAddress` + +The BGP peering address and BGP identifier of this BGP speaker. Not providing this value will automatically disable BGP on this Local Network Gateway resource. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `localPeerWeight` + +The weight added to routes learned from this BGP speaker. This will only take effect if both the localAsn and the localBgpPeeringAddress values are provided. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the local network gateway. | +| `resourceGroupName` | string | The resource group the local network gateway was deployed into. | +| `resourceId` | string | The resource ID of the local network gateway. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/local-network-gateway/main.bicep b/avm/1.1.0/res/network/local-network-gateway/main.bicep new file mode 100644 index 000000000..d8c01dd9c --- /dev/null +++ b/avm/1.1.0/res/network/local-network-gateway/main.bicep @@ -0,0 +1,191 @@ +metadata name = 'Local Network Gateways' +metadata description = 'This module deploys a Local Network Gateway.' + +@description('Required. Name of the Local Network Gateway.') +@minLength(1) +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Required. List of the local (on-premises) IP address ranges.') +param localAddressPrefixes array + +@description('Required. Public IP of the local gateway.') +param localGatewayPublicIpAddress string + +@description('Optional. The BGP speaker\'s ASN. Not providing this value will automatically disable BGP on this Local Network Gateway resource.') +param localAsn string = '' + +@description('Optional. The BGP peering address and BGP identifier of this BGP speaker. Not providing this value will automatically disable BGP on this Local Network Gateway resource.') +param localBgpPeeringAddress string = '' + +@description('Optional. The weight added to routes learned from this BGP speaker. This will only take effect if both the localAsn and the localBgpPeeringAddress values are provided.') +param localPeerWeight string = '' + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. FQDN of local network gateway.') +param fqdn string = '' + +var bgpSettings = { + asn: localAsn + bgpPeeringAddress: localBgpPeeringAddress + peerWeight: !empty(localPeerWeight) ? localPeerWeight : '0' +} + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.res.network-localnetworkgateway.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + localNetworkAddressSpace: { + addressPrefixes: localAddressPrefixes + } + fqdn: !empty(fqdn) ? fqdn : null + gatewayIpAddress: localGatewayPublicIpAddress + bgpSettings: !empty(localAsn) && !empty(localBgpPeeringAddress) ? bgpSettings : null + } +} + +resource localNetworkGateway_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: localNetworkGateway +} + +resource localNetworkGateway_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + localNetworkGateway.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: localNetworkGateway + } +] + +@description('The resource ID of the local network gateway.') +output resourceId string = localNetworkGateway.id + +@description('The resource group the local network gateway was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the local network gateway.') +output name string = localNetworkGateway.name + +@description('The location the resource was deployed into.') +output location string = localNetworkGateway.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/local-network-gateway/main.json b/avm/1.1.0/res/network/local-network-gateway/main.json new file mode 100644 index 000000000..fc55f7838 --- /dev/null +++ b/avm/1.1.0/res/network/local-network-gateway/main.json @@ -0,0 +1,321 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "13708664764642631468" + }, + "name": "Local Network Gateways", + "description": "This module deploys a Local Network Gateway." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the Local Network Gateway." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "localAddressPrefixes": { + "type": "array", + "metadata": { + "description": "Required. List of the local (on-premises) IP address ranges." + } + }, + "localGatewayPublicIpAddress": { + "type": "string", + "metadata": { + "description": "Required. Public IP of the local gateway." + } + }, + "localAsn": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The BGP speaker's ASN. Not providing this value will automatically disable BGP on this Local Network Gateway resource." + } + }, + "localBgpPeeringAddress": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The BGP peering address and BGP identifier of this BGP speaker. Not providing this value will automatically disable BGP on this Local Network Gateway resource." + } + }, + "localPeerWeight": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The weight added to routes learned from this BGP speaker. This will only take effect if both the localAsn and the localBgpPeeringAddress values are provided." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "fqdn": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. FQDN of local network gateway." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "bgpSettings": { + "asn": "[parameters('localAsn')]", + "bgpPeeringAddress": "[parameters('localBgpPeeringAddress')]", + "peerWeight": "[if(not(empty(parameters('localPeerWeight'))), parameters('localPeerWeight'), '0')]" + }, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.res.network-localnetworkgateway.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "localNetworkGateway": { + "type": "Microsoft.Network/localNetworkGateways", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "localNetworkAddressSpace": { + "addressPrefixes": "[parameters('localAddressPrefixes')]" + }, + "fqdn": "[if(not(empty(parameters('fqdn'))), parameters('fqdn'), null())]", + "gatewayIpAddress": "[parameters('localGatewayPublicIpAddress')]", + "bgpSettings": "[if(and(not(empty(parameters('localAsn'))), not(empty(parameters('localBgpPeeringAddress')))), variables('bgpSettings'), null())]" + } + }, + "localNetworkGateway_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/localNetworkGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "localNetworkGateway" + ] + }, + "localNetworkGateway_roleAssignments": { + "copy": { + "name": "localNetworkGateway_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/localNetworkGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/localNetworkGateways', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "localNetworkGateway" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the local network gateway." + }, + "value": "[resourceId('Microsoft.Network/localNetworkGateways', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the local network gateway was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the local network gateway." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('localNetworkGateway', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/local-network-gateway/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/local-network-gateway/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..1d3a803c2 --- /dev/null +++ b/avm/1.1.0/res/network/local-network-gateway/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,52 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.localnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nlngmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + localAddressPrefixes: [ + '192.168.1.0/24' + ] + localGatewayPublicIpAddress: '8.8.8.8' + } + } +] diff --git a/avm/1.1.0/res/network/local-network-gateway/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/local-network-gateway/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/network/local-network-gateway/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/local-network-gateway/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/local-network-gateway/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..edff8a7f5 --- /dev/null +++ b/avm/1.1.0/res/network/local-network-gateway/tests/e2e/max/main.test.bicep @@ -0,0 +1,94 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.localnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nlngmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + localAddressPrefixes: [ + '192.168.1.0/24' + ] + localGatewayPublicIpAddress: '8.8.8.8' + localAsn: '65123' + localBgpPeeringAddress: '192.168.1.5' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'd14a9fe8-2358-434a-a715-3d10978088cc' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/local-network-gateway/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/local-network-gateway/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..b2f1caefb --- /dev/null +++ b/avm/1.1.0/res/network/local-network-gateway/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,63 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.localnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nlngwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + localAddressPrefixes: [ + '192.168.1.0/24' + ] + localGatewayPublicIpAddress: '8.8.8.8' + localAsn: '65123' + localBgpPeeringAddress: '192.168.1.5' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/local-network-gateway/version.json b/avm/1.1.0/res/network/local-network-gateway/version.json new file mode 100644 index 000000000..76049e1c4 --- /dev/null +++ b/avm/1.1.0/res/network/local-network-gateway/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/nat-gateway/README.md b/avm/1.1.0/res/network/nat-gateway/README.md new file mode 100644 index 000000000..48846ff68 --- /dev/null +++ b/avm/1.1.0/res/network/nat-gateway/README.md @@ -0,0 +1,1012 @@ +# NAT Gateways `[Microsoft.Network/natGateways]` + +This module deploys a NAT Gateway. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/natGateways` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/natGateways) | +| `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | +| `Microsoft.Network/publicIPPrefixes` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPPrefixes) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/nat-gateway:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using an existing Public IP](#example-2-using-an-existing-public-ip) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [Combine a generated and provided Public IP Prefix](#example-4-combine-a-generated-and-provided-public-ip-prefix) +- [WAF-aligned](#example-5-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module natGateway 'br/public:avm/res/network/nat-gateway:' = { + name: 'natGatewayDeployment' + params: { + // Required parameters + name: 'nngmin001' + zone: 1 + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nngmin001" + }, + "zone": { + "value": 1 + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/nat-gateway:' + +// Required parameters +param name = 'nngmin001' +param zone = 1 +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using an existing Public IP_ + +This instance deploys the module using an existing Public IP address. + + +

+ +via Bicep module + +```bicep +module natGateway 'br/public:avm/res/network/nat-gateway:' = { + name: 'natGatewayDeployment' + params: { + // Required parameters + name: 'nngepip001' + zone: 1 + // Non-required parameters + location: '' + publicIpResourceIds: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nngepip001" + }, + "zone": { + "value": 1 + }, + // Non-required parameters + "location": { + "value": "" + }, + "publicIpResourceIds": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/nat-gateway:' + +// Required parameters +param name = 'nngepip001' +param zone = 1 +// Non-required parameters +param location = '' +param publicIpResourceIds = '' +``` + +
+

+ +### Example 3: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module natGateway 'br/public:avm/res/network/nat-gateway:' = { + name: 'natGatewayDeployment' + params: { + // Required parameters + name: 'nngmax001' + zone: 1 + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + publicIPAddressObjects: [ + { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'nngmax001-pip' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + skuTier: 'Regional' + zones: [ + 1 + 2 + 3 + ] + } + ] + roleAssignments: [ + { + name: '69d7ed51-8af4-4eed-bcea-bdadcccb1200' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nngmax001" + }, + "zone": { + "value": 1 + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "publicIPAddressObjects": { + "value": [ + { + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "name": "nngmax001-pip", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "skuTier": "Regional", + "zones": [ + 1, + 2, + 3 + ] + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "69d7ed51-8af4-4eed-bcea-bdadcccb1200", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/nat-gateway:' + +// Required parameters +param name = 'nngmax001' +param zone = 1 +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param publicIPAddressObjects = [ + { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'nngmax001-pip' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + skuTier: 'Regional' + zones: [ + 1 + 2 + 3 + ] + } +] +param roleAssignments = [ + { + name: '69d7ed51-8af4-4eed-bcea-bdadcccb1200' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 4: _Combine a generated and provided Public IP Prefix_ + +This example shows how you can provide a Public IP Prefix to the module, while also generating one in the module. + + +

+ +via Bicep module + +```bicep +module natGateway 'br/public:avm/res/network/nat-gateway:' = { + name: 'natGatewayDeployment' + params: { + // Required parameters + name: 'nngcprx001' + zone: 0 + // Non-required parameters + location: '' + publicIPPrefixObjects: [ + { + name: 'nngcprx001-pippre' + prefixLength: 30 + tags: { + 'hidden-title': 'CustomTag' + } + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nngcprx001" + }, + "zone": { + "value": 0 + }, + // Non-required parameters + "location": { + "value": "" + }, + "publicIPPrefixObjects": { + "value": [ + { + "name": "nngcprx001-pippre", + "prefixLength": 30, + "tags": { + "hidden-title": "CustomTag" + } + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/nat-gateway:' + +// Required parameters +param name = 'nngcprx001' +param zone = 0 +// Non-required parameters +param location = '' +param publicIPPrefixObjects = [ + { + name: 'nngcprx001-pippre' + prefixLength: 30 + tags: { + 'hidden-title': 'CustomTag' + } + } +] +``` + +
+

+ +### Example 5: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module natGateway 'br/public:avm/res/network/nat-gateway:' = { + name: 'natGatewayDeployment' + params: { + // Required parameters + name: 'nngwaf001' + zone: 1 + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + publicIPAddressObjects: [ + { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'nngwaf001-pip' + skuTier: 'Regional' + zones: [ + 1 + 2 + 3 + ] + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nngwaf001" + }, + "zone": { + "value": 1 + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "publicIPAddressObjects": { + "value": [ + { + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "name": "nngwaf001-pip", + "skuTier": "Regional", + "zones": [ + 1, + 2, + 3 + ] + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/nat-gateway:' + +// Required parameters +param name = 'nngwaf001' +param zone = 1 +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param publicIPAddressObjects = [ + { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'nngwaf001-pip' + skuTier: 'Regional' + zones: [ + 1 + 2 + 3 + ] + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Azure Bastion resource. | +| [`zone`](#parameter-zone) | int | A list of availability zones denoting the zone in which Nat Gateway should be deployed. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`idleTimeoutInMinutes`](#parameter-idletimeoutinminutes) | int | The idle timeout of the NAT gateway. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`publicIPAddressObjects`](#parameter-publicipaddressobjects) | array | Specifies the properties of the Public IPs to create and be used by the NAT Gateway. | +| [`publicIPPrefixObjects`](#parameter-publicipprefixobjects) | array | Specifies the properties of the Public IP Prefixes to create and be used by the NAT Gateway. | +| [`publicIPPrefixResourceIds`](#parameter-publicipprefixresourceids) | array | Existing Public IP Prefixes resource IDs to use for the NAT Gateway. | +| [`publicIpResourceIds`](#parameter-publicipresourceids) | array | Existing Public IP Address resource IDs to use for the NAT Gateway. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags for the resource. | + +### Parameter: `name` + +Name of the Azure Bastion resource. + +- Required: Yes +- Type: string + +### Parameter: `zone` + +A list of availability zones denoting the zone in which Nat Gateway should be deployed. + +- Required: Yes +- Type: int +- Allowed: + ```Bicep + [ + 0 + 1 + 2 + 3 + ] + ``` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `idleTimeoutInMinutes` + +The idle timeout of the NAT gateway. + +- Required: No +- Type: int +- Default: `5` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `publicIPAddressObjects` + +Specifies the properties of the Public IPs to create and be used by the NAT Gateway. + +- Required: No +- Type: array + +### Parameter: `publicIPPrefixObjects` + +Specifies the properties of the Public IP Prefixes to create and be used by the NAT Gateway. + +- Required: No +- Type: array + +### Parameter: `publicIPPrefixResourceIds` + +Existing Public IP Prefixes resource IDs to use for the NAT Gateway. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `publicIpResourceIds` + +Existing Public IP Address resource IDs to use for the NAT Gateway. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags for the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the NAT Gateway. | +| `resourceGroupName` | string | The resource group the NAT Gateway was deployed into. | +| `resourceId` | string | The resource ID of the NAT Gateway. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/public-ip-address:0.5.1` | Remote reference | +| `br/public:avm/res/network/public-ip-prefix:0.4.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/nat-gateway/main.bicep b/avm/1.1.0/res/network/nat-gateway/main.bicep new file mode 100644 index 000000000..04a52c5ae --- /dev/null +++ b/avm/1.1.0/res/network/nat-gateway/main.bicep @@ -0,0 +1,248 @@ +metadata name = 'NAT Gateways' +metadata description = 'This module deploys a NAT Gateway.' + +@description('Required. Name of the Azure Bastion resource.') +param name string + +@description('Required. A list of availability zones denoting the zone in which Nat Gateway should be deployed.') +@allowed([ + 0 + 1 + 2 + 3 +]) +param zone int + +@description('Optional. The idle timeout of the NAT gateway.') +param idleTimeoutInMinutes int = 5 + +@description('Optional. Existing Public IP Address resource IDs to use for the NAT Gateway.') +param publicIpResourceIds array = [] + +@description('Optional. Existing Public IP Prefixes resource IDs to use for the NAT Gateway.') +param publicIPPrefixResourceIds array = [] + +@description('Optional. Specifies the properties of the Public IPs to create and be used by the NAT Gateway.') +param publicIPAddressObjects array? + +@description('Optional. Specifies the properties of the Public IP Prefixes to create and be used by the NAT Gateway.') +param publicIPPrefixObjects array? + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags for the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.res.network-natgateway.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +module publicIPAddresses 'br/public:avm/res/network/public-ip-address:0.5.1' = [ + for (publicIPAddressObject, index) in (publicIPAddressObjects ?? []): { + name: '${uniqueString(deployment().name, location)}-NatGw-PIP-${index}' + params: { + name: publicIPAddressObject.?name ?? '${name}-pip' + location: location + lock: publicIPAddressObject.?lock ?? lock + diagnosticSettings: publicIPAddressObject.?diagnosticSettings + publicIPAddressVersion: publicIPAddressObject.?publicIPAddressVersion + publicIPAllocationMethod: 'Static' + publicIpPrefixResourceId: publicIPAddressObject.?publicIPPrefixResourceId + roleAssignments: publicIPAddressObject.?roleAssignments + skuName: 'Standard' // Must be standard + skuTier: publicIPAddressObject.?skuTier + tags: publicIPAddressObject.?tags ?? tags + zones: publicIPAddressObject.?zones ?? (zone != 0 ? [zone] : null) + enableTelemetry: publicIPAddressObject.?enableTelemetry ?? enableTelemetry + ddosSettings: publicIPAddressObject.?ddosSettings + dnsSettings: publicIPAddressObject.?dnsSettings + idleTimeoutInMinutes: publicIPAddressObject.?idleTimeoutInMinutes + } + } +] + +module formattedPublicIpResourceIds 'modules/formatResourceId.bicep' = { + name: '${uniqueString(deployment().name, location)}-formattedPublicIpResourceIds' + params: { + generatedResourceIds: [ + for (obj, index) in (publicIPAddressObjects ?? []): publicIPAddresses[index].outputs.resourceId + ] + providedResourceIds: publicIpResourceIds + } +} + +module publicIPPrefixes 'br/public:avm/res/network/public-ip-prefix:0.4.1' = [ + for (publicIPPrefixObject, index) in (publicIPPrefixObjects ?? []): { + name: '${uniqueString(deployment().name, location)}-NatGw-Prefix-PIP-${index}' + params: { + name: publicIPPrefixObject.?name ?? '${name}-pip' + location: location + lock: publicIPPrefixObject.?lock ?? lock + prefixLength: publicIPPrefixObject.prefixLength + customIPPrefix: publicIPPrefixObject.?customIPPrefix + roleAssignments: publicIPPrefixObject.?roleAssignments + tags: publicIPPrefixObject.?tags ?? tags + enableTelemetry: publicIPPrefixObject.?enableTelemetry ?? enableTelemetry + } + } +] +module formattedPublicIpPrefixResourceIds 'modules/formatResourceId.bicep' = { + name: '${uniqueString(deployment().name, location)}-formattedPublicIpPrefixResourceIds' + params: { + generatedResourceIds: [ + for (obj, index) in (publicIPPrefixObjects ?? []): publicIPPrefixes[index].outputs.resourceId + ] + providedResourceIds: publicIPPrefixResourceIds + } +} + +// NAT GATEWAY +// =========== +resource natGateway 'Microsoft.Network/natGateways@2023-04-01' = { + name: name + location: location + tags: tags + sku: { + name: 'Standard' + } + properties: { + idleTimeoutInMinutes: idleTimeoutInMinutes + publicIpPrefixes: formattedPublicIpPrefixResourceIds.outputs.formattedResourceIds + publicIpAddresses: formattedPublicIpResourceIds.outputs.formattedResourceIds + } + zones: zone != 0 ? [string(zone)] : null +} + +resource natGateway_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: natGateway +} + +resource natGateway_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(natGateway.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: natGateway + } +] + +@description('The name of the NAT Gateway.') +output name string = natGateway.name + +@description('The resource ID of the NAT Gateway.') +output resourceId string = natGateway.id + +@description('The resource group the NAT Gateway was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = natGateway.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/nat-gateway/main.json b/avm/1.1.0/res/network/nat-gateway/main.json new file mode 100644 index 000000000..ef2596e61 --- /dev/null +++ b/avm/1.1.0/res/network/nat-gateway/main.json @@ -0,0 +1,1485 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "6945935143037087267" + }, + "name": "NAT Gateways", + "description": "This module deploys a NAT Gateway." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure Bastion resource." + } + }, + "zone": { + "type": "int", + "allowedValues": [ + 0, + 1, + 2, + 3 + ], + "metadata": { + "description": "Required. A list of availability zones denoting the zone in which Nat Gateway should be deployed." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 5, + "metadata": { + "description": "Optional. The idle timeout of the NAT gateway." + } + }, + "publicIpResourceIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Existing Public IP Address resource IDs to use for the NAT Gateway." + } + }, + "publicIPPrefixResourceIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Existing Public IP Prefixes resource IDs to use for the NAT Gateway." + } + }, + "publicIPAddressObjects": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the properties of the Public IPs to create and be used by the NAT Gateway." + } + }, + "publicIPPrefixObjects": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the properties of the Public IP Prefixes to create and be used by the NAT Gateway." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.res.network-natgateway.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "natGateway": { + "type": "Microsoft.Network/natGateways", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "Standard" + }, + "properties": { + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "publicIpPrefixes": "[reference('formattedPublicIpPrefixResourceIds').outputs.formattedResourceIds.value]", + "publicIpAddresses": "[reference('formattedPublicIpResourceIds').outputs.formattedResourceIds.value]" + }, + "zones": "[if(not(equals(parameters('zone'), 0)), createArray(string(parameters('zone'))), null())]", + "dependsOn": [ + "formattedPublicIpPrefixResourceIds", + "formattedPublicIpResourceIds" + ] + }, + "natGateway_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/natGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "natGateway" + ] + }, + "natGateway_roleAssignments": { + "copy": { + "name": "natGateway_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/natGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/natGateways', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "natGateway" + ] + }, + "publicIPAddresses": { + "copy": { + "name": "publicIPAddresses", + "count": "[length(coalesce(parameters('publicIPAddressObjects'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NatGw-PIP-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'name'), format('{0}-pip', parameters('name')))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "diagnosticSettings": { + "value": "[tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'diagnosticSettings')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "Static" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'publicIPPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "skuName": { + "value": "Standard" + }, + "skuTier": { + "value": "[tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "zones": { + "value": "[coalesce(tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'zones'), if(not(equals(parameters('zone'), 0)), createArray(parameters('zone')), null()))]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "ddosSettings": { + "value": "[tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'dnsSettings')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'idleTimeoutInMinutes')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "14450344965065009842" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "", + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "metadata": { + "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + } + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.5.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": null + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" + } + } + } + } + }, + "formattedPublicIpResourceIds": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-formattedPublicIpResourceIds', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "generatedResourceIds": { + "copy": [ + { + "name": "value", + "count": "[length(coalesce(parameters('publicIPAddressObjects'), createArray()))]", + "input": "[reference(format('publicIPAddresses[{0}]', copyIndex('value'))).outputs.resourceId.value]" + } + ] + }, + "providedResourceIds": { + "value": "[parameters('publicIpResourceIds')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "1685955788035758459" + } + }, + "parameters": { + "generatedResourceIds": { + "type": "array", + "defaultValue": [] + }, + "providedResourceIds": { + "type": "array", + "defaultValue": [] + } + }, + "resources": [], + "outputs": { + "formattedResourceIds": { + "type": "array", + "copy": { + "count": "[length(concat(parameters('generatedResourceIds'), parameters('providedResourceIds')))]", + "input": { + "id": "[concat(parameters('generatedResourceIds'), parameters('providedResourceIds'))[copyIndex()]]" + } + } + } + } + } + }, + "dependsOn": [ + "publicIPAddresses" + ] + }, + "publicIPPrefixes": { + "copy": { + "name": "publicIPPrefixes", + "count": "[length(coalesce(parameters('publicIPPrefixObjects'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NatGw-Prefix-PIP-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('publicIPPrefixObjects'), createArray())[copyIndex()], 'name'), format('{0}-pip', parameters('name')))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('publicIPPrefixObjects'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "prefixLength": { + "value": "[coalesce(parameters('publicIPPrefixObjects'), createArray())[copyIndex()].prefixLength]" + }, + "customIPPrefix": { + "value": "[tryGet(coalesce(parameters('publicIPPrefixObjects'), createArray())[copyIndex()], 'customIPPrefix')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('publicIPPrefixObjects'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('publicIPPrefixObjects'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('publicIPPrefixObjects'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "2051021969117142516" + }, + "name": "Public IP Prefixes", + "description": "This module deploys a Public IP Prefix.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. The name of the Public IP Prefix." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "prefixLength": { + "type": "int", + "minValue": 28, + "maxValue": 31, + "metadata": { + "description": "Required. Length of the Public IP Prefix." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "customIPPrefix": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The custom IP address prefix that this prefix is associated with. A custom IP address prefix is a contiguous range of IP addresses owned by an external customer and provisioned into a subscription. When a custom IP prefix is in Provisioned, Commissioning, or Commissioned state, a linked public IP prefix can be created. Either as a subset of the custom IP prefix range or the entire range." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipprefix.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpPrefix": { + "type": "Microsoft.Network/publicIPPrefixes", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "Standard" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "customIPPrefix": "[if(not(empty(parameters('customIPPrefix'))), parameters('customIPPrefix'), null())]", + "publicIPAddressVersion": "IPv4", + "prefixLength": "[parameters('prefixLength')]" + } + }, + "publicIpPrefix_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPPrefixes/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "publicIpPrefix" + ] + }, + "publicIpPrefix_roleAssignments": { + "copy": { + "name": "publicIpPrefix_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPPrefixes/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPPrefixes', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpPrefix" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP prefix." + }, + "value": "[resourceId('Microsoft.Network/publicIPPrefixes', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP prefix was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP prefix." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpPrefix', '2023-09-01', 'full').location]" + } + } + } + } + }, + "formattedPublicIpPrefixResourceIds": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-formattedPublicIpPrefixResourceIds', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "generatedResourceIds": { + "copy": [ + { + "name": "value", + "count": "[length(coalesce(parameters('publicIPPrefixObjects'), createArray()))]", + "input": "[reference(format('publicIPPrefixes[{0}]', copyIndex('value'))).outputs.resourceId.value]" + } + ] + }, + "providedResourceIds": { + "value": "[parameters('publicIPPrefixResourceIds')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "1685955788035758459" + } + }, + "parameters": { + "generatedResourceIds": { + "type": "array", + "defaultValue": [] + }, + "providedResourceIds": { + "type": "array", + "defaultValue": [] + } + }, + "resources": [], + "outputs": { + "formattedResourceIds": { + "type": "array", + "copy": { + "count": "[length(concat(parameters('generatedResourceIds'), parameters('providedResourceIds')))]", + "input": { + "id": "[concat(parameters('generatedResourceIds'), parameters('providedResourceIds'))[copyIndex()]]" + } + } + } + } + } + }, + "dependsOn": [ + "publicIPPrefixes" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the NAT Gateway." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the NAT Gateway." + }, + "value": "[resourceId('Microsoft.Network/natGateways', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the NAT Gateway was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('natGateway', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/nat-gateway/modules/formatResourceId.bicep b/avm/1.1.0/res/network/nat-gateway/modules/formatResourceId.bicep new file mode 100644 index 000000000..b4aa1ad77 --- /dev/null +++ b/avm/1.1.0/res/network/nat-gateway/modules/formatResourceId.bicep @@ -0,0 +1,6 @@ +param generatedResourceIds array = [] +param providedResourceIds array = [] + +output formattedResourceIds array = [for resourceId in concat(generatedResourceIds, providedResourceIds): { + id: resourceId +}] diff --git a/avm/1.1.0/res/network/nat-gateway/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/nat-gateway/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..282c6fcd1 --- /dev/null +++ b/avm/1.1.0/res/network/nat-gateway/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,52 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +// e.g., for a module 'network/private-endpoint' you could use 'dep-dev-network.privateendpoints-${serviceShort}-rg' +param resourceGroupName string = 'dep-${namePrefix}-network.natgateway-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +// e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test +param serviceShort string = 'nngmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + // You parameters go here + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + zone: 1 + } + } +] diff --git a/avm/1.1.0/res/network/nat-gateway/tests/e2e/existingPip/dependencies.bicep b/avm/1.1.0/res/network/nat-gateway/tests/e2e/existingPip/dependencies.bicep new file mode 100644 index 000000000..d12b008b0 --- /dev/null +++ b/avm/1.1.0/res/network/nat-gateway/tests/e2e/existingPip/dependencies.bicep @@ -0,0 +1,25 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Public IP to create.') +param existingPipName string + +resource existingPip 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: existingPipName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +@description('The resource ID of the existing Public IP.') +output existingPipResourceId string = existingPip.id diff --git a/avm/1.1.0/res/network/nat-gateway/tests/e2e/existingPip/main.test.bicep b/avm/1.1.0/res/network/nat-gateway/tests/e2e/existingPip/main.test.bicep new file mode 100644 index 000000000..1b1384820 --- /dev/null +++ b/avm/1.1.0/res/network/nat-gateway/tests/e2e/existingPip/main.test.bicep @@ -0,0 +1,61 @@ +targetScope = 'subscription' + +metadata name = 'Using an existing Public IP' +metadata description = 'This instance deploys the module using an existing Public IP address.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.natgateway-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nngepip' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + existingPipName: '${namePrefix}${serviceShort}001-existingpip1' + + } +} + + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + zone: 1 + publicIpResourceIds: [nestedDependencies.outputs.existingPipResourceId] + } + } +] diff --git a/avm/1.1.0/res/network/nat-gateway/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/nat-gateway/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/network/nat-gateway/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/nat-gateway/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/nat-gateway/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..0420b10ad --- /dev/null +++ b/avm/1.1.0/res/network/nat-gateway/tests/e2e/max/main.test.bicep @@ -0,0 +1,144 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.natgateway-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nngmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + zone: 1 + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + publicIPAddressObjects: [ + { + name: '${namePrefix}${serviceShort}001-pip' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + skuTier: 'Regional' + zones: [1, 2, 3] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + ] + roleAssignments: [ + { + name: '69d7ed51-8af4-4eed-bcea-bdadcccb1200' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/nat-gateway/tests/e2e/prefixCombined/main.test.bicep b/avm/1.1.0/res/network/nat-gateway/tests/e2e/prefixCombined/main.test.bicep new file mode 100644 index 000000000..70bea4996 --- /dev/null +++ b/avm/1.1.0/res/network/nat-gateway/tests/e2e/prefixCombined/main.test.bicep @@ -0,0 +1,58 @@ +targetScope = 'subscription' + +metadata name = 'Combine a generated and provided Public IP Prefix' +metadata description = 'This example shows how you can provide a Public IP Prefix to the module, while also generating one in the module.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.natgateway-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nngcprx' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + zone: 0 + publicIPPrefixObjects: [ + { + name: '${namePrefix}${serviceShort}001-pippre' + prefixLength: 30 + tags: { + 'hidden-title': 'CustomTag' + } + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/nat-gateway/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/nat-gateway/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..ad2c02dbe --- /dev/null +++ b/avm/1.1.0/res/network/nat-gateway/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,93 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.natgateway-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nngwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + zone: 1 + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + publicIPAddressObjects: [ + { + name: '${namePrefix}${serviceShort}001-pip' + skuTier: 'Regional' + zones: [1, 2, 3] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/nat-gateway/tests/unit/avm.core.team.tests.ps1 b/avm/1.1.0/res/network/nat-gateway/tests/unit/avm.core.team.tests.ps1 new file mode 100644 index 000000000..e0d041ea7 --- /dev/null +++ b/avm/1.1.0/res/network/nat-gateway/tests/unit/avm.core.team.tests.ps1 @@ -0,0 +1,39 @@ +<# +.SYNOPSIS +This file contains Pester tests that the AVM Core Team has written for the module. Any additions or changes to these tests will need to be reviewed by the AVM Core Team, this is handled by CODEOWNERS. + +If you wish to add your own Pester tests for you module create a new .tests.ps1 file in the /tests/unit folder of your module. +#> + +param ( + [Parameter(Mandatory = $false)] + [array] $moduleFolderPaths, + + [Parameter(Mandatory = $false)] + [string] $repoRootPath +) + +BeforeAll { + . (Join-Path $RepoRootPath 'utilities' 'pipelines' 'sharedScripts' 'helper' 'Get-IsParameterRequired.ps1') + + if ($moduleFolderPaths.Count -gt 1) { + $topLevelModuleTemplatePath = $moduleFolderPaths | Sort-Object -Culture 'en-US' | Select-Object -First 1 + } else { + $topLevelModuleTemplatePath = $moduleFolderPaths + } + + $moduleJsonContentHashtable = Get-Content -Path (Join-Path $topLevelModuleTemplatePath 'main.json') | ConvertFrom-Json -AsHashtable +} + +Describe 'AVM Core Team Module Specific Tests' { + + Context 'WAF - Reliability Pillar - Parameter Tests' { + + It 'NAT Gateway Module Availability Zone Parameter Should Not Have A Default Value Set' { + $isRequired = Get-IsParameterRequired -TemplateFileContent $moduleJsonContentHashtable -Parameter $moduleJsonContentHashtable.parameters.zone + $isRequired | Should -Be $true + } + + } + +} diff --git a/avm/1.1.0/res/network/nat-gateway/version.json b/avm/1.1.0/res/network/nat-gateway/version.json new file mode 100644 index 000000000..2b6eff08f --- /dev/null +++ b/avm/1.1.0/res/network/nat-gateway/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "1.2", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-interface/README.md b/avm/1.1.0/res/network/network-interface/README.md new file mode 100644 index 000000000..a9368e215 --- /dev/null +++ b/avm/1.1.0/res/network/network-interface/README.md @@ -0,0 +1,996 @@ +# Network Interface `[Microsoft.Network/networkInterfaces]` + +This module deploys a Network Interface. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/networkInterfaces` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkInterfaces) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/network-interface:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module networkInterface 'br/public:avm/res/network/network-interface:' = { + name: 'networkInterfaceDeployment' + params: { + // Required parameters + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + name: 'nnimin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "ipConfigurations": { + "value": [ + { + "name": "ipconfig01", + "subnetResourceId": "" + } + ] + }, + "name": { + "value": "nnimin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-interface:' + +// Required parameters +param ipConfigurations = [ + { + name: 'ipconfig01' + subnetResourceId: '' + } +] +param name = 'nnimin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module networkInterface 'br/public:avm/res/network/network-interface:' = { + name: 'networkInterfaceDeployment' + params: { + // Required parameters + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + subnetResourceId: '' + } + { + applicationSecurityGroups: [ + { + id: '' + } + ] + subnetResourceId: '' + } + ] + name: 'nnimax001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '026b830f-441f-469a-8cf3-c3ea9f5bcfe1' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "ipConfigurations": { + "value": [ + { + "applicationSecurityGroups": [ + { + "id": "" + } + ], + "loadBalancerBackendAddressPools": [ + { + "id": "" + } + ], + "name": "ipconfig01", + "subnetResourceId": "" + }, + { + "applicationSecurityGroups": [ + { + "id": "" + } + ], + "subnetResourceId": "" + } + ] + }, + "name": { + "value": "nnimax001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "026b830f-441f-469a-8cf3-c3ea9f5bcfe1", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-interface:' + +// Required parameters +param ipConfigurations = [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + subnetResourceId: '' + } + { + applicationSecurityGroups: [ + { + id: '' + } + ] + subnetResourceId: '' + } +] +param name = 'nnimax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '026b830f-441f-469a-8cf3-c3ea9f5bcfe1' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module networkInterface 'br/public:avm/res/network/network-interface:' = { + name: 'networkInterfaceDeployment' + params: { + // Required parameters + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + subnetResourceId: '' + } + { + applicationSecurityGroups: [ + { + id: '' + } + ] + subnetResourceId: '' + } + ] + name: 'nniwaf001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "ipConfigurations": { + "value": [ + { + "applicationSecurityGroups": [ + { + "id": "" + } + ], + "loadBalancerBackendAddressPools": [ + { + "id": "" + } + ], + "name": "ipconfig01", + "subnetResourceId": "" + }, + { + "applicationSecurityGroups": [ + { + "id": "" + } + ], + "subnetResourceId": "" + } + ] + }, + "name": { + "value": "nniwaf001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-interface:' + +// Required parameters +param ipConfigurations = [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + subnetResourceId: '' + } + { + applicationSecurityGroups: [ + { + id: '' + } + ] + subnetResourceId: '' + } +] +param name = 'nniwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipConfigurations`](#parameter-ipconfigurations) | array | A list of IPConfigurations of the network interface. | +| [`name`](#parameter-name) | string | The name of the network interface. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`auxiliaryMode`](#parameter-auxiliarymode) | string | Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic. | +| [`auxiliarySku`](#parameter-auxiliarysku) | string | Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`disableTcpStateTracking`](#parameter-disabletcpstatetracking) | bool | Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true. | +| [`dnsServers`](#parameter-dnsservers) | array | List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection. | +| [`enableAcceleratedNetworking`](#parameter-enableacceleratednetworking) | bool | If the network interface is accelerated networking enabled. | +| [`enableIPForwarding`](#parameter-enableipforwarding) | bool | Indicates whether IP forwarding is enabled on this network interface. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`networkSecurityGroupResourceId`](#parameter-networksecuritygroupresourceid) | string | The network security group (NSG) to attach to the network interface. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Resource tags. | + +### Parameter: `ipConfigurations` + +A list of IPConfigurations of the network interface. + +- Required: Yes +- Type: array + +### Parameter: `name` + +The name of the network interface. + +- Required: Yes +- Type: string + +### Parameter: `auxiliaryMode` + +Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic. + +- Required: No +- Type: string +- Default: `'None'` +- Allowed: + ```Bicep + [ + 'Floating' + 'MaxConnections' + 'None' + ] + ``` + +### Parameter: `auxiliarySku` + +Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic. + +- Required: No +- Type: string +- Default: `'None'` +- Allowed: + ```Bicep + [ + 'A1' + 'A2' + 'A4' + 'A8' + 'None' + ] + ``` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `disableTcpStateTracking` + +Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `dnsServers` + +List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `enableAcceleratedNetworking` + +If the network interface is accelerated networking enabled. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableIPForwarding` + +Indicates whether IP forwarding is enabled on this network interface. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `networkSecurityGroupResourceId` + +The network security group (NSG) to attach to the network interface. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed resource. | +| `resourceGroupName` | string | The resource group of the deployed resource. | +| `resourceId` | string | The resource ID of the deployed resource. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/network-interface/main.bicep b/avm/1.1.0/res/network/network-interface/main.bicep new file mode 100644 index 000000000..61e66e85c --- /dev/null +++ b/avm/1.1.0/res/network/network-interface/main.bicep @@ -0,0 +1,333 @@ +metadata name = 'Network Interface' +metadata description = 'This module deploys a Network Interface.' + +@description('Required. The name of the network interface.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Resource tags.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Indicates whether IP forwarding is enabled on this network interface.') +param enableIPForwarding bool = false + +@description('Optional. If the network interface is accelerated networking enabled.') +param enableAcceleratedNetworking bool = false + +@description('Optional. List of DNS servers IP addresses. Use \'AzureProvidedDNS\' to switch to azure provided DNS resolution. \'AzureProvidedDNS\' value cannot be combined with other IPs, it must be the only value in dnsServers collection.') +param dnsServers array = [] + +@description('Optional. The network security group (NSG) to attach to the network interface.') +param networkSecurityGroupResourceId string = '' + +@allowed([ + 'Floating' + 'MaxConnections' + 'None' +]) +@description('Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic.') +param auxiliaryMode string = 'None' + +@allowed([ + 'A1' + 'A2' + 'A4' + 'A8' + 'None' +]) +@description('Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic.') +param auxiliarySku string = 'None' + +@description('Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true.') +param disableTcpStateTracking bool = false + +@description('Required. A list of IPConfigurations of the network interface.') +param ipConfigurations array + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +// =========== // +// Variables // +// =========== // + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-networkinterface.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource networkInterface 'Microsoft.Network/networkInterfaces@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + auxiliaryMode: auxiliaryMode + auxiliarySku: auxiliarySku + disableTcpStateTracking: disableTcpStateTracking + dnsSettings: !empty(dnsServers) + ? { + dnsServers: dnsServers + } + : null + enableAcceleratedNetworking: enableAcceleratedNetworking + enableIPForwarding: enableIPForwarding + networkSecurityGroup: !empty(networkSecurityGroupResourceId) + ? { + id: networkSecurityGroupResourceId + } + : null + ipConfigurations: [ + for (ipConfiguration, index) in ipConfigurations: { + name: contains(ipConfiguration, 'name') ? ipConfiguration.name : 'ipconfig0${index + 1}' + properties: { + primary: index == 0 ? true : false + privateIPAllocationMethod: contains(ipConfiguration, 'privateIPAllocationMethod') + ? (!empty(ipConfiguration.privateIPAllocationMethod) ? ipConfiguration.privateIPAllocationMethod : null) + : null + privateIPAddress: contains(ipConfiguration, 'privateIPAddress') + ? (!empty(ipConfiguration.privateIPAddress) ? ipConfiguration.privateIPAddress : null) + : null + publicIPAddress: contains(ipConfiguration, 'publicIPAddressResourceId') + ? (ipConfiguration.publicIPAddressResourceId != null + ? { + id: ipConfiguration.publicIPAddressResourceId + } + : null) + : null + subnet: { + id: ipConfiguration.subnetResourceId + } + loadBalancerBackendAddressPools: contains(ipConfiguration, 'loadBalancerBackendAddressPools') + ? ipConfiguration.loadBalancerBackendAddressPools + : null + applicationSecurityGroups: contains(ipConfiguration, 'applicationSecurityGroups') + ? ipConfiguration.applicationSecurityGroups + : null + applicationGatewayBackendAddressPools: contains(ipConfiguration, 'applicationGatewayBackendAddressPools') + ? ipConfiguration.applicationGatewayBackendAddressPools + : null + gatewayLoadBalancer: contains(ipConfiguration, 'gatewayLoadBalancer') + ? ipConfiguration.gatewayLoadBalancer + : null + loadBalancerInboundNatRules: contains(ipConfiguration, 'loadBalancerInboundNatRules') + ? ipConfiguration.loadBalancerInboundNatRules + : null + privateIPAddressVersion: contains(ipConfiguration, 'privateIPAddressVersion') + ? ipConfiguration.privateIPAddressVersion + : null + virtualNetworkTaps: contains(ipConfiguration, 'virtualNetworkTaps') + ? ipConfiguration.virtualNetworkTaps + : null + } + } + ] + } +} + +resource networkInterface_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: networkInterface +} + +resource networkInterface_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: networkInterface + } +] + +resource networkInterface_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(networkInterface.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: networkInterface + } +] + +// =========== // +// Outputs // +// =========== // +@description('The name of the deployed resource.') +output name string = networkInterface.name + +@description('The resource ID of the deployed resource.') +output resourceId string = networkInterface.id + +@description('The resource group of the deployed resource.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = networkInterface.location + +// ================ // +// Definitions // +// ================ // + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? diff --git a/avm/1.1.0/res/network/network-interface/main.json b/avm/1.1.0/res/network/network-interface/main.json new file mode 100644 index 000000000..f5769506b --- /dev/null +++ b/avm/1.1.0/res/network/network-interface/main.json @@ -0,0 +1,528 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "11102907122675548882" + }, + "name": "Network Interface", + "description": "This module deploys a Network Interface." + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the network interface." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "dnsServers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "auxiliaryMode": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Floating", + "MaxConnections", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "auxiliarySku": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "A1", + "A2", + "A4", + "A8", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "disableTcpStateTracking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "description": "Required. A list of IPConfigurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "ipConfigurations", + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].name, format('ipconfig0{0}', add(copyIndex('ipConfigurations'), 1)))]", + "properties": { + "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", + "privateIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod, null()), null())]", + "privateIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress, null()), null())]", + "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId, null())), createObject('id', parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId), null()), null())]", + "subnet": { + "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" + }, + "loadBalancerBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerBackendAddressPools, null())]", + "applicationSecurityGroups": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationSecurityGroups, null())]", + "applicationGatewayBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationGatewayBackendAddressPools, null())]", + "gatewayLoadBalancer": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].gatewayLoadBalancer, null())]", + "loadBalancerInboundNatRules": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerInboundNatRules, null())]", + "privateIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddressVersion, null())]", + "virtualNetworkTaps": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].virtualNetworkTaps, null())]" + } + } + } + ], + "auxiliaryMode": "[parameters('auxiliaryMode')]", + "auxiliarySku": "[parameters('auxiliarySku')]", + "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", + "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "enableIPForwarding": "[parameters('enableIPForwarding')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" + } + }, + "networkInterface_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_diagnosticSettings": { + "copy": { + "name": "networkInterface_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_roleAssignments": { + "copy": { + "name": "networkInterface_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkInterface" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed resource." + }, + "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed resource." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkInterface', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-interface/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/network-interface/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..4a0984bd0 --- /dev/null +++ b/avm/1.1.0/res/network/network-interface/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,30 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/1.1.0/res/network/network-interface/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/network-interface/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..eb4bb2e19 --- /dev/null +++ b/avm/1.1.0/res/network/network-interface/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,66 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.networkinterfaces-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnimin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + ] + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/network-interface/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/network-interface/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..18b4a0123 --- /dev/null +++ b/avm/1.1.0/res/network/network-interface/tests/e2e/max/dependencies.bicep @@ -0,0 +1,113 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Application Security Group to create.') +param applicationSecurityGroupName string + +@description('Required. The name of the Load Balancer to create.') +param loadBalancerName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource applicationSecurityGroup 'Microsoft.Network/applicationSecurityGroups@2023-04-01' = { + name: applicationSecurityGroupName + location: location +} + +resource loadBalancer 'Microsoft.Network/loadBalancers@2023-04-01' = { + name: loadBalancerName + location: location + sku: { + name: 'Standard' + } + + properties: { + frontendIPConfigurations: [ + { + name: 'privateIPConfig1' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + } + + resource backendPool 'backendAddressPools@2022-01-01' = { + name: 'default' + } +} + +resource inboundNatRule 'Microsoft.Network/loadBalancers/inboundNatRules@2023-04-01' = { + name: 'inboundNatRule1' + properties: { + frontendPort: 443 + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfiguration: { + id: loadBalancer.properties.frontendIPConfigurations[0].id + } + idleTimeoutInMinutes: 4 + protocol: 'Tcp' + } + parent: loadBalancer +} + +resource inboundNatRule2 'Microsoft.Network/loadBalancers/inboundNatRules@2023-04-01' = { + name: 'inboundNatRule2' + properties: { + frontendPort: 3389 + backendPort: 3389 + frontendIPConfiguration: { + id: loadBalancer.properties.frontendIPConfigurations[0].id + } + idleTimeoutInMinutes: 4 + protocol: 'Tcp' + } + parent: loadBalancer +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Application Security Group.') +output applicationSecurityGroupResourceId string = applicationSecurityGroup.id + +@description('The resource ID of the created Load Balancer Backend Pool.') +output loadBalancerBackendPoolResourceId string = loadBalancer::backendPool.id diff --git a/avm/1.1.0/res/network/network-interface/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/network-interface/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..c54b3828c --- /dev/null +++ b/avm/1.1.0/res/network/network-interface/tests/e2e/max/main.test.bicep @@ -0,0 +1,142 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.networkinterfaces-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnimax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + applicationSecurityGroupName: 'dep-${namePrefix}-asg-${serviceShort}' + loadBalancerName: 'dep-${namePrefix}-lb-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: nestedDependencies.outputs.applicationSecurityGroupResourceId + } + ] + loadBalancerBackendAddressPools: [ + { + id: nestedDependencies.outputs.loadBalancerBackendPoolResourceId + } + ] + name: 'ipconfig01' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + { + subnetResourceId: nestedDependencies.outputs.subnetResourceId + applicationSecurityGroups: [ + { + id: nestedDependencies.outputs.applicationSecurityGroupResourceId + } + ] + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '026b830f-441f-469a-8cf3-c3ea9f5bcfe1' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/network-interface/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/network-interface/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..757890a86 --- /dev/null +++ b/avm/1.1.0/res/network/network-interface/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,102 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Application Security Group to create.') +param applicationSecurityGroupName string + +@description('Required. The name of the Load Balancer to create.') +param loadBalancerName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource applicationSecurityGroup 'Microsoft.Network/applicationSecurityGroups@2023-04-01' = { + name: applicationSecurityGroupName + location: location +} + +resource loadBalancer 'Microsoft.Network/loadBalancers@2023-04-01' = { + name: loadBalancerName + location: location + sku: { + name: 'Standard' + } + + properties: { + frontendIPConfigurations: [ + { + name: 'privateIPConfig1' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + } + + resource backendPool 'backendAddressPools@2022-01-01' = { + name: 'default' + } +} + +resource inboundNatRule 'Microsoft.Network/loadBalancers/inboundNatRules@2023-04-01' = { + name: 'inboundNatRule1' + properties: { + frontendPort: 443 + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfiguration: { + id: loadBalancer.properties.frontendIPConfigurations[0].id + } + idleTimeoutInMinutes: 4 + protocol: 'Tcp' + } + parent: loadBalancer +} + +resource inboundNatRule2 'Microsoft.Network/loadBalancers/inboundNatRules@2023-04-01' = { + name: 'inboundNatRule2' + properties: { + frontendPort: 3389 + backendPort: 3389 + frontendIPConfiguration: { + id: loadBalancer.properties.frontendIPConfigurations[0].id + } + idleTimeoutInMinutes: 4 + protocol: 'Tcp' + } + parent: loadBalancer +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Application Security Group.') +output applicationSecurityGroupResourceId string = applicationSecurityGroup.id + +@description('The resource ID of the created Load Balancer Backend Pool.') +output loadBalancerBackendPoolResourceId string = loadBalancer::backendPool.id diff --git a/avm/1.1.0/res/network/network-interface/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/network-interface/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..4adc0b8d9 --- /dev/null +++ b/avm/1.1.0/res/network/network-interface/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,115 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.networkinterfaces-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nniwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + applicationSecurityGroupName: 'dep-${namePrefix}-asg-${serviceShort}' + loadBalancerName: 'dep-${namePrefix}-lb-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: nestedDependencies.outputs.applicationSecurityGroupResourceId + } + ] + loadBalancerBackendAddressPools: [ + { + id: nestedDependencies.outputs.loadBalancerBackendPoolResourceId + } + ] + name: 'ipconfig01' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + } + { + subnetResourceId: nestedDependencies.outputs.subnetResourceId + applicationSecurityGroups: [ + { + id: nestedDependencies.outputs.applicationSecurityGroupResourceId + } + ] + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/network-interface/version.json b/avm/1.1.0/res/network/network-interface/version.json new file mode 100644 index 000000000..13669e660 --- /dev/null +++ b/avm/1.1.0/res/network/network-interface/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.4", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-manager/README.md b/avm/1.1.0/res/network/network-manager/README.md new file mode 100644 index 000000000..1a8240461 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/README.md @@ -0,0 +1,2307 @@ +# Network Managers `[Microsoft.Network/networkManagers]` + +This module deploys a Network Manager. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/networkManagers` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers) | +| `Microsoft.Network/networkManagers/connectivityConfigurations` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/connectivityConfigurations) | +| `Microsoft.Network/networkManagers/networkGroups` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/networkGroups) | +| `Microsoft.Network/networkManagers/networkGroups/staticMembers` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/networkGroups/staticMembers) | +| `Microsoft.Network/networkManagers/routingConfigurations` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/routingConfigurations) | +| `Microsoft.Network/networkManagers/routingConfigurations/ruleCollections` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/routingConfigurations/ruleCollections) | +| `Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/routingConfigurations/ruleCollections/rules) | +| `Microsoft.Network/networkManagers/scopeConnections` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/scopeConnections) | +| `Microsoft.Network/networkManagers/securityAdminConfigurations` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/securityAdminConfigurations) | +| `Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/securityAdminConfigurations/ruleCollections) | +| `Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/securityAdminConfigurations/ruleCollections/rules) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/network-manager:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module networkManager 'br/public:avm/res/network/network-manager:' = { + name: 'networkManagerDeployment' + params: { + // Required parameters + name: 'nnmmin001' + networkManagerScopes: { + subscriptions: [ + '' + ] + } + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nnmmin001" + }, + "networkManagerScopes": { + "value": { + "subscriptions": [ + "" + ] + } + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-manager:' + +// Required parameters +param name = 'nnmmin001' +param networkManagerScopes = { + subscriptions: [ + '' + ] +} +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module networkManager 'br/public:avm/res/network/network-manager:' = { + name: 'networkManagerDeployment' + params: { + // Required parameters + name: '' + networkManagerScopes: { + managementGroups: [ + '/providers/Microsoft.Management/managementGroups/#_managementGroupId_#' + ] + } + // Non-required parameters + connectivityConfigurations: [ + { + appliesToGroups: [ + { + groupConnectivity: 'None' + isGlobal: false + networkGroupResourceId: '' + useHubGateway: false + } + ] + connectivityTopology: 'HubAndSpoke' + deleteExistingPeering: true + description: 'hubSpokeConnectivity description' + hubs: [ + { + resourceId: '' + resourceType: 'Microsoft.Network/virtualNetworks' + } + ] + isGlobal: false + name: 'hubSpokeConnectivity' + } + { + appliesToGroups: [ + { + groupConnectivity: 'DirectlyConnected' + isGlobal: true + networkGroupResourceId: '' + useHubGateway: false + } + ] + connectivityTopology: 'Mesh' + deleteExistingPeering: true + description: 'MeshConnectivity description' + isGlobal: true + name: 'MeshConnectivity-1' + } + { + appliesToGroups: [ + { + groupConnectivity: 'DirectlyConnected' + isGlobal: false + networkGroupResourceId: '' + useHubGateway: false + } + ] + connectivityTopology: 'Mesh' + isGlobal: false + name: 'MeshConnectivity-2' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + networkGroups: [ + { + description: 'network-group-spokes description' + memberType: 'VirtualNetwork' + name: 'network-group-spokes-1' + staticMembers: [ + { + name: 'virtualNetworkSpoke1' + resourceId: '' + } + { + name: 'virtualNetworkSpoke2' + resourceId: '' + } + ] + } + { + memberType: 'VirtualNetwork' + name: 'network-group-spokes-2' + staticMembers: [ + { + name: 'default' + resourceId: '' + } + ] + } + { + memberType: 'VirtualNetwork' + name: 'network-group-spokes-3' + } + { + memberType: 'Subnet' + name: 'network-groups-subnets-1' + staticMembers: [ + { + name: 'virtualNetworkSpoke1-defaultSubnet' + resourceId: '' + } + { + name: 'virtualNetworkSpoke2-defaultSubnet' + resourceId: '' + } + ] + } + ] + networkManagerScopeAccesses: [ + 'Connectivity' + 'Routing' + 'SecurityAdmin' + ] + roleAssignments: [ + { + name: 'e8472331-308c-4c77-aa31-017279d8e5b6' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + routingConfigurations: [ + { + description: 'description of the routing config' + name: 'test-routing-config-1' + } + { + name: 'test-routing-config-2' + ruleCollections: [ + { + appliesTo: [ + { + networkGroupResourceId: '' + } + ] + disableBgpRoutePropagation: false + name: 'test-routing-rule-collection-1-subnet' + rules: [ + { + destination: { + destinationAddress: 'AzureCloud' + type: 'ServiceTag' + } + name: 'test-routing-rule-1' + nextHop: { + nextHopType: 'VnetLocal' + } + } + { + destination: { + destinationAddress: '10.10.10.10/32' + type: 'AddressPrefix' + } + name: 'test-routing-rule-2' + nextHop: { + nextHopAddress: '192.168.1.1' + nextHopType: 'VirtualAppliance' + } + } + ] + } + ] + } + { + name: 'test-routing-config-3' + ruleCollections: [ + { + appliesTo: [ + { + networkGroupResourceId: '' + } + ] + name: 'test-routing-rule-collection-2-virtual-network' + } + ] + } + ] + scopeConnections: [ + { + description: 'description of the scope connection' + name: 'scope-connection-test' + resourceId: '' + tenantId: '' + } + ] + securityAdminConfigurations: [ + { + applyOnNetworkIntentPolicyBasedServices: [ + 'AllowRulesOnly' + ] + description: 'description of the security admin config' + name: 'test-security-admin-config-1' + ruleCollections: [ + { + appliesToGroups: [ + { + networkGroupResourceId: '' + } + ] + description: 'test-rule-collection-description' + name: 'test-rule-collection-1' + rules: [ + { + access: 'Allow' + description: 'test-inbound-allow-rule-1-description' + direction: 'Inbound' + name: 'test-inbound-allow-rule-1' + priority: 150 + protocol: 'Tcp' + } + { + access: 'Deny' + description: 'test-outbound-deny-rule-2-description' + direction: 'Outbound' + name: 'test-outbound-deny-rule-2' + priority: 200 + protocol: 'Tcp' + sourcePortRanges: [ + '442-445' + '80' + ] + sources: [ + { + addressPrefix: 'AppService.WestEurope' + addressPrefixType: 'ServiceTag' + } + ] + } + ] + } + { + appliesToGroups: [ + { + networkGroupResourceId: '' + } + { + networkGroupResourceId: '' + } + ] + name: 'test-rule-collection-2' + rules: [ + { + access: 'Allow' + destinationPortRanges: [ + '442-445' + '80' + ] + destinations: [ + { + addressPrefix: '192.168.20.20' + addressPrefixType: 'IPPrefix' + } + ] + direction: 'Inbound' + name: 'test-inbound-allow-rule-3' + priority: 250 + protocol: 'Tcp' + } + { + access: 'Allow' + description: 'test-inbound-allow-rule-4-description' + destinations: [ + { + addressPrefix: '172.16.0.0/24' + addressPrefixType: 'IPPrefix' + } + { + addressPrefix: '172.16.1.0/24' + addressPrefixType: 'IPPrefix' + } + ] + direction: 'Inbound' + name: 'test-inbound-allow-rule-4' + priority: 260 + protocol: 'Tcp' + sources: [ + { + addressPrefix: '10.0.0.0/24' + addressPrefixType: 'IPPrefix' + } + { + addressPrefix: '100.100.100.100' + addressPrefixType: 'IPPrefix' + } + ] + } + ] + } + ] + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "" + }, + "networkManagerScopes": { + "value": { + "managementGroups": [ + "/providers/Microsoft.Management/managementGroups/#_managementGroupId_#" + ] + } + }, + // Non-required parameters + "connectivityConfigurations": { + "value": [ + { + "appliesToGroups": [ + { + "groupConnectivity": "None", + "isGlobal": false, + "networkGroupResourceId": "", + "useHubGateway": false + } + ], + "connectivityTopology": "HubAndSpoke", + "deleteExistingPeering": true, + "description": "hubSpokeConnectivity description", + "hubs": [ + { + "resourceId": "", + "resourceType": "Microsoft.Network/virtualNetworks" + } + ], + "isGlobal": false, + "name": "hubSpokeConnectivity" + }, + { + "appliesToGroups": [ + { + "groupConnectivity": "DirectlyConnected", + "isGlobal": true, + "networkGroupResourceId": "", + "useHubGateway": false + } + ], + "connectivityTopology": "Mesh", + "deleteExistingPeering": true, + "description": "MeshConnectivity description", + "isGlobal": true, + "name": "MeshConnectivity-1" + }, + { + "appliesToGroups": [ + { + "groupConnectivity": "DirectlyConnected", + "isGlobal": false, + "networkGroupResourceId": "", + "useHubGateway": false + } + ], + "connectivityTopology": "Mesh", + "isGlobal": false, + "name": "MeshConnectivity-2" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "networkGroups": { + "value": [ + { + "description": "network-group-spokes description", + "memberType": "VirtualNetwork", + "name": "network-group-spokes-1", + "staticMembers": [ + { + "name": "virtualNetworkSpoke1", + "resourceId": "" + }, + { + "name": "virtualNetworkSpoke2", + "resourceId": "" + } + ] + }, + { + "memberType": "VirtualNetwork", + "name": "network-group-spokes-2", + "staticMembers": [ + { + "name": "default", + "resourceId": "" + } + ] + }, + { + "memberType": "VirtualNetwork", + "name": "network-group-spokes-3" + }, + { + "memberType": "Subnet", + "name": "network-groups-subnets-1", + "staticMembers": [ + { + "name": "virtualNetworkSpoke1-defaultSubnet", + "resourceId": "" + }, + { + "name": "virtualNetworkSpoke2-defaultSubnet", + "resourceId": "" + } + ] + } + ] + }, + "networkManagerScopeAccesses": { + "value": [ + "Connectivity", + "Routing", + "SecurityAdmin" + ] + }, + "roleAssignments": { + "value": [ + { + "name": "e8472331-308c-4c77-aa31-017279d8e5b6", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "routingConfigurations": { + "value": [ + { + "description": "description of the routing config", + "name": "test-routing-config-1" + }, + { + "name": "test-routing-config-2", + "ruleCollections": [ + { + "appliesTo": [ + { + "networkGroupResourceId": "" + } + ], + "disableBgpRoutePropagation": false, + "name": "test-routing-rule-collection-1-subnet", + "rules": [ + { + "destination": { + "destinationAddress": "AzureCloud", + "type": "ServiceTag" + }, + "name": "test-routing-rule-1", + "nextHop": { + "nextHopType": "VnetLocal" + } + }, + { + "destination": { + "destinationAddress": "10.10.10.10/32", + "type": "AddressPrefix" + }, + "name": "test-routing-rule-2", + "nextHop": { + "nextHopAddress": "192.168.1.1", + "nextHopType": "VirtualAppliance" + } + } + ] + } + ] + }, + { + "name": "test-routing-config-3", + "ruleCollections": [ + { + "appliesTo": [ + { + "networkGroupResourceId": "" + } + ], + "name": "test-routing-rule-collection-2-virtual-network" + } + ] + } + ] + }, + "scopeConnections": { + "value": [ + { + "description": "description of the scope connection", + "name": "scope-connection-test", + "resourceId": "", + "tenantId": "" + } + ] + }, + "securityAdminConfigurations": { + "value": [ + { + "applyOnNetworkIntentPolicyBasedServices": [ + "AllowRulesOnly" + ], + "description": "description of the security admin config", + "name": "test-security-admin-config-1", + "ruleCollections": [ + { + "appliesToGroups": [ + { + "networkGroupResourceId": "" + } + ], + "description": "test-rule-collection-description", + "name": "test-rule-collection-1", + "rules": [ + { + "access": "Allow", + "description": "test-inbound-allow-rule-1-description", + "direction": "Inbound", + "name": "test-inbound-allow-rule-1", + "priority": 150, + "protocol": "Tcp" + }, + { + "access": "Deny", + "description": "test-outbound-deny-rule-2-description", + "direction": "Outbound", + "name": "test-outbound-deny-rule-2", + "priority": 200, + "protocol": "Tcp", + "sourcePortRanges": [ + "442-445", + "80" + ], + "sources": [ + { + "addressPrefix": "AppService.WestEurope", + "addressPrefixType": "ServiceTag" + } + ] + } + ] + }, + { + "appliesToGroups": [ + { + "networkGroupResourceId": "" + }, + { + "networkGroupResourceId": "" + } + ], + "name": "test-rule-collection-2", + "rules": [ + { + "access": "Allow", + "destinationPortRanges": [ + "442-445", + "80" + ], + "destinations": [ + { + "addressPrefix": "192.168.20.20", + "addressPrefixType": "IPPrefix" + } + ], + "direction": "Inbound", + "name": "test-inbound-allow-rule-3", + "priority": 250, + "protocol": "Tcp" + }, + { + "access": "Allow", + "description": "test-inbound-allow-rule-4-description", + "destinations": [ + { + "addressPrefix": "172.16.0.0/24", + "addressPrefixType": "IPPrefix" + }, + { + "addressPrefix": "172.16.1.0/24", + "addressPrefixType": "IPPrefix" + } + ], + "direction": "Inbound", + "name": "test-inbound-allow-rule-4", + "priority": 260, + "protocol": "Tcp", + "sources": [ + { + "addressPrefix": "10.0.0.0/24", + "addressPrefixType": "IPPrefix" + }, + { + "addressPrefix": "100.100.100.100", + "addressPrefixType": "IPPrefix" + } + ] + } + ] + } + ] + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-manager:' + +// Required parameters +param name = '' +param networkManagerScopes = { + managementGroups: [ + '/providers/Microsoft.Management/managementGroups/#_managementGroupId_#' + ] +} +// Non-required parameters +param connectivityConfigurations = [ + { + appliesToGroups: [ + { + groupConnectivity: 'None' + isGlobal: false + networkGroupResourceId: '' + useHubGateway: false + } + ] + connectivityTopology: 'HubAndSpoke' + deleteExistingPeering: true + description: 'hubSpokeConnectivity description' + hubs: [ + { + resourceId: '' + resourceType: 'Microsoft.Network/virtualNetworks' + } + ] + isGlobal: false + name: 'hubSpokeConnectivity' + } + { + appliesToGroups: [ + { + groupConnectivity: 'DirectlyConnected' + isGlobal: true + networkGroupResourceId: '' + useHubGateway: false + } + ] + connectivityTopology: 'Mesh' + deleteExistingPeering: true + description: 'MeshConnectivity description' + isGlobal: true + name: 'MeshConnectivity-1' + } + { + appliesToGroups: [ + { + groupConnectivity: 'DirectlyConnected' + isGlobal: false + networkGroupResourceId: '' + useHubGateway: false + } + ] + connectivityTopology: 'Mesh' + isGlobal: false + name: 'MeshConnectivity-2' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param networkGroups = [ + { + description: 'network-group-spokes description' + memberType: 'VirtualNetwork' + name: 'network-group-spokes-1' + staticMembers: [ + { + name: 'virtualNetworkSpoke1' + resourceId: '' + } + { + name: 'virtualNetworkSpoke2' + resourceId: '' + } + ] + } + { + memberType: 'VirtualNetwork' + name: 'network-group-spokes-2' + staticMembers: [ + { + name: 'default' + resourceId: '' + } + ] + } + { + memberType: 'VirtualNetwork' + name: 'network-group-spokes-3' + } + { + memberType: 'Subnet' + name: 'network-groups-subnets-1' + staticMembers: [ + { + name: 'virtualNetworkSpoke1-defaultSubnet' + resourceId: '' + } + { + name: 'virtualNetworkSpoke2-defaultSubnet' + resourceId: '' + } + ] + } +] +param networkManagerScopeAccesses = [ + 'Connectivity' + 'Routing' + 'SecurityAdmin' +] +param roleAssignments = [ + { + name: 'e8472331-308c-4c77-aa31-017279d8e5b6' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param routingConfigurations = [ + { + description: 'description of the routing config' + name: 'test-routing-config-1' + } + { + name: 'test-routing-config-2' + ruleCollections: [ + { + appliesTo: [ + { + networkGroupResourceId: '' + } + ] + disableBgpRoutePropagation: false + name: 'test-routing-rule-collection-1-subnet' + rules: [ + { + destination: { + destinationAddress: 'AzureCloud' + type: 'ServiceTag' + } + name: 'test-routing-rule-1' + nextHop: { + nextHopType: 'VnetLocal' + } + } + { + destination: { + destinationAddress: '10.10.10.10/32' + type: 'AddressPrefix' + } + name: 'test-routing-rule-2' + nextHop: { + nextHopAddress: '192.168.1.1' + nextHopType: 'VirtualAppliance' + } + } + ] + } + ] + } + { + name: 'test-routing-config-3' + ruleCollections: [ + { + appliesTo: [ + { + networkGroupResourceId: '' + } + ] + name: 'test-routing-rule-collection-2-virtual-network' + } + ] + } +] +param scopeConnections = [ + { + description: 'description of the scope connection' + name: 'scope-connection-test' + resourceId: '' + tenantId: '' + } +] +param securityAdminConfigurations = [ + { + applyOnNetworkIntentPolicyBasedServices: [ + 'AllowRulesOnly' + ] + description: 'description of the security admin config' + name: 'test-security-admin-config-1' + ruleCollections: [ + { + appliesToGroups: [ + { + networkGroupResourceId: '' + } + ] + description: 'test-rule-collection-description' + name: 'test-rule-collection-1' + rules: [ + { + access: 'Allow' + description: 'test-inbound-allow-rule-1-description' + direction: 'Inbound' + name: 'test-inbound-allow-rule-1' + priority: 150 + protocol: 'Tcp' + } + { + access: 'Deny' + description: 'test-outbound-deny-rule-2-description' + direction: 'Outbound' + name: 'test-outbound-deny-rule-2' + priority: 200 + protocol: 'Tcp' + sourcePortRanges: [ + '442-445' + '80' + ] + sources: [ + { + addressPrefix: 'AppService.WestEurope' + addressPrefixType: 'ServiceTag' + } + ] + } + ] + } + { + appliesToGroups: [ + { + networkGroupResourceId: '' + } + { + networkGroupResourceId: '' + } + ] + name: 'test-rule-collection-2' + rules: [ + { + access: 'Allow' + destinationPortRanges: [ + '442-445' + '80' + ] + destinations: [ + { + addressPrefix: '192.168.20.20' + addressPrefixType: 'IPPrefix' + } + ] + direction: 'Inbound' + name: 'test-inbound-allow-rule-3' + priority: 250 + protocol: 'Tcp' + } + { + access: 'Allow' + description: 'test-inbound-allow-rule-4-description' + destinations: [ + { + addressPrefix: '172.16.0.0/24' + addressPrefixType: 'IPPrefix' + } + { + addressPrefix: '172.16.1.0/24' + addressPrefixType: 'IPPrefix' + } + ] + direction: 'Inbound' + name: 'test-inbound-allow-rule-4' + priority: 260 + protocol: 'Tcp' + sources: [ + { + addressPrefix: '10.0.0.0/24' + addressPrefixType: 'IPPrefix' + } + { + addressPrefix: '100.100.100.100' + addressPrefixType: 'IPPrefix' + } + ] + } + ] + } + ] + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module networkManager 'br/public:avm/res/network/network-manager:' = { + name: 'networkManagerDeployment' + params: { + // Required parameters + name: 'nnmwaf001' + networkManagerScopes: { + subscriptions: [ + '' + ] + } + // Non-required parameters + location: '' + networkManagerScopeAccesses: [ + 'SecurityAdmin' + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nnmwaf001" + }, + "networkManagerScopes": { + "value": { + "subscriptions": [ + "" + ] + } + }, + // Non-required parameters + "location": { + "value": "" + }, + "networkManagerScopeAccesses": { + "value": [ + "SecurityAdmin" + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-manager:' + +// Required parameters +param name = 'nnmwaf001' +param networkManagerScopes = { + subscriptions: [ + '' + ] +} +// Non-required parameters +param location = '' +param networkManagerScopeAccesses = [ + 'SecurityAdmin' +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Network Manager. | +| [`networkManagerScopes`](#parameter-networkmanagerscopes) | object | Scope of Network Manager. Contains a list of management groups or a list of subscriptions. This defines the boundary of network resources that this Network Manager instance can manage. If using Management Groups, ensure that the "Microsoft.Network" resource provider is registered for those Management Groups prior to deployment. Must contain at least one management group or subscription. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkGroups`](#parameter-networkgroups) | array | Network Groups and static members to create for the network manager. Required if using "connectivityConfigurations" or "securityAdminConfigurations" parameters. A network group is global container that includes a set of virtual network resources from any region. Then, configurations are applied to target the network group, which applies the configuration to all members of the group. The two types are group memberships are static and dynamic memberships. Static membership allows you to explicitly add virtual networks to a group by manually selecting individual virtual networks, and is available as a child module, while dynamic membership is defined through Azure policy. See [How Azure Policy works with Network Groups](https://learn.microsoft.com/en-us/azure/virtual-network-manager/concept-azure-policy-integration) for more details. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`connectivityConfigurations`](#parameter-connectivityconfigurations) | array | Connectivity Configurations to create for the network manager. Network manager must contain at least one network group in order to define connectivity configurations. | +| [`description`](#parameter-description) | string | A description of the Network Manager. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`networkManagerScopeAccesses`](#parameter-networkmanagerscopeaccesses) | array | Scope Access (Also known as features). String array containing any of "Connectivity", "SecurityAdmin", or "Routing". The connectivity feature allows you to create network topologies at scale. The security admin feature lets you create high-priority security rules, which take precedence over NSGs. The routing feature allows you to describe your desired routing behavior and orchestrate user-defined routes (UDRs) to create and maintain the desired routing behavior. If none of the features are required, then this parameter does not need to be specified, which then only enables features like "IPAM" and "Virtual Network Verifier". | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`routingConfigurations`](#parameter-routingconfigurations) | array | Routing Configurations requires enabling the "Routing" feature on Network Manager. A routing configuration contains a set of rule collections. Each rule collection contains one or more routing rules. | +| [`scopeConnections`](#parameter-scopeconnections) | array | Scope Connections to create for the network manager. Allows network manager to manage resources from another tenant. Supports management groups or subscriptions from another tenant. | +| [`securityAdminConfigurations`](#parameter-securityadminconfigurations) | array | Security Admin Configurations requires enabling the "SecurityAdmin" feature on Network Manager. A security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules. You then associate the rule collection with the network groups that you want to apply the security admin rules to. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `name` + +Name of the Network Manager. + +- Required: Yes +- Type: string + +### Parameter: `networkManagerScopes` + +Scope of Network Manager. Contains a list of management groups or a list of subscriptions. This defines the boundary of network resources that this Network Manager instance can manage. If using Management Groups, ensure that the "Microsoft.Network" resource provider is registered for those Management Groups prior to deployment. Must contain at least one management group or subscription. + +- Required: Yes +- Type: object + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`managementGroups`](#parameter-networkmanagerscopesmanagementgroups) | array | List of fully qualified IDs of management groups to assign to the network manager to manage. Required if `subscriptions` is not provided. Fully qualified ID format: '/providers/Microsoft.Management/managementGroups/{managementGroupId}'. | +| [`subscriptions`](#parameter-networkmanagerscopessubscriptions) | array | List of fully qualified IDs of Subscriptions to assign to the network manager to manage. Required if `managementGroups` is not provided. Fully qualified ID format: '/subscriptions/{subscriptionId}'. | + +### Parameter: `networkManagerScopes.managementGroups` + + List of fully qualified IDs of management groups to assign to the network manager to manage. Required if `subscriptions` is not provided. Fully qualified ID format: '/providers/Microsoft.Management/managementGroups/{managementGroupId}'. + +- Required: No +- Type: array + +### Parameter: `networkManagerScopes.subscriptions` + +List of fully qualified IDs of Subscriptions to assign to the network manager to manage. Required if `managementGroups` is not provided. Fully qualified ID format: '/subscriptions/{subscriptionId}'. + +- Required: No +- Type: array + +### Parameter: `networkGroups` + +Network Groups and static members to create for the network manager. Required if using "connectivityConfigurations" or "securityAdminConfigurations" parameters. A network group is global container that includes a set of virtual network resources from any region. Then, configurations are applied to target the network group, which applies the configuration to all members of the group. The two types are group memberships are static and dynamic memberships. Static membership allows you to explicitly add virtual networks to a group by manually selecting individual virtual networks, and is available as a child module, while dynamic membership is defined through Azure policy. See [How Azure Policy works with Network Groups](https://learn.microsoft.com/en-us/azure/virtual-network-manager/concept-azure-policy-integration) for more details. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-networkgroupsname) | string | The name of the network group. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-networkgroupsdescription) | string | A description of the network group. | +| [`memberType`](#parameter-networkgroupsmembertype) | string | The type of the group member. Subnet member type is used for routing configurations. | +| [`staticMembers`](#parameter-networkgroupsstaticmembers) | array | Static Members to create for the network group. Contains virtual networks to add to the network group. | + +### Parameter: `networkGroups.name` + +The name of the network group. + +- Required: Yes +- Type: string + +### Parameter: `networkGroups.description` + +A description of the network group. + +- Required: No +- Type: string + +### Parameter: `networkGroups.memberType` + +The type of the group member. Subnet member type is used for routing configurations. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Subnet' + 'VirtualNetwork' + ] + ``` + +### Parameter: `networkGroups.staticMembers` + +Static Members to create for the network group. Contains virtual networks to add to the network group. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-networkgroupsstaticmembersname) | string | The name of the static member. | +| [`resourceId`](#parameter-networkgroupsstaticmembersresourceid) | string | Resource ID of the virtual network. | + +### Parameter: `networkGroups.staticMembers.name` + +The name of the static member. + +- Required: Yes +- Type: string + +### Parameter: `networkGroups.staticMembers.resourceId` + +Resource ID of the virtual network. + +- Required: Yes +- Type: string + +### Parameter: `connectivityConfigurations` + +Connectivity Configurations to create for the network manager. Network manager must contain at least one network group in order to define connectivity configurations. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appliesToGroups`](#parameter-connectivityconfigurationsappliestogroups) | array | Network Groups for the configuration. A connectivity configuration must be associated to at least one network group. | +| [`connectivityTopology`](#parameter-connectivityconfigurationsconnectivitytopology) | string | The connectivity topology to apply the configuration to. | +| [`name`](#parameter-connectivityconfigurationsname) | string | The name of the connectivity configuration. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`deleteExistingPeering`](#parameter-connectivityconfigurationsdeleteexistingpeering) | bool | Delete existing peering connections. | +| [`description`](#parameter-connectivityconfigurationsdescription) | string | A description of the connectivity configuration. | +| [`hubs`](#parameter-connectivityconfigurationshubs) | array | The hubs to apply the configuration to. | +| [`isGlobal`](#parameter-connectivityconfigurationsisglobal) | bool | Is global configuration. | + +### Parameter: `connectivityConfigurations.appliesToGroups` + +Network Groups for the configuration. A connectivity configuration must be associated to at least one network group. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupConnectivity`](#parameter-connectivityconfigurationsappliestogroupsgroupconnectivity) | string | Group connectivity type. | +| [`networkGroupResourceId`](#parameter-connectivityconfigurationsappliestogroupsnetworkgroupresourceid) | string | Resource Id of the network group. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`isGlobal`](#parameter-connectivityconfigurationsappliestogroupsisglobal) | bool | Flag if global is supported. | +| [`useHubGateway`](#parameter-connectivityconfigurationsappliestogroupsusehubgateway) | bool | Flag if use hub gateway. | + +### Parameter: `connectivityConfigurations.appliesToGroups.groupConnectivity` + +Group connectivity type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'DirectlyConnected' + 'None' + ] + ``` + +### Parameter: `connectivityConfigurations.appliesToGroups.networkGroupResourceId` + +Resource Id of the network group. + +- Required: Yes +- Type: string + +### Parameter: `connectivityConfigurations.appliesToGroups.isGlobal` + +Flag if global is supported. + +- Required: No +- Type: bool + +### Parameter: `connectivityConfigurations.appliesToGroups.useHubGateway` + +Flag if use hub gateway. + +- Required: No +- Type: bool + +### Parameter: `connectivityConfigurations.connectivityTopology` + +The connectivity topology to apply the configuration to. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'HubAndSpoke' + 'Mesh' + ] + ``` + +### Parameter: `connectivityConfigurations.name` + +The name of the connectivity configuration. + +- Required: Yes +- Type: string + +### Parameter: `connectivityConfigurations.deleteExistingPeering` + +Delete existing peering connections. + +- Required: No +- Type: bool + +### Parameter: `connectivityConfigurations.description` + +A description of the connectivity configuration. + +- Required: No +- Type: string + +### Parameter: `connectivityConfigurations.hubs` + +The hubs to apply the configuration to. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`resourceId`](#parameter-connectivityconfigurationshubsresourceid) | string | Resource Id of the hub. | +| [`resourceType`](#parameter-connectivityconfigurationshubsresourcetype) | string | Resource type of the hub. | + +### Parameter: `connectivityConfigurations.hubs.resourceId` + +Resource Id of the hub. + +- Required: Yes +- Type: string + +### Parameter: `connectivityConfigurations.hubs.resourceType` + +Resource type of the hub. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Microsoft.Network/virtualNetworks' + ] + ``` + +### Parameter: `connectivityConfigurations.isGlobal` + +Is global configuration. + +- Required: No +- Type: bool + +### Parameter: `description` + +A description of the Network Manager. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `networkManagerScopeAccesses` + +Scope Access (Also known as features). String array containing any of "Connectivity", "SecurityAdmin", or "Routing". The connectivity feature allows you to create network topologies at scale. The security admin feature lets you create high-priority security rules, which take precedence over NSGs. The routing feature allows you to describe your desired routing behavior and orchestrate user-defined routes (UDRs) to create and maintain the desired routing behavior. If none of the features are required, then this parameter does not need to be specified, which then only enables features like "IPAM" and "Virtual Network Verifier". + +- Required: No +- Type: array +- Allowed: + ```Bicep + [ + 'Connectivity' + 'Routing' + 'SecurityAdmin' + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'IPAM Pool User'` + - `'LocalNGFirewallAdministrator role'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Resource Policy Contributor'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `routingConfigurations` + +Routing Configurations requires enabling the "Routing" feature on Network Manager. A routing configuration contains a set of rule collections. Each rule collection contains one or more routing rules. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-routingconfigurationsname) | string | The name of the routing configuration. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-routingconfigurationsdescription) | string | A description of the routing configuration. | +| [`ruleCollections`](#parameter-routingconfigurationsrulecollections) | array | Rule collections to create for the routing configuration. | + +### Parameter: `routingConfigurations.name` + +The name of the routing configuration. + +- Required: Yes +- Type: string + +### Parameter: `routingConfigurations.description` + +A description of the routing configuration. + +- Required: No +- Type: string + +### Parameter: `routingConfigurations.ruleCollections` + +Rule collections to create for the routing configuration. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appliesTo`](#parameter-routingconfigurationsrulecollectionsappliesto) | array | List of network groups for configuration. A routing rule collection must be associated to at least one network group. | +| [`name`](#parameter-routingconfigurationsrulecollectionsname) | string | The name of the rule collection. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-routingconfigurationsrulecollectionsdescription) | string | A description of the rule collection. | +| [`disableBgpRoutePropagation`](#parameter-routingconfigurationsrulecollectionsdisablebgproutepropagation) | bool | Disables BGP route propagation for the rule collection. Defaults to true. | +| [`rules`](#parameter-routingconfigurationsrulecollectionsrules) | array | List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager. | + +### Parameter: `routingConfigurations.ruleCollections.appliesTo` + +List of network groups for configuration. A routing rule collection must be associated to at least one network group. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkGroupResourceId`](#parameter-routingconfigurationsrulecollectionsappliestonetworkgroupresourceid) | string | The resource ID of the network group. | + +### Parameter: `routingConfigurations.ruleCollections.appliesTo.networkGroupResourceId` + +The resource ID of the network group. + +- Required: Yes +- Type: string + +### Parameter: `routingConfigurations.ruleCollections.name` + +The name of the rule collection. + +- Required: Yes +- Type: string + +### Parameter: `routingConfigurations.ruleCollections.description` + +A description of the rule collection. + +- Required: No +- Type: string + +### Parameter: `routingConfigurations.ruleCollections.disableBgpRoutePropagation` + +Disables BGP route propagation for the rule collection. Defaults to true. + +- Required: No +- Type: bool + +### Parameter: `routingConfigurations.ruleCollections.rules` + +List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`destination`](#parameter-routingconfigurationsrulecollectionsrulesdestination) | object | The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. | +| [`name`](#parameter-routingconfigurationsrulecollectionsrulesname) | string | The name of the rule. | +| [`nextHop`](#parameter-routingconfigurationsrulecollectionsrulesnexthop) | object | The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-routingconfigurationsrulecollectionsrulesdescription) | string | A description of the rule. | + +### Parameter: `routingConfigurations.ruleCollections.rules.destination` + +The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`destinationAddress`](#parameter-routingconfigurationsrulecollectionsrulesdestinationdestinationaddress) | string | The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be "AzureCloud", "Storage.AustraliaEast", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags. | +| [`type`](#parameter-routingconfigurationsrulecollectionsrulesdestinationtype) | string | The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. | + +### Parameter: `routingConfigurations.ruleCollections.rules.destination.destinationAddress` + +The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be "AzureCloud", "Storage.AustraliaEast", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags. + +- Required: Yes +- Type: string + +### Parameter: `routingConfigurations.ruleCollections.rules.destination.type` + +The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'AddressPrefix' + 'ServiceTag' + ] + ``` + +### Parameter: `routingConfigurations.ruleCollections.rules.name` + +The name of the rule. + +- Required: Yes +- Type: string + +### Parameter: `routingConfigurations.ruleCollections.rules.nextHop` + +The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`nextHopType`](#parameter-routingconfigurationsrulecollectionsrulesnexthopnexthoptype) | string | The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`nextHopAddress`](#parameter-routingconfigurationsrulecollectionsrulesnexthopnexthopaddress) | string | The IP address of the next hop. Required if the next hop type is VirtualAppliance. | + +### Parameter: `routingConfigurations.ruleCollections.rules.nextHop.nextHopType` + +The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Internet' + 'NoNextHop' + 'VirtualAppliance' + 'VirtualNetworkGateway' + 'VnetLocal' + ] + ``` + +### Parameter: `routingConfigurations.ruleCollections.rules.nextHop.nextHopAddress` + +The IP address of the next hop. Required if the next hop type is VirtualAppliance. + +- Required: No +- Type: string + +### Parameter: `routingConfigurations.ruleCollections.rules.description` + +A description of the rule. + +- Required: No +- Type: string + +### Parameter: `scopeConnections` + +Scope Connections to create for the network manager. Allows network manager to manage resources from another tenant. Supports management groups or subscriptions from another tenant. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-scopeconnectionsname) | string | The name of the scope connection. | +| [`resourceId`](#parameter-scopeconnectionsresourceid) | string | Enter the subscription or management group resource ID that you want to add to this network manager's scope. | +| [`tenantId`](#parameter-scopeconnectionstenantid) | string | Tenant ID of the subscription or management group that you want to manage. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-scopeconnectionsdescription) | string | A description of the scope connection. | + +### Parameter: `scopeConnections.name` + +The name of the scope connection. + +- Required: Yes +- Type: string + +### Parameter: `scopeConnections.resourceId` + +Enter the subscription or management group resource ID that you want to add to this network manager's scope. + +- Required: Yes +- Type: string + +### Parameter: `scopeConnections.tenantId` + +Tenant ID of the subscription or management group that you want to manage. + +- Required: Yes +- Type: string + +### Parameter: `scopeConnections.description` + +A description of the scope connection. + +- Required: No +- Type: string + +### Parameter: `securityAdminConfigurations` + +Security Admin Configurations requires enabling the "SecurityAdmin" feature on Network Manager. A security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules. You then associate the rule collection with the network groups that you want to apply the security admin rules to. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applyOnNetworkIntentPolicyBasedServices`](#parameter-securityadminconfigurationsapplyonnetworkintentpolicybasedservices) | array | Apply on network intent policy based services. | +| [`name`](#parameter-securityadminconfigurationsname) | string | The name of the security admin configuration. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-securityadminconfigurationsdescription) | string | A description of the security admin configuration. | +| [`ruleCollections`](#parameter-securityadminconfigurationsrulecollections) | array | Rule collections to create for the security admin configuration. | + +### Parameter: `securityAdminConfigurations.applyOnNetworkIntentPolicyBasedServices` + +Apply on network intent policy based services. + +- Required: Yes +- Type: array +- Allowed: + ```Bicep + [ + 'All' + 'AllowRulesOnly' + 'None' + ] + ``` + +### Parameter: `securityAdminConfigurations.name` + +The name of the security admin configuration. + +- Required: Yes +- Type: string + +### Parameter: `securityAdminConfigurations.description` + +A description of the security admin configuration. + +- Required: No +- Type: string + +### Parameter: `securityAdminConfigurations.ruleCollections` + +Rule collections to create for the security admin configuration. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appliesToGroups`](#parameter-securityadminconfigurationsrulecollectionsappliestogroups) | array | List of network groups for configuration. An admin rule collection must be associated to at least one network group. | +| [`name`](#parameter-securityadminconfigurationsrulecollectionsname) | string | The name of the admin rule collection. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-securityadminconfigurationsrulecollectionsdescription) | string | A description of the admin rule collection. | +| [`rules`](#parameter-securityadminconfigurationsrulecollectionsrules) | array | List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail. | + +### Parameter: `securityAdminConfigurations.ruleCollections.appliesToGroups` + +List of network groups for configuration. An admin rule collection must be associated to at least one network group. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkGroupResourceId`](#parameter-securityadminconfigurationsrulecollectionsappliestogroupsnetworkgroupresourceid) | string | The resource ID of the network group. | + +### Parameter: `securityAdminConfigurations.ruleCollections.appliesToGroups.networkGroupResourceId` + +The resource ID of the network group. + +- Required: Yes +- Type: string + +### Parameter: `securityAdminConfigurations.ruleCollections.name` + +The name of the admin rule collection. + +- Required: Yes +- Type: string + +### Parameter: `securityAdminConfigurations.ruleCollections.description` + +A description of the admin rule collection. + +- Required: No +- Type: string + +### Parameter: `securityAdminConfigurations.ruleCollections.rules` + +List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`access`](#parameter-securityadminconfigurationsrulecollectionsrulesaccess) | string | Indicates the access allowed for this particular rule. "Allow" means traffic matching this rule will be allowed. "Deny" means traffic matching this rule will be blocked. "AlwaysAllow" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs. | +| [`direction`](#parameter-securityadminconfigurationsrulecollectionsrulesdirection) | string | Indicates if the traffic matched against the rule in inbound or outbound. | +| [`name`](#parameter-securityadminconfigurationsrulecollectionsrulesname) | string | The name of the rule. | +| [`priority`](#parameter-securityadminconfigurationsrulecollectionsrulespriority) | int | The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule. | +| [`protocol`](#parameter-securityadminconfigurationsrulecollectionsrulesprotocol) | string | Network protocol this rule applies to. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-securityadminconfigurationsrulecollectionsrulesdescription) | string | A description of the rule. | +| [`destinationPortRanges`](#parameter-securityadminconfigurationsrulecollectionsrulesdestinationportranges) | array | List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. | +| [`destinations`](#parameter-securityadminconfigurationsrulecollectionsrulesdestinations) | array | The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. | +| [`sourcePortRanges`](#parameter-securityadminconfigurationsrulecollectionsrulessourceportranges) | array | List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. | +| [`sources`](#parameter-securityadminconfigurationsrulecollectionsrulessources) | array | The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. | + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.access` + +Indicates the access allowed for this particular rule. "Allow" means traffic matching this rule will be allowed. "Deny" means traffic matching this rule will be blocked. "AlwaysAllow" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Allow' + 'AlwaysAllow' + 'Deny' + ] + ``` + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.direction` + +Indicates if the traffic matched against the rule in inbound or outbound. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Inbound' + 'Outbound' + ] + ``` + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.name` + +The name of the rule. + +- Required: Yes +- Type: string + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.priority` + +The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule. + +- Required: Yes +- Type: int +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.protocol` + +Network protocol this rule applies to. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Ah' + 'Any' + 'Esp' + 'Icmp' + 'Tcp' + 'Udp' + ] + ``` +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.description` + +A description of the rule. + +- Required: No +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.destinationPortRanges` + +List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.destinations` + +The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefix`](#parameter-securityadminconfigurationsrulecollectionsrulesdestinationsaddressprefix) | string | Address prefix. | +| [`addressPrefixType`](#parameter-securityadminconfigurationsrulecollectionsrulesdestinationsaddressprefixtype) | string | Address prefix type. | + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.destinations.addressPrefix` + +Address prefix. + +- Required: Yes +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.destinations.addressPrefixType` + +Address prefix type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'IPPrefix' + 'ServiceTag' + ] + ``` +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.sourcePortRanges` + +List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.sources` + +The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefix`](#parameter-securityadminconfigurationsrulecollectionsrulessourcesaddressprefix) | string | Address prefix. | +| [`addressPrefixType`](#parameter-securityadminconfigurationsrulecollectionsrulessourcesaddressprefixtype) | string | Address prefix type. | + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.sources.addressPrefix` + +Address prefix. + +- Required: Yes +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `securityAdminConfigurations.ruleCollections.rules.sources.addressPrefixType` + +Address prefix type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'IPPrefix' + 'ServiceTag' + ] + ``` +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the network manager. | +| `resourceGroupName` | string | The resource group the network manager was deployed into. | +| `resourceId` | string | The resource ID of the network manager. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.4.1` | Remote reference | + +## Notes + +In order to deploy a Network Manager with the `networkManagerScopes` property set to `managementGroups`, you need to register the `Microsoft.Network` resource provider at the Management Group first ([ref](https://learn.microsoft.com/en-us/rest/api/resources/providers/register-at-management-group-scope)). + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/network-manager/connectivity-configuration/README.md b/avm/1.1.0/res/network/network-manager/connectivity-configuration/README.md new file mode 100644 index 000000000..0c72273f9 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/connectivity-configuration/README.md @@ -0,0 +1,191 @@ +# Network Manager Connectivity Configurations `[Microsoft.Network/networkManagers/connectivityConfigurations]` + +This module deploys a Network Manager Connectivity Configuration. +Connectivity configurations define hub-and-spoke or mesh topologies applied to one or more network groups. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkManagers/connectivityConfigurations` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/connectivityConfigurations) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appliesToGroups`](#parameter-appliestogroups) | array | Network Groups for the configuration. A connectivity configuration must be associated to at least one network group. | +| [`connectivityTopology`](#parameter-connectivitytopology) | string | Connectivity topology type. | +| [`name`](#parameter-name) | string | The name of the connectivity configuration. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`hubs`](#parameter-hubs) | array | List of hub items. This will create peerings between the specified hub and the virtual networks in the network group specified. Required if connectivityTopology is of type "HubAndSpoke". | +| [`networkManagerName`](#parameter-networkmanagername) | string | The name of the parent network manager. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`deleteExistingPeering`](#parameter-deleteexistingpeering) | bool | Flag if need to remove current existing peerings. If set to "True", all peerings on virtual networks in selected network groups will be removed and replaced with the peerings defined by this configuration. Optional when connectivityTopology is of type "HubAndSpoke". | +| [`description`](#parameter-description) | string | A description of the connectivity configuration. | +| [`isGlobal`](#parameter-isglobal) | bool | Flag if global mesh is supported. By default, mesh connectivity is applied to virtual networks within the same region. If set to "True", a global mesh enables connectivity across regions. | + +### Parameter: `appliesToGroups` + +Network Groups for the configuration. A connectivity configuration must be associated to at least one network group. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupConnectivity`](#parameter-appliestogroupsgroupconnectivity) | string | Group connectivity type. | +| [`networkGroupResourceId`](#parameter-appliestogroupsnetworkgroupresourceid) | string | Resource Id of the network group. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`isGlobal`](#parameter-appliestogroupsisglobal) | bool | Flag if global is supported. | +| [`useHubGateway`](#parameter-appliestogroupsusehubgateway) | bool | Flag if use hub gateway. | + +### Parameter: `appliesToGroups.groupConnectivity` + +Group connectivity type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'DirectlyConnected' + 'None' + ] + ``` + +### Parameter: `appliesToGroups.networkGroupResourceId` + +Resource Id of the network group. + +- Required: Yes +- Type: string + +### Parameter: `appliesToGroups.isGlobal` + +Flag if global is supported. + +- Required: No +- Type: bool + +### Parameter: `appliesToGroups.useHubGateway` + +Flag if use hub gateway. + +- Required: No +- Type: bool + +### Parameter: `connectivityTopology` + +Connectivity topology type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'HubAndSpoke' + 'Mesh' + ] + ``` + +### Parameter: `name` + +The name of the connectivity configuration. + +- Required: Yes +- Type: string + +### Parameter: `hubs` + +List of hub items. This will create peerings between the specified hub and the virtual networks in the network group specified. Required if connectivityTopology is of type "HubAndSpoke". + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`resourceId`](#parameter-hubsresourceid) | string | Resource Id of the hub. | +| [`resourceType`](#parameter-hubsresourcetype) | string | Resource type of the hub. | + +### Parameter: `hubs.resourceId` + +Resource Id of the hub. + +- Required: Yes +- Type: string + +### Parameter: `hubs.resourceType` + +Resource type of the hub. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Microsoft.Network/virtualNetworks' + ] + ``` + +### Parameter: `networkManagerName` + +The name of the parent network manager. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `deleteExistingPeering` + +Flag if need to remove current existing peerings. If set to "True", all peerings on virtual networks in selected network groups will be removed and replaced with the peerings defined by this configuration. Optional when connectivityTopology is of type "HubAndSpoke". + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `description` + +A description of the connectivity configuration. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `isGlobal` + +Flag if global mesh is supported. By default, mesh connectivity is applied to virtual networks within the same region. If set to "True", a global mesh enables connectivity across regions. + +- Required: No +- Type: bool +- Default: `False` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed connectivity configuration. | +| `resourceGroupName` | string | The resource group the connectivity configuration was deployed into. | +| `resourceId` | string | The resource ID of the deployed connectivity configuration. | diff --git a/avm/1.1.0/res/network/network-manager/connectivity-configuration/main.bicep b/avm/1.1.0/res/network/network-manager/connectivity-configuration/main.bicep new file mode 100644 index 000000000..540ac2d3b --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/connectivity-configuration/main.bicep @@ -0,0 +1,92 @@ +metadata name = 'Network Manager Connectivity Configurations' +metadata description = '''This module deploys a Network Manager Connectivity Configuration. +Connectivity configurations define hub-and-spoke or mesh topologies applied to one or more network groups.''' + +@sys.description('Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment.') +param networkManagerName string + +@maxLength(64) +@sys.description('Required. The name of the connectivity configuration.') +param name string + +@maxLength(500) +@sys.description('Optional. A description of the connectivity configuration.') +param description string = '' + +@sys.description('Required. Network Groups for the configuration. A connectivity configuration must be associated to at least one network group.') +param appliesToGroups appliesToGroupsType + +@allowed([ + 'HubAndSpoke' + 'Mesh' +]) +@sys.description('Required. Connectivity topology type.') +param connectivityTopology string + +@sys.description('Conditional. List of hub items. This will create peerings between the specified hub and the virtual networks in the network group specified. Required if connectivityTopology is of type "HubAndSpoke".') +param hubs hubsType + +@sys.description('Optional. Flag if need to remove current existing peerings. If set to "True", all peerings on virtual networks in selected network groups will be removed and replaced with the peerings defined by this configuration. Optional when connectivityTopology is of type "HubAndSpoke".') +param deleteExistingPeering bool = false + +@sys.description('Optional. Flag if global mesh is supported. By default, mesh connectivity is applied to virtual networks within the same region. If set to "True", a global mesh enables connectivity across regions.') +param isGlobal bool = false + +resource networkManager 'Microsoft.Network/networkManagers@2024-05-01' existing = { + name: networkManagerName +} + +resource connectivityConfiguration 'Microsoft.Network/networkManagers/connectivityConfigurations@2024-05-01' = { + name: name + parent: networkManager + properties: { + appliesToGroups: map(appliesToGroups, (group) => { + groupConnectivity: group.groupConnectivity + isGlobal: string(group.isGlobal) ?? 'false' + networkGroupId: any(group.networkGroupResourceId) + useHubGateway: string(group.useHubGateway) ?? 'false' + }) + connectivityTopology: connectivityTopology + deleteExistingPeering: connectivityTopology == 'HubAndSpoke' ? string(deleteExistingPeering) : 'false' + description: description + hubs: connectivityTopology == 'HubAndSpoke' ? hubs : [] + isGlobal: string(isGlobal) + } +} + +@sys.description('The name of the deployed connectivity configuration.') +output name string = connectivityConfiguration.name + +@sys.description('The resource ID of the deployed connectivity configuration.') +output resourceId string = connectivityConfiguration.id + +@sys.description('The resource group the connectivity configuration was deployed into.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +@export() +type appliesToGroupsType = { + @sys.description('Required. Group connectivity type.') + groupConnectivity: ('DirectlyConnected' | 'None') + + @sys.description('Optional. Flag if global is supported.') + isGlobal: bool? + + @sys.description('Required. Resource Id of the network group.') + networkGroupResourceId: string + + @sys.description('Optional. Flag if use hub gateway.') + useHubGateway: bool? +}[] + +@export() +type hubsType = { + @sys.description('Required. Resource Id of the hub.') + resourceId: string + + @sys.description('Required. Resource type of the hub.') + resourceType: 'Microsoft.Network/virtualNetworks' +}[]? diff --git a/avm/1.1.0/res/network/network-manager/connectivity-configuration/main.json b/avm/1.1.0/res/network/network-manager/connectivity-configuration/main.json new file mode 100644 index 000000000..1ca58107d --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/connectivity-configuration/main.json @@ -0,0 +1,187 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "14947854714653371230" + }, + "name": "Network Manager Connectivity Configurations", + "description": "This module deploys a Network Manager Connectivity Configuration.\nConnectivity configurations define hub-and-spoke or mesh topologies applied to one or more network groups." + }, + "definitions": { + "appliesToGroupsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "groupConnectivity": { + "type": "string", + "allowedValues": [ + "DirectlyConnected", + "None" + ], + "metadata": { + "description": "Required. Group connectivity type." + } + }, + "isGlobal": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag if global is supported." + } + }, + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource Id of the network group." + } + }, + "useHubGateway": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag if use hub gateway." + } + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "hubsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource Id of the hub." + } + }, + "resourceType": { + "type": "string", + "allowedValues": [ + "Microsoft.Network/virtualNetworks" + ], + "metadata": { + "description": "Required. Resource type of the hub." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the connectivity configuration." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the connectivity configuration." + } + }, + "appliesToGroups": { + "$ref": "#/definitions/appliesToGroupsType", + "metadata": { + "description": "Required. Network Groups for the configuration. A connectivity configuration must be associated to at least one network group." + } + }, + "connectivityTopology": { + "type": "string", + "allowedValues": [ + "HubAndSpoke", + "Mesh" + ], + "metadata": { + "description": "Required. Connectivity topology type." + } + }, + "hubs": { + "$ref": "#/definitions/hubsType", + "metadata": { + "description": "Conditional. List of hub items. This will create peerings between the specified hub and the virtual networks in the network group specified. Required if connectivityTopology is of type \"HubAndSpoke\"." + } + }, + "deleteExistingPeering": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag if need to remove current existing peerings. If set to \"True\", all peerings on virtual networks in selected network groups will be removed and replaced with the peerings defined by this configuration. Optional when connectivityTopology is of type \"HubAndSpoke\"." + } + }, + "isGlobal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag if global mesh is supported. By default, mesh connectivity is applied to virtual networks within the same region. If set to \"True\", a global mesh enables connectivity across regions." + } + } + }, + "resources": { + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "connectivityConfiguration": { + "type": "Microsoft.Network/networkManagers/connectivityConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('name'))]", + "properties": { + "appliesToGroups": "[map(parameters('appliesToGroups'), lambda('group', createObject('groupConnectivity', lambdaVariables('group').groupConnectivity, 'isGlobal', coalesce(string(lambdaVariables('group').isGlobal), 'false'), 'networkGroupId', lambdaVariables('group').networkGroupResourceId, 'useHubGateway', coalesce(string(lambdaVariables('group').useHubGateway), 'false'))))]", + "connectivityTopology": "[parameters('connectivityTopology')]", + "deleteExistingPeering": "[if(equals(parameters('connectivityTopology'), 'HubAndSpoke'), string(parameters('deleteExistingPeering')), 'false')]", + "description": "[parameters('description')]", + "hubs": "[if(equals(parameters('connectivityTopology'), 'HubAndSpoke'), parameters('hubs'), createArray())]", + "isGlobal": "[string(parameters('isGlobal'))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed connectivity configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed connectivity configuration." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/connectivityConfigurations', parameters('networkManagerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the connectivity configuration was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-manager/main.bicep b/avm/1.1.0/res/network/network-manager/main.bicep new file mode 100644 index 000000000..a90c09188 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/main.bicep @@ -0,0 +1,323 @@ +metadata name = 'Network Managers' +metadata description = 'This module deploys a Network Manager.' + +@sys.description('Required. Name of the Network Manager.') +@minLength(1) +@maxLength(64) +param name string + +@sys.description('Optional. Location for all resources.') +param location string = resourceGroup().location + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.4.1' +@sys.description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.4.1' +@sys.description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@sys.description('Optional. Tags of the resource.') +param tags object? + +@maxLength(500) +@sys.description('Optional. A description of the Network Manager.') +param description string = '' + +@sys.description('Optional. Scope Access (Also known as features). String array containing any of "Connectivity", "SecurityAdmin", or "Routing". The connectivity feature allows you to create network topologies at scale. The security admin feature lets you create high-priority security rules, which take precedence over NSGs. The routing feature allows you to describe your desired routing behavior and orchestrate user-defined routes (UDRs) to create and maintain the desired routing behavior. If none of the features are required, then this parameter does not need to be specified, which then only enables features like "IPAM" and "Virtual Network Verifier".') +param networkManagerScopeAccesses networkManagerScopeAccessType + +@sys.description('Required. Scope of Network Manager. Contains a list of management groups or a list of subscriptions. This defines the boundary of network resources that this Network Manager instance can manage. If using Management Groups, ensure that the "Microsoft.Network" resource provider is registered for those Management Groups prior to deployment. Must contain at least one management group or subscription.') +param networkManagerScopes networkManagerScopesType + +@sys.description('Conditional. Network Groups and static members to create for the network manager. Required if using "connectivityConfigurations" or "securityAdminConfigurations" parameters. A network group is global container that includes a set of virtual network resources from any region. Then, configurations are applied to target the network group, which applies the configuration to all members of the group. The two types are group memberships are static and dynamic memberships. Static membership allows you to explicitly add virtual networks to a group by manually selecting individual virtual networks, and is available as a child module, while dynamic membership is defined through Azure policy. See [How Azure Policy works with Network Groups](https://learn.microsoft.com/en-us/azure/virtual-network-manager/concept-azure-policy-integration) for more details.') +param networkGroups networkGroupType + +@sys.description('Optional. Connectivity Configurations to create for the network manager. Network manager must contain at least one network group in order to define connectivity configurations.') +param connectivityConfigurations connectivityConfigurationsType + +@sys.description('Optional. Scope Connections to create for the network manager. Allows network manager to manage resources from another tenant. Supports management groups or subscriptions from another tenant.') +param scopeConnections scopeConnectionType + +@sys.description('Optional. Security Admin Configurations requires enabling the "SecurityAdmin" feature on Network Manager. A security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules. You then associate the rule collection with the network groups that you want to apply the security admin rules to.') +param securityAdminConfigurations securityAdminConfigurationsType + +@sys.description('Optional. Routing Configurations requires enabling the "Routing" feature on Network Manager. A routing configuration contains a set of rule collections. Each rule collection contains one or more routing rules.') +param routingConfigurations routingConfigurationsType + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'IPAM Pool User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7b3e853f-ad5d-4fb5-a7b8-56a3581c7037' + ) + 'LocalNGFirewallAdministrator role': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a8835c7d-b5cb-47fa-b6f0-65ea10ce07a2' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + 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': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-networkmanager.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource networkManager 'Microsoft.Network/networkManagers@2024-05-01' = { + name: name + location: location + tags: tags + properties: { + description: description + networkManagerScopeAccesses: networkManagerScopeAccesses + networkManagerScopes: networkManagerScopes + } +} + +module networkManager_networkGroups 'network-group/main.bicep' = [ + for (networkGroup, index) in networkGroups ?? []: { + name: '${uniqueString(deployment().name, location)}-NetworkManager-NetworkGroups-${index}' + params: { + name: networkGroup.name + networkManagerName: networkManager.name + description: networkGroup.?description + staticMembers: networkGroup.?staticMembers + memberType: networkGroup.?memberType ?? 'VirtualNetwork' + } + } +] + +module networkManager_connectivityConfigurations 'connectivity-configuration/main.bicep' = [ + for (connectivityConfiguration, index) in connectivityConfigurations ?? []: { + name: '${uniqueString(deployment().name, location)}-NetworkManager-ConnectivityConfigurations-${index}' + params: { + name: connectivityConfiguration.name + networkManagerName: networkManager.name + description: connectivityConfiguration.?description + appliesToGroups: connectivityConfiguration.?appliesToGroups ?? [] + connectivityTopology: connectivityConfiguration.connectivityTopology + hubs: connectivityConfiguration.?hubs ?? [] + deleteExistingPeering: connectivityConfiguration.?deleteExistingPeering ?? false + isGlobal: connectivityConfiguration.?isGlobal ?? false + } + dependsOn: networkManager_networkGroups + } +] + +module networkManager_scopeConnections 'scope-connection/main.bicep' = [ + for (scopeConnection, index) in scopeConnections ?? []: { + name: '${uniqueString(deployment().name, location)}-NetworkManager-ScopeConnections-${index}' + params: { + name: scopeConnection.name + networkManagerName: networkManager.name + description: scopeConnection.?description + resourceId: scopeConnection.resourceId + tenantId: scopeConnection.tenantId + } + } +] + +module networkManager_securityAdminConfigurations 'security-admin-configuration/main.bicep' = [ + for (securityAdminConfiguration, index) in securityAdminConfigurations ?? []: { + name: '${uniqueString(deployment().name, location)}-NetworkManager-SecurityAdminConfigurations-${index}' + params: { + name: securityAdminConfiguration.name + networkManagerName: networkManager.name + description: securityAdminConfiguration.?description + applyOnNetworkIntentPolicyBasedServices: securityAdminConfiguration.applyOnNetworkIntentPolicyBasedServices + ruleCollections: securityAdminConfiguration.?ruleCollections ?? [] + } + dependsOn: networkManager_networkGroups + } +] + +module networkManager_routingConfigurations 'routing-configuration/main.bicep' = [ + for (routingConfiguration, index) in routingConfigurations ?? []: { + name: '${uniqueString(deployment().name, location)}-NetworkManager-RoutingConfigurations-${index}' + params: { + name: routingConfiguration.name + networkManagerName: networkManager.name + description: routingConfiguration.?description + ruleCollections: routingConfiguration.?ruleCollections ?? [] + } + dependsOn: networkManager_networkGroups + } +] + +resource networkManager_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: networkManager +} + +resource networkManager_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(networkManager.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: networkManager + } +] + +@sys.description('The resource group the network manager was deployed into.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The resource ID of the network manager.') +output resourceId string = networkManager.id + +@sys.description('The name of the network manager.') +output name string = networkManager.name + +@sys.description('The location the resource was deployed into.') +output location string = networkManager.location + +// =============== // +// Definitions // +// =============== // + +import { staticMembersType } from 'network-group/main.bicep' +type networkGroupType = { + @sys.description('Required. The name of the network group.') + name: string + + @sys.description('Optional. A description of the network group.') + description: string? + + @sys.description('Optional. The type of the group member. Subnet member type is used for routing configurations.') + memberType: ('Subnet' | 'VirtualNetwork')? + + @sys.description('Optional. Static Members to create for the network group. Contains virtual networks to add to the network group.') + staticMembers: staticMembersType? +}[]? + +type networkManagerScopeAccessType = ('Connectivity' | 'SecurityAdmin' | 'Routing')[]? + +type networkManagerScopesType = { + @sys.description('Conditional. List of fully qualified IDs of management groups to assign to the network manager to manage. Required if `subscriptions` is not provided. Fully qualified ID format: \'/providers/Microsoft.Management/managementGroups/{managementGroupId}\'.') + managementGroups: string[]? + + @sys.description('Conditional. List of fully qualified IDs of Subscriptions to assign to the network manager to manage. Required if `managementGroups` is not provided. Fully qualified ID format: \'/subscriptions/{subscriptionId}\'.') + subscriptions: string[]? +} + +type scopeConnectionType = { + @sys.description('Required. The name of the scope connection.') + name: string + + @sys.description('Optional. A description of the scope connection.') + description: string? + + @sys.description('Required. Enter the subscription or management group resource ID that you want to add to this network manager\'s scope.') + resourceId: string + + @sys.description('Required. Tenant ID of the subscription or management group that you want to manage.') + tenantId: string +}[]? + +import { appliesToGroupsType, hubsType } from 'connectivity-configuration/main.bicep' +type connectivityConfigurationsType = { + @sys.description('Required. The name of the connectivity configuration.') + name: string + + @sys.description('Optional. A description of the connectivity configuration.') + description: string? + + @sys.description('Required. Network Groups for the configuration. A connectivity configuration must be associated to at least one network group.') + appliesToGroups: appliesToGroupsType + + @sys.description('Required. The connectivity topology to apply the configuration to.') + connectivityTopology: ('HubAndSpoke' | 'Mesh') + + @sys.description('Optional. The hubs to apply the configuration to.') + hubs: hubsType? + + @sys.description('Optional. Delete existing peering connections.') + deleteExistingPeering: bool? + + @sys.description('Optional. Is global configuration.') + isGlobal: bool? +}[]? + +import { applyOnNetworkIntentPolicyBasedServicesType, securityAdminConfigurationRuleCollectionType } from 'security-admin-configuration/main.bicep' +type securityAdminConfigurationsType = { + @sys.description('Required. The name of the security admin configuration.') + name: string + + @sys.description('Optional. A description of the security admin configuration.') + description: string? + + @sys.description('Required. Apply on network intent policy based services.') + applyOnNetworkIntentPolicyBasedServices: applyOnNetworkIntentPolicyBasedServicesType + + @sys.description('Optional. Rule collections to create for the security admin configuration.') + ruleCollections: securityAdminConfigurationRuleCollectionType? +}[]? + +import { routingConfigurationRuleCollectionType } from 'routing-configuration/main.bicep' +type routingConfigurationsType = { + @sys.description('Required. The name of the routing configuration.') + name: string + + @sys.description('Optional. A description of the routing configuration.') + description: string? + + @sys.description('Optional. Rule collections to create for the routing configuration.') + ruleCollections: routingConfigurationRuleCollectionType? +}[]? diff --git a/avm/1.1.0/res/network/network-manager/main.json b/avm/1.1.0/res/network/network-manager/main.json new file mode 100644 index 000000000..1b2050e01 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/main.json @@ -0,0 +1,3487 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "4546579136195392915" + }, + "name": "Network Managers", + "description": "This module deploys a Network Manager." + }, + "definitions": { + "networkGroupType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the network group." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the network group." + } + }, + "memberType": { + "type": "string", + "allowedValues": [ + "Subnet", + "VirtualNetwork" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the group member. Subnet member type is used for routing configurations." + } + }, + "staticMembers": { + "$ref": "#/definitions/staticMembersType", + "nullable": true, + "metadata": { + "description": "Optional. Static Members to create for the network group. Contains virtual networks to add to the network group." + } + } + } + }, + "nullable": true + }, + "networkManagerScopeAccessType": { + "type": "array", + "allowedValues": [ + "Connectivity", + "Routing", + "SecurityAdmin" + ], + "nullable": true + }, + "networkManagerScopesType": { + "type": "object", + "properties": { + "managementGroups": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of fully qualified IDs of management groups to assign to the network manager to manage. Required if `subscriptions` is not provided. Fully qualified ID format: '/providers/Microsoft.Management/managementGroups/{managementGroupId}'." + } + }, + "subscriptions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of fully qualified IDs of Subscriptions to assign to the network manager to manage. Required if `managementGroups` is not provided. Fully qualified ID format: '/subscriptions/{subscriptionId}'." + } + } + } + }, + "scopeConnectionType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the scope connection." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the scope connection." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Enter the subscription or management group resource ID that you want to add to this network manager's scope." + } + }, + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. Tenant ID of the subscription or management group that you want to manage." + } + } + } + }, + "nullable": true + }, + "connectivityConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the connectivity configuration." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the connectivity configuration." + } + }, + "appliesToGroups": { + "$ref": "#/definitions/appliesToGroupsType", + "metadata": { + "description": "Required. Network Groups for the configuration. A connectivity configuration must be associated to at least one network group." + } + }, + "connectivityTopology": { + "type": "string", + "allowedValues": [ + "HubAndSpoke", + "Mesh" + ], + "metadata": { + "description": "Required. The connectivity topology to apply the configuration to." + } + }, + "hubs": { + "$ref": "#/definitions/hubsType", + "nullable": true, + "metadata": { + "description": "Optional. The hubs to apply the configuration to." + } + }, + "deleteExistingPeering": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Delete existing peering connections." + } + }, + "isGlobal": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Is global configuration." + } + } + } + }, + "nullable": true + }, + "securityAdminConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security admin configuration." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the security admin configuration." + } + }, + "applyOnNetworkIntentPolicyBasedServices": { + "$ref": "#/definitions/applyOnNetworkIntentPolicyBasedServicesType", + "metadata": { + "description": "Required. Apply on network intent policy based services." + } + }, + "ruleCollections": { + "$ref": "#/definitions/securityAdminConfigurationRuleCollectionType", + "nullable": true, + "metadata": { + "description": "Optional. Rule collections to create for the security admin configuration." + } + } + } + }, + "nullable": true + }, + "routingConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the routing configuration." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the routing configuration." + } + }, + "ruleCollections": { + "$ref": "#/definitions/routingConfigurationRuleCollectionType", + "nullable": true, + "metadata": { + "description": "Optional. Rule collections to create for the routing configuration." + } + } + } + }, + "nullable": true + }, + "_1.appliesToType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the network group." + } + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "routing-configuration/rule-collection/main.bicep" + } + } + }, + "_1.rulesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destination": { + "$ref": "#/definitions/_2.destinationType", + "metadata": { + "description": "Required. The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "nextHop": { + "$ref": "#/definitions/_2.nextHopType", + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "routing-configuration/rule-collection/main.bicep" + } + } + }, + "_2.destinationType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "AddressPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "destinationAddress": { + "type": "string", + "metadata": { + "description": "Required. The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be \"AzureCloud\", \"Storage.AustraliaEast\", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "routing-configuration/rule-collection/rule/main.bicep" + } + } + }, + "_2.nextHopType": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "NoNextHop", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + }, + "nextHopAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The IP address of the next hop. Required if the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "routing-configuration/rule-collection/rule/main.bicep" + } + } + }, + "_3.appliesToGroupsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the network group." + } + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "security-admin-configuration/rule-collection/main.bicep" + } + } + }, + "_3.rulesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule." + } + }, + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "AlwaysAllow", + "Deny" + ], + "metadata": { + "description": "Required. Indicates the access allowed for this particular rule. \"Allow\" means traffic matching this rule will be allowed. \"Deny\" means traffic matching this rule will be blocked. \"AlwaysAllow\" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destinationPortRanges": { + "$ref": "#/definitions/_4.destinationPortRangesType", + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "destinations": { + "$ref": "#/definitions/_4.destinationsType", + "nullable": true, + "metadata": { + "description": "Optional. The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. Indicates if the traffic matched against the rule in inbound or outbound." + } + }, + "priority": { + "type": "int", + "minValue": 1, + "maxValue": 4096, + "metadata": { + "description": "Required. The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Ah", + "Any", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourcePortRanges": { + "$ref": "#/definitions/_4.sourcePortRangesType", + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "sources": { + "$ref": "#/definitions/_4.sourcesType", + "nullable": true, + "metadata": { + "description": "Optional. The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "security-admin-configuration/rule-collection/main.bicep" + } + } + }, + "_4.destinationPortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "security-admin-configuration/rule-collection/rule/main.bicep" + } + } + }, + "_4.destinationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "security-admin-configuration/rule-collection/rule/main.bicep" + } + } + }, + "_4.sourcePortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "security-admin-configuration/rule-collection/rule/main.bicep" + } + } + }, + "_4.sourcesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "security-admin-configuration/rule-collection/rule/main.bicep" + } + } + }, + "appliesToGroupsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "groupConnectivity": { + "type": "string", + "allowedValues": [ + "DirectlyConnected", + "None" + ], + "metadata": { + "description": "Required. Group connectivity type." + } + }, + "isGlobal": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag if global is supported." + } + }, + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource Id of the network group." + } + }, + "useHubGateway": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag if use hub gateway." + } + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connectivity-configuration/main.bicep" + } + } + }, + "applyOnNetworkIntentPolicyBasedServicesType": { + "type": "array", + "allowedValues": [ + "All", + "AllowRulesOnly", + "None" + ], + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "security-admin-configuration/main.bicep" + } + } + }, + "hubsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource Id of the hub." + } + }, + "resourceType": { + "type": "string", + "allowedValues": [ + "Microsoft.Network/virtualNetworks" + ], + "metadata": { + "description": "Required. Resource type of the hub." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connectivity-configuration/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.1" + } + } + }, + "routingConfigurationRuleCollectionType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule collection." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule collection." + } + }, + "appliesTo": { + "$ref": "#/definitions/_1.appliesToType", + "metadata": { + "description": "Required. List of network groups for configuration. A routing rule collection must be associated to at least one network group." + } + }, + "disableBgpRoutePropagation": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Disables BGP route propagation for the rule collection. Defaults to true." + } + }, + "rules": { + "$ref": "#/definitions/_1.rulesType", + "nullable": true, + "metadata": { + "description": "Optional. List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "routing-configuration/main.bicep" + } + } + }, + "securityAdminConfigurationRuleCollectionType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the admin rule collection." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the admin rule collection." + } + }, + "appliesToGroups": { + "$ref": "#/definitions/_3.appliesToGroupsType", + "metadata": { + "description": "Required. List of network groups for configuration. An admin rule collection must be associated to at least one network group." + } + }, + "rules": { + "$ref": "#/definitions/_3.rulesType", + "nullable": true, + "metadata": { + "description": "Optional. List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "security-admin-configuration/main.bicep" + } + } + }, + "staticMembersType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the static member." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the virtual network." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "network-group/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "metadata": { + "description": "Required. Name of the Network Manager." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the Network Manager." + } + }, + "networkManagerScopeAccesses": { + "$ref": "#/definitions/networkManagerScopeAccessType", + "metadata": { + "description": "Optional. Scope Access (Also known as features). String array containing any of \"Connectivity\", \"SecurityAdmin\", or \"Routing\". The connectivity feature allows you to create network topologies at scale. The security admin feature lets you create high-priority security rules, which take precedence over NSGs. The routing feature allows you to describe your desired routing behavior and orchestrate user-defined routes (UDRs) to create and maintain the desired routing behavior. If none of the features are required, then this parameter does not need to be specified, which then only enables features like \"IPAM\" and \"Virtual Network Verifier\"." + } + }, + "networkManagerScopes": { + "$ref": "#/definitions/networkManagerScopesType", + "metadata": { + "description": "Required. Scope of Network Manager. Contains a list of management groups or a list of subscriptions. This defines the boundary of network resources that this Network Manager instance can manage. If using Management Groups, ensure that the \"Microsoft.Network\" resource provider is registered for those Management Groups prior to deployment. Must contain at least one management group or subscription." + } + }, + "networkGroups": { + "$ref": "#/definitions/networkGroupType", + "metadata": { + "description": "Conditional. Network Groups and static members to create for the network manager. Required if using \"connectivityConfigurations\" or \"securityAdminConfigurations\" parameters. A network group is global container that includes a set of virtual network resources from any region. Then, configurations are applied to target the network group, which applies the configuration to all members of the group. The two types are group memberships are static and dynamic memberships. Static membership allows you to explicitly add virtual networks to a group by manually selecting individual virtual networks, and is available as a child module, while dynamic membership is defined through Azure policy. See [How Azure Policy works with Network Groups](https://learn.microsoft.com/en-us/azure/virtual-network-manager/concept-azure-policy-integration) for more details." + } + }, + "connectivityConfigurations": { + "$ref": "#/definitions/connectivityConfigurationsType", + "metadata": { + "description": "Optional. Connectivity Configurations to create for the network manager. Network manager must contain at least one network group in order to define connectivity configurations." + } + }, + "scopeConnections": { + "$ref": "#/definitions/scopeConnectionType", + "metadata": { + "description": "Optional. Scope Connections to create for the network manager. Allows network manager to manage resources from another tenant. Supports management groups or subscriptions from another tenant." + } + }, + "securityAdminConfigurations": { + "$ref": "#/definitions/securityAdminConfigurationsType", + "metadata": { + "description": "Optional. Security Admin Configurations requires enabling the \"SecurityAdmin\" feature on Network Manager. A security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules. You then associate the rule collection with the network groups that you want to apply the security admin rules to." + } + }, + "routingConfigurations": { + "$ref": "#/definitions/routingConfigurationsType", + "metadata": { + "description": "Optional. Routing Configurations requires enabling the \"Routing\" feature on Network Manager. A routing configuration contains a set of rule collections. Each rule collection contains one or more routing rules." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "IPAM Pool User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7b3e853f-ad5d-4fb5-a7b8-56a3581c7037')]", + "LocalNGFirewallAdministrator role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a8835c7d-b5cb-47fa-b6f0-65ea10ce07a2')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "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": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networkmanager.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkManager": { + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "description": "[parameters('description')]", + "networkManagerScopeAccesses": "[parameters('networkManagerScopeAccesses')]", + "networkManagerScopes": "[parameters('networkManagerScopes')]" + } + }, + "networkManager_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkManagers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "networkManager" + ] + }, + "networkManager_roleAssignments": { + "copy": { + "name": "networkManager_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkManagers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkManagers', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkManager" + ] + }, + "networkManager_networkGroups": { + "copy": { + "name": "networkManager_networkGroups", + "count": "[length(coalesce(parameters('networkGroups'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkManager-NetworkGroups-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('networkGroups'), createArray())[copyIndex()].name]" + }, + "networkManagerName": { + "value": "[parameters('name')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('networkGroups'), createArray())[copyIndex()], 'description')]" + }, + "staticMembers": { + "value": "[tryGet(coalesce(parameters('networkGroups'), createArray())[copyIndex()], 'staticMembers')]" + }, + "memberType": { + "value": "[coalesce(tryGet(coalesce(parameters('networkGroups'), createArray())[copyIndex()], 'memberType'), 'VirtualNetwork')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "5379165154107386117" + }, + "name": "Network Manager Network Groups", + "description": "This module deploys a Network Manager Network Group.\nA network group is a collection of same-type network resources that you can associate with network manager configurations. You can add same-type network resources after you create the network group." + }, + "definitions": { + "staticMembersType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the static member." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the virtual network." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the network group." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the network group." + } + }, + "memberType": { + "type": "string", + "defaultValue": "VirtualNetwork", + "allowedValues": [ + "Subnet", + "VirtualNetwork" + ], + "metadata": { + "description": "Optional. The type of the group member. Subnet member type is used for routing configurations." + } + }, + "staticMembers": { + "$ref": "#/definitions/staticMembersType", + "metadata": { + "description": "Optional. Static Members to create for the network group. Contains virtual networks to add to the network group." + } + } + }, + "resources": { + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "networkGroup": { + "type": "Microsoft.Network/networkManagers/networkGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "memberType": "[parameters('memberType')]" + } + }, + "networkGroup_staticMembers": { + "copy": { + "name": "networkGroup_staticMembers", + "count": "[length(coalesce(parameters('staticMembers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkGroup-StaticMembers-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkManagerName": { + "value": "[parameters('networkManagerName')]" + }, + "networkGroupName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('staticMembers'), createArray())[copyIndex()].name]" + }, + "resourceId": { + "value": "[coalesce(parameters('staticMembers'), createArray())[copyIndex()].resourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12446365305773972010" + }, + "name": "Network Manager Network Group Static Members", + "description": "This module deploys a Network Manager Network Group Static Member.\nStatic membership allows you to explicitly add virtual networks to a group by manually selecting individual virtual networks." + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "networkGroupName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network group. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the static member." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the virtual network." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkManagers/networkGroups/staticMembers", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('networkGroupName'), parameters('name'))]", + "properties": { + "resourceId": "[parameters('resourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed static member." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed static member." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/networkGroups/staticMembers', parameters('networkManagerName'), parameters('networkGroupName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the static member was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "networkGroup" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed network group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed network group." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/networkGroups', parameters('networkManagerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "networkManager" + ] + }, + "networkManager_connectivityConfigurations": { + "copy": { + "name": "networkManager_connectivityConfigurations", + "count": "[length(coalesce(parameters('connectivityConfigurations'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkManager-ConnectivityConfigurations-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('connectivityConfigurations'), createArray())[copyIndex()].name]" + }, + "networkManagerName": { + "value": "[parameters('name')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('connectivityConfigurations'), createArray())[copyIndex()], 'description')]" + }, + "appliesToGroups": { + "value": "[coalesce(tryGet(coalesce(parameters('connectivityConfigurations'), createArray())[copyIndex()], 'appliesToGroups'), createArray())]" + }, + "connectivityTopology": { + "value": "[coalesce(parameters('connectivityConfigurations'), createArray())[copyIndex()].connectivityTopology]" + }, + "hubs": { + "value": "[coalesce(tryGet(coalesce(parameters('connectivityConfigurations'), createArray())[copyIndex()], 'hubs'), createArray())]" + }, + "deleteExistingPeering": { + "value": "[coalesce(tryGet(coalesce(parameters('connectivityConfigurations'), createArray())[copyIndex()], 'deleteExistingPeering'), false())]" + }, + "isGlobal": { + "value": "[coalesce(tryGet(coalesce(parameters('connectivityConfigurations'), createArray())[copyIndex()], 'isGlobal'), false())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "14947854714653371230" + }, + "name": "Network Manager Connectivity Configurations", + "description": "This module deploys a Network Manager Connectivity Configuration.\nConnectivity configurations define hub-and-spoke or mesh topologies applied to one or more network groups." + }, + "definitions": { + "appliesToGroupsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "groupConnectivity": { + "type": "string", + "allowedValues": [ + "DirectlyConnected", + "None" + ], + "metadata": { + "description": "Required. Group connectivity type." + } + }, + "isGlobal": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag if global is supported." + } + }, + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource Id of the network group." + } + }, + "useHubGateway": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag if use hub gateway." + } + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "hubsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource Id of the hub." + } + }, + "resourceType": { + "type": "string", + "allowedValues": [ + "Microsoft.Network/virtualNetworks" + ], + "metadata": { + "description": "Required. Resource type of the hub." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the connectivity configuration." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the connectivity configuration." + } + }, + "appliesToGroups": { + "$ref": "#/definitions/appliesToGroupsType", + "metadata": { + "description": "Required. Network Groups for the configuration. A connectivity configuration must be associated to at least one network group." + } + }, + "connectivityTopology": { + "type": "string", + "allowedValues": [ + "HubAndSpoke", + "Mesh" + ], + "metadata": { + "description": "Required. Connectivity topology type." + } + }, + "hubs": { + "$ref": "#/definitions/hubsType", + "metadata": { + "description": "Conditional. List of hub items. This will create peerings between the specified hub and the virtual networks in the network group specified. Required if connectivityTopology is of type \"HubAndSpoke\"." + } + }, + "deleteExistingPeering": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag if need to remove current existing peerings. If set to \"True\", all peerings on virtual networks in selected network groups will be removed and replaced with the peerings defined by this configuration. Optional when connectivityTopology is of type \"HubAndSpoke\"." + } + }, + "isGlobal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Flag if global mesh is supported. By default, mesh connectivity is applied to virtual networks within the same region. If set to \"True\", a global mesh enables connectivity across regions." + } + } + }, + "resources": { + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "connectivityConfiguration": { + "type": "Microsoft.Network/networkManagers/connectivityConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('name'))]", + "properties": { + "appliesToGroups": "[map(parameters('appliesToGroups'), lambda('group', createObject('groupConnectivity', lambdaVariables('group').groupConnectivity, 'isGlobal', coalesce(string(lambdaVariables('group').isGlobal), 'false'), 'networkGroupId', lambdaVariables('group').networkGroupResourceId, 'useHubGateway', coalesce(string(lambdaVariables('group').useHubGateway), 'false'))))]", + "connectivityTopology": "[parameters('connectivityTopology')]", + "deleteExistingPeering": "[if(equals(parameters('connectivityTopology'), 'HubAndSpoke'), string(parameters('deleteExistingPeering')), 'false')]", + "description": "[parameters('description')]", + "hubs": "[if(equals(parameters('connectivityTopology'), 'HubAndSpoke'), parameters('hubs'), createArray())]", + "isGlobal": "[string(parameters('isGlobal'))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed connectivity configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed connectivity configuration." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/connectivityConfigurations', parameters('networkManagerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the connectivity configuration was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "networkManager", + "networkManager_networkGroups" + ] + }, + "networkManager_scopeConnections": { + "copy": { + "name": "networkManager_scopeConnections", + "count": "[length(coalesce(parameters('scopeConnections'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkManager-ScopeConnections-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('scopeConnections'), createArray())[copyIndex()].name]" + }, + "networkManagerName": { + "value": "[parameters('name')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('scopeConnections'), createArray())[copyIndex()], 'description')]" + }, + "resourceId": { + "value": "[coalesce(parameters('scopeConnections'), createArray())[copyIndex()].resourceId]" + }, + "tenantId": { + "value": "[coalesce(parameters('scopeConnections'), createArray())[copyIndex()].tenantId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "2901273702758810148" + }, + "name": "Network Manager Scope Connections", + "description": "This module deploys a Network Manager Scope Connection.\nCreate a cross-tenant connection to manage a resource from another tenant." + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the scope connection." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the scope connection." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Enter the subscription or management group resource ID that you want to add to this network manager's scope." + } + }, + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. Tenant ID of the subscription or management group that you want to manage." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkManagers/scopeConnections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "resourceId": "[parameters('resourceId')]", + "tenantId": "[parameters('tenantId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed scope connection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed scope connection." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/scopeConnections', parameters('networkManagerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the scope connection was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "networkManager" + ] + }, + "networkManager_securityAdminConfigurations": { + "copy": { + "name": "networkManager_securityAdminConfigurations", + "count": "[length(coalesce(parameters('securityAdminConfigurations'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkManager-SecurityAdminConfigurations-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('securityAdminConfigurations'), createArray())[copyIndex()].name]" + }, + "networkManagerName": { + "value": "[parameters('name')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('securityAdminConfigurations'), createArray())[copyIndex()], 'description')]" + }, + "applyOnNetworkIntentPolicyBasedServices": { + "value": "[coalesce(parameters('securityAdminConfigurations'), createArray())[copyIndex()].applyOnNetworkIntentPolicyBasedServices]" + }, + "ruleCollections": { + "value": "[coalesce(tryGet(coalesce(parameters('securityAdminConfigurations'), createArray())[copyIndex()], 'ruleCollections'), createArray())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15398119849930180416" + }, + "name": "Network Manager Security Admin Configurations", + "description": "This module deploys an Network Manager Security Admin Configuration.\nA security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules." + }, + "definitions": { + "applyOnNetworkIntentPolicyBasedServicesType": { + "type": "array", + "allowedValues": [ + "All", + "AllowRulesOnly", + "None" + ], + "metadata": { + "__bicep_export!": true + } + }, + "securityAdminConfigurationRuleCollectionType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the admin rule collection." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the admin rule collection." + } + }, + "appliesToGroups": { + "$ref": "#/definitions/appliesToGroupsType", + "metadata": { + "description": "Required. List of network groups for configuration. An admin rule collection must be associated to at least one network group." + } + }, + "rules": { + "$ref": "#/definitions/rulesType", + "nullable": true, + "metadata": { + "description": "Optional. List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "_1.destinationPortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/rule/main.bicep" + } + } + }, + "_1.destinationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/rule/main.bicep" + } + } + }, + "_1.sourcePortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/rule/main.bicep" + } + } + }, + "_1.sourcesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/rule/main.bicep" + } + } + }, + "appliesToGroupsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the network group." + } + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/main.bicep" + } + } + }, + "rulesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule." + } + }, + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "AlwaysAllow", + "Deny" + ], + "metadata": { + "description": "Required. Indicates the access allowed for this particular rule. \"Allow\" means traffic matching this rule will be allowed. \"Deny\" means traffic matching this rule will be blocked. \"AlwaysAllow\" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destinationPortRanges": { + "$ref": "#/definitions/_1.destinationPortRangesType", + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "destinations": { + "$ref": "#/definitions/_1.destinationsType", + "nullable": true, + "metadata": { + "description": "Optional. The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. Indicates if the traffic matched against the rule in inbound or outbound." + } + }, + "priority": { + "type": "int", + "minValue": 1, + "maxValue": 4096, + "metadata": { + "description": "Required. The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Ah", + "Any", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourcePortRanges": { + "$ref": "#/definitions/_1.sourcePortRangesType", + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "sources": { + "$ref": "#/definitions/_1.sourcesType", + "nullable": true, + "metadata": { + "description": "Optional. The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/main.bicep" + } + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the security admin configuration." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the security admin configuration." + } + }, + "applyOnNetworkIntentPolicyBasedServices": { + "$ref": "#/definitions/applyOnNetworkIntentPolicyBasedServicesType", + "metadata": { + "description": "Required. Enum list of network intent policy based services." + } + }, + "networkGroupAddressSpaceAggregationOption": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "None", + "Manual" + ], + "metadata": { + "description": "Optional. Determine update behavior for changes to network groups referenced within the rules in this configuration." + } + }, + "ruleCollections": { + "$ref": "#/definitions/securityAdminConfigurationRuleCollectionType", + "metadata": { + "description": "Optional. A security admin configuration contains a set of rule collections that are applied to network groups. Each rule collection contains one or more security admin rules." + } + } + }, + "resources": { + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "securityAdminConfigurations": { + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "applyOnNetworkIntentPolicyBasedServices": "[parameters('applyOnNetworkIntentPolicyBasedServices')]", + "networkGroupAddressSpaceAggregationOption": "[parameters('networkGroupAddressSpaceAggregationOption')]" + } + }, + "securityAdminConfigurations_ruleCollections": { + "copy": { + "name": "securityAdminConfigurations_ruleCollections", + "count": "[length(coalesce(parameters('ruleCollections'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-SecurityAdminConfigurations-RuleCollections-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkManagerName": { + "value": "[parameters('networkManagerName')]" + }, + "securityAdminConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('ruleCollections'), createArray())[copyIndex()].name]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('ruleCollections'), createArray())[copyIndex()], 'description')]" + }, + "appliesToGroups": { + "value": "[coalesce(parameters('ruleCollections'), createArray())[copyIndex()].appliesToGroups]" + }, + "rules": { + "value": "[coalesce(tryGet(coalesce(parameters('ruleCollections'), createArray())[copyIndex()], 'rules'), createArray())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "17868772067986931575" + }, + "name": "Network Manager Security Admin Configuration Rule Collections", + "description": "This module deploys an Network Manager Security Admin Configuration Rule Collection.\nA security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail." + }, + "definitions": { + "appliesToGroupsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the network group." + } + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "rulesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule." + } + }, + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "AlwaysAllow", + "Deny" + ], + "metadata": { + "description": "Required. Indicates the access allowed for this particular rule. \"Allow\" means traffic matching this rule will be allowed. \"Deny\" means traffic matching this rule will be blocked. \"AlwaysAllow\" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destinationPortRanges": { + "$ref": "#/definitions/destinationPortRangesType", + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "destinations": { + "$ref": "#/definitions/destinationsType", + "nullable": true, + "metadata": { + "description": "Optional. The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. Indicates if the traffic matched against the rule in inbound or outbound." + } + }, + "priority": { + "type": "int", + "minValue": 1, + "maxValue": 4096, + "metadata": { + "description": "Required. The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Ah", + "Any", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourcePortRanges": { + "$ref": "#/definitions/sourcePortRangesType", + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "sources": { + "$ref": "#/definitions/sourcesType", + "nullable": true, + "metadata": { + "description": "Optional. The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "destinationPortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + }, + "destinationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + }, + "sourcePortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + }, + "sourcesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "securityAdminConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent security admin configuration. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the admin rule collection." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the admin rule collection." + } + }, + "appliesToGroups": { + "$ref": "#/definitions/appliesToGroupsType", + "metadata": { + "description": "Required. List of network groups for configuration. An admin rule collection must be associated to at least one network group." + } + }, + "rules": { + "$ref": "#/definitions/rulesType", + "metadata": { + "description": "Optional. List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail." + } + } + }, + "resources": { + "networkManager::securityAdminConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "ruleCollection": { + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "appliesToGroups": "[map(parameters('appliesToGroups'), lambda('group', createObject('networkGroupId', lambdaVariables('group').networkGroupResourceId)))]" + } + }, + "ruleCollection_rules": { + "copy": { + "name": "ruleCollection_rules", + "count": "[length(coalesce(parameters('rules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-RuleCollections-Rules-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkManagerName": { + "value": "[parameters('networkManagerName')]" + }, + "securityAdminConfigurationName": { + "value": "[parameters('securityAdminConfigurationName')]" + }, + "ruleCollectionName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].name]" + }, + "access": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].access]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'description')]" + }, + "destinationPortRanges": { + "value": "[coalesce(tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'destinationPortRanges'), createArray())]" + }, + "destinations": { + "value": "[coalesce(tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'destinations'), createArray())]" + }, + "direction": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].direction]" + }, + "priority": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].priority]" + }, + "protocol": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].protocol]" + }, + "sourcePortRanges": { + "value": "[coalesce(tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'sourcePortRanges'), createArray())]" + }, + "sources": { + "value": "[coalesce(tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'sources'), createArray())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3195100427454268317" + }, + "name": "Network Manager Security Admin Configuration Rule Collection Rules", + "description": "This module deploys an Azure Virtual Network Manager (AVNM) Security Admin Configuration Rule Collection Rule.\nA security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules." + }, + "definitions": { + "destinationPortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "destinationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "sourcePortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "sourcesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "securityAdminConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent security admin configuration. Required if the template is used in a standalone deployment." + } + }, + "ruleCollectionName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent rule collection. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "AlwaysAllow", + "Deny" + ], + "metadata": { + "description": "Required. Indicates the access allowed for this particular rule. \"Allow\" means traffic matching this rule will be allowed. \"Deny\" means traffic matching this rule will be blocked. \"AlwaysAllow\" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs." + } + }, + "destinationPortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "destinations": { + "$ref": "#/definitions/destinationsType", + "metadata": { + "description": "Optional. The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. Indicates if the traffic matched against the rule in inbound or outbound." + } + }, + "priority": { + "type": "int", + "minValue": 1, + "maxValue": 4096, + "metadata": { + "description": "Required. The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Ah", + "Any", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourcePortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "sources": { + "$ref": "#/definitions/sourcesType", + "metadata": { + "description": "Optional. The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + } + }, + "resources": { + "networkManager::securityAdminConfiguration::ruleCollection": { + "existing": true, + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('ruleCollectionName'))]" + }, + "networkManager::securityAdminConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "rule": { + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]", + "kind": "Custom", + "properties": { + "access": "[parameters('access')]", + "description": "[parameters('description')]", + "destinationPortRanges": "[parameters('destinationPortRanges')]", + "destinations": "[parameters('destinations')]", + "direction": "[parameters('direction')]", + "priority": "[parameters('priority')]", + "protocol": "[parameters('protocol')]", + "sourcePortRanges": "[parameters('sourcePortRanges')]", + "sources": "[parameters('sources')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed rule." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "ruleCollection" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed admin rule collection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed admin rule collection." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the admin rule collection was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "securityAdminConfigurations" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed security admin configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed security admin configuration." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/securityAdminConfigurations', parameters('networkManagerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the security admin configuration was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "networkManager", + "networkManager_networkGroups" + ] + }, + "networkManager_routingConfigurations": { + "copy": { + "name": "networkManager_routingConfigurations", + "count": "[length(coalesce(parameters('routingConfigurations'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkManager-RoutingConfigurations-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('routingConfigurations'), createArray())[copyIndex()].name]" + }, + "networkManagerName": { + "value": "[parameters('name')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('routingConfigurations'), createArray())[copyIndex()], 'description')]" + }, + "ruleCollections": { + "value": "[coalesce(tryGet(coalesce(parameters('routingConfigurations'), createArray())[copyIndex()], 'ruleCollections'), createArray())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "5470663689877325880" + }, + "name": "Network Manager Routing Configurations", + "description": "This module deploys an Network Manager Routing Configuration.\nRouting configurations are the building blocks of UDR management. They're used to describe the desired routing behavior for a network group." + }, + "definitions": { + "routingConfigurationRuleCollectionType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule collection." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule collection." + } + }, + "appliesTo": { + "$ref": "#/definitions/appliesToType", + "metadata": { + "description": "Required. List of network groups for configuration. A routing rule collection must be associated to at least one network group." + } + }, + "disableBgpRoutePropagation": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Disables BGP route propagation for the rule collection. Defaults to true." + } + }, + "rules": { + "$ref": "#/definitions/rulesType", + "nullable": true, + "metadata": { + "description": "Optional. List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "_1.destinationType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "AddressPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "destinationAddress": { + "type": "string", + "metadata": { + "description": "Required. The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be \"AzureCloud\", \"Storage.AustraliaEast\", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/rule/main.bicep" + } + } + }, + "_1.nextHopType": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "NoNextHop", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + }, + "nextHopAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The IP address of the next hop. Required if the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/rule/main.bicep" + } + } + }, + "appliesToType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the network group." + } + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/main.bicep" + } + } + }, + "rulesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destination": { + "$ref": "#/definitions/_1.destinationType", + "metadata": { + "description": "Required. The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "nextHop": { + "$ref": "#/definitions/_1.nextHopType", + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/main.bicep" + } + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the routing configuration." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the routing configuration." + } + }, + "ruleCollections": { + "$ref": "#/definitions/routingConfigurationRuleCollectionType", + "metadata": { + "description": "Optional. A routing configuration contains a set of rule collections that are applied to network groups. Each rule collection contains one or more routing rules." + } + } + }, + "resources": { + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "routingConfigurations": { + "type": "Microsoft.Network/networkManagers/routingConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]" + } + }, + "routingConfigurations_ruleCollections": { + "copy": { + "name": "routingConfigurations_ruleCollections", + "count": "[length(coalesce(parameters('ruleCollections'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-RoutingConfigurations-RuleCollections-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkManagerName": { + "value": "[parameters('networkManagerName')]" + }, + "routingConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('ruleCollections'), createArray())[copyIndex()].name]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('ruleCollections'), createArray())[copyIndex()], 'description')]" + }, + "appliesTo": { + "value": "[coalesce(parameters('ruleCollections'), createArray())[copyIndex()].appliesTo]" + }, + "disableBgpRoutePropagation": { + "value": "[tryGet(coalesce(parameters('ruleCollections'), createArray())[copyIndex()], 'disableBgpRoutePropagation')]" + }, + "rules": { + "value": "[coalesce(tryGet(coalesce(parameters('ruleCollections'), createArray())[copyIndex()], 'rules'), createArray())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9240364702512586570" + }, + "name": "Network Manager Routing Configuration Rule Collections", + "description": "This module deploys an Network Manager Routing Configuration Rule Collection.\nRouting configurations are the building blocks of UDR management. They're used to describe the desired routing behavior for a network group. Each routing configuration contains one ore more rule collections. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager." + }, + "definitions": { + "appliesToType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the network group." + } + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "rulesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "metadata": { + "description": "Required. The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "nextHop": { + "$ref": "#/definitions/nextHopType", + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "destinationType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "AddressPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "destinationAddress": { + "type": "string", + "metadata": { + "description": "Required. The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be \"AzureCloud\", \"Storage.AustraliaEast\", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + }, + "nextHopType": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "NoNextHop", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + }, + "nextHopAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The IP address of the next hop. Required if the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "routingConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Routing Configuration. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the routing rule collection." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the routing rule collection." + } + }, + "appliesTo": { + "$ref": "#/definitions/appliesToType", + "metadata": { + "description": "Required. List of network groups for configuration. A routing rule collection must be associated to at least one network group." + } + }, + "disableBgpRoutePropagation": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether BGP route propagation is enabled for the routing rule collection. Defaults to true." + } + }, + "rules": { + "$ref": "#/definitions/rulesType", + "metadata": { + "description": "Optional. List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager." + } + } + }, + "resources": { + "networkManager::routingConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/routingConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('routingConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "ruleCollection": { + "type": "Microsoft.Network/networkManagers/routingConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "appliesTo": "[map(parameters('appliesTo'), lambda('group', createObject('networkGroupId', lambdaVariables('group').networkGroupResourceId)))]", + "disableBgpRoutePropagation": "[string(parameters('disableBgpRoutePropagation'))]" + } + }, + "ruleCollection_rules": { + "copy": { + "name": "ruleCollection_rules", + "count": "[length(coalesce(parameters('rules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-RuleCollections-Rules-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkManagerName": { + "value": "[parameters('networkManagerName')]" + }, + "routingConfigurationName": { + "value": "[parameters('routingConfigurationName')]" + }, + "ruleCollectionName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].name]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'description')]" + }, + "destination": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].destination]" + }, + "nextHop": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].nextHop]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10535917161454379553" + }, + "name": "Network Manager Routing configuration Rule Collection Rules", + "description": "This module deploys an Azure Virtual Network Manager (AVNM) Routing Configuration Rule Collection Rule.\nA Routing configuration contains a set of rule collections. Each rule collection contains one or more routing rules." + }, + "definitions": { + "destinationType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "AddressPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "destinationAddress": { + "type": "string", + "metadata": { + "description": "Required. The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be \"AzureCloud\", \"Storage.AustraliaEast\", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "nextHopType": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "NoNextHop", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + }, + "nextHopAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The IP address of the next hop. Required if the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "routingConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Routing configuration. Required if the template is used in a standalone deployment." + } + }, + "ruleCollectionName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent rule collection. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "metadata": { + "description": "Required. The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "nextHop": { + "$ref": "#/definitions/nextHopType", + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + } + }, + "resources": { + "networkManager::routingConfiguration::ruleCollection": { + "existing": true, + "type": "Microsoft.Network/networkManagers/routingConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('ruleCollectionName'))]" + }, + "networkManager::routingConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/routingConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('routingConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "rule": { + "type": "Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "destination": "[parameters('destination')]", + "nextHop": "[parameters('nextHop')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed rule." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "ruleCollection" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed routing rule collection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed routing rule collection." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/routingConfigurations/ruleCollections', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the routing rule collection was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "routingConfigurations" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed routing configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed routing configuration." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/routingConfigurations', parameters('networkManagerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the routing configuration was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "networkManager", + "networkManager_networkGroups" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network manager was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the network manager." + }, + "value": "[resourceId('Microsoft.Network/networkManagers', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the network manager." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkManager', '2024-05-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-manager/network-group/README.md b/avm/1.1.0/res/network/network-manager/network-group/README.md new file mode 100644 index 000000000..cd306ce49 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/network-group/README.md @@ -0,0 +1,112 @@ +# Network Manager Network Groups `[Microsoft.Network/networkManagers/networkGroups]` + +This module deploys a Network Manager Network Group. +A network group is a collection of same-type network resources that you can associate with network manager configurations. You can add same-type network resources after you create the network group. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkManagers/networkGroups` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/networkGroups) | +| `Microsoft.Network/networkManagers/networkGroups/staticMembers` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/networkGroups/staticMembers) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the network group. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkManagerName`](#parameter-networkmanagername) | string | The name of the parent network manager. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | A description of the network group. | +| [`memberType`](#parameter-membertype) | string | The type of the group member. Subnet member type is used for routing configurations. | +| [`staticMembers`](#parameter-staticmembers) | array | Static Members to create for the network group. Contains virtual networks to add to the network group. | + +### Parameter: `name` + +The name of the network group. + +- Required: Yes +- Type: string + +### Parameter: `networkManagerName` + +The name of the parent network manager. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `description` + +A description of the network group. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `memberType` + +The type of the group member. Subnet member type is used for routing configurations. + +- Required: No +- Type: string +- Default: `'VirtualNetwork'` +- Allowed: + ```Bicep + [ + 'Subnet' + 'VirtualNetwork' + ] + ``` + +### Parameter: `staticMembers` + +Static Members to create for the network group. Contains virtual networks to add to the network group. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-staticmembersname) | string | The name of the static member. | +| [`resourceId`](#parameter-staticmembersresourceid) | string | Resource ID of the virtual network. | + +### Parameter: `staticMembers.name` + +The name of the static member. + +- Required: Yes +- Type: string + +### Parameter: `staticMembers.resourceId` + +Resource ID of the virtual network. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed network group. | +| `resourceGroupName` | string | The resource group the network group was deployed into. | +| `resourceId` | string | The resource ID of the deployed network group. | diff --git a/avm/1.1.0/res/network/network-manager/network-group/main.bicep b/avm/1.1.0/res/network/network-manager/network-group/main.bicep new file mode 100644 index 000000000..aab155aad --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/network-group/main.bicep @@ -0,0 +1,71 @@ +metadata name = 'Network Manager Network Groups' +metadata description = '''This module deploys a Network Manager Network Group. +A network group is a collection of same-type network resources that you can associate with network manager configurations. You can add same-type network resources after you create the network group.''' + +@sys.description('Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment.') +param networkManagerName string + +@maxLength(64) +@sys.description('Required. The name of the network group.') +param name string + +@maxLength(500) +@sys.description('Optional. A description of the network group.') +param description string = '' + +@allowed([ + 'Subnet' + 'VirtualNetwork' +]) +@sys.description('Optional. The type of the group member. Subnet member type is used for routing configurations.') +param memberType string = 'VirtualNetwork' + +@sys.description('Optional. Static Members to create for the network group. Contains virtual networks to add to the network group.') +param staticMembers staticMembersType + +resource networkManager 'Microsoft.Network/networkManagers@2024-05-01' existing = { + name: networkManagerName +} + +resource networkGroup 'Microsoft.Network/networkManagers/networkGroups@2024-05-01' = { + name: name + parent: networkManager + properties: { + description: description + memberType: memberType + } +} + +module networkGroup_staticMembers 'static-member/main.bicep' = [ + for (staticMember, index) in staticMembers ?? []: { + name: '${uniqueString(deployment().name)}-NetworkGroup-StaticMembers-${index}' + params: { + networkManagerName: networkManager.name + networkGroupName: networkGroup.name + name: staticMember.name + resourceId: staticMember.resourceId + } + } +] + +@sys.description('The name of the deployed network group.') +output name string = networkGroup.name + +@sys.description('The resource ID of the deployed network group.') +output resourceId string = networkGroup.id + +@sys.description('The resource group the network group was deployed into.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +@export() +type staticMembersType = { + @sys.description('Required. The name of the static member.') + name: string + + @sys.description('Required. Resource ID of the virtual network.') + resourceId: string +}[]? diff --git a/avm/1.1.0/res/network/network-manager/network-group/main.json b/avm/1.1.0/res/network/network-manager/network-group/main.json new file mode 100644 index 000000000..4a3c128fa --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/network-group/main.json @@ -0,0 +1,224 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "5379165154107386117" + }, + "name": "Network Manager Network Groups", + "description": "This module deploys a Network Manager Network Group.\nA network group is a collection of same-type network resources that you can associate with network manager configurations. You can add same-type network resources after you create the network group." + }, + "definitions": { + "staticMembersType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the static member." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the virtual network." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the network group." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the network group." + } + }, + "memberType": { + "type": "string", + "defaultValue": "VirtualNetwork", + "allowedValues": [ + "Subnet", + "VirtualNetwork" + ], + "metadata": { + "description": "Optional. The type of the group member. Subnet member type is used for routing configurations." + } + }, + "staticMembers": { + "$ref": "#/definitions/staticMembersType", + "metadata": { + "description": "Optional. Static Members to create for the network group. Contains virtual networks to add to the network group." + } + } + }, + "resources": { + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "networkGroup": { + "type": "Microsoft.Network/networkManagers/networkGroups", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "memberType": "[parameters('memberType')]" + } + }, + "networkGroup_staticMembers": { + "copy": { + "name": "networkGroup_staticMembers", + "count": "[length(coalesce(parameters('staticMembers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkGroup-StaticMembers-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkManagerName": { + "value": "[parameters('networkManagerName')]" + }, + "networkGroupName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('staticMembers'), createArray())[copyIndex()].name]" + }, + "resourceId": { + "value": "[coalesce(parameters('staticMembers'), createArray())[copyIndex()].resourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12446365305773972010" + }, + "name": "Network Manager Network Group Static Members", + "description": "This module deploys a Network Manager Network Group Static Member.\nStatic membership allows you to explicitly add virtual networks to a group by manually selecting individual virtual networks." + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "networkGroupName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network group. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the static member." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the virtual network." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkManagers/networkGroups/staticMembers", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('networkGroupName'), parameters('name'))]", + "properties": { + "resourceId": "[parameters('resourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed static member." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed static member." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/networkGroups/staticMembers', parameters('networkManagerName'), parameters('networkGroupName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the static member was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "networkGroup" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed network group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed network group." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/networkGroups', parameters('networkManagerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-manager/network-group/static-member/README.md b/avm/1.1.0/res/network/network-manager/network-group/static-member/README.md new file mode 100644 index 000000000..7cb930fac --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/network-group/static-member/README.md @@ -0,0 +1,68 @@ +# Network Manager Network Group Static Members `[Microsoft.Network/networkManagers/networkGroups/staticMembers]` + +This module deploys a Network Manager Network Group Static Member. +Static membership allows you to explicitly add virtual networks to a group by manually selecting individual virtual networks. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkManagers/networkGroups/staticMembers` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/networkGroups/staticMembers) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the static member. | +| [`resourceId`](#parameter-resourceid) | string | Resource ID of the virtual network. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkGroupName`](#parameter-networkgroupname) | string | The name of the parent network group. Required if the template is used in a standalone deployment. | +| [`networkManagerName`](#parameter-networkmanagername) | string | The name of the parent network manager. Required if the template is used in a standalone deployment. | + +### Parameter: `name` + +The name of the static member. + +- Required: Yes +- Type: string + +### Parameter: `resourceId` + +Resource ID of the virtual network. + +- Required: Yes +- Type: string + +### Parameter: `networkGroupName` + +The name of the parent network group. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `networkManagerName` + +The name of the parent network manager. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed static member. | +| `resourceGroupName` | string | The resource group the static member was deployed into. | +| `resourceId` | string | The resource ID of the deployed static member. | diff --git a/avm/1.1.0/res/network/network-manager/network-group/static-member/main.bicep b/avm/1.1.0/res/network/network-manager/network-group/static-member/main.bicep new file mode 100644 index 000000000..c89395ae5 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/network-group/static-member/main.bicep @@ -0,0 +1,40 @@ +metadata name = 'Network Manager Network Group Static Members' +metadata description = '''This module deploys a Network Manager Network Group Static Member. +Static membership allows you to explicitly add virtual networks to a group by manually selecting individual virtual networks.''' + +@description('Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment.') +param networkManagerName string + +@description('Conditional. The name of the parent network group. Required if the template is used in a standalone deployment.') +param networkGroupName string + +@description('Required. The name of the static member.') +param name string + +@description('Required. Resource ID of the virtual network.') +param resourceId string + +resource networkManager 'Microsoft.Network/networkManagers@2024-05-01' existing = { + name: networkManagerName + + resource networkGroup 'networkGroups' existing = { + name: networkGroupName + } +} + +resource staticMember 'Microsoft.Network/networkManagers/networkGroups/staticMembers@2024-05-01' = { + name: name + parent: networkManager::networkGroup + properties: { + resourceId: resourceId + } +} + +@description('The name of the deployed static member.') +output name string = staticMember.name + +@description('The resource ID of the deployed static member.') +output resourceId string = staticMember.id + +@description('The resource group the static member was deployed into.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/network/network-manager/network-group/static-member/main.json b/avm/1.1.0/res/network/network-manager/network-group/static-member/main.json new file mode 100644 index 000000000..4ffade011 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/network-group/static-member/main.json @@ -0,0 +1,72 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12446365305773972010" + }, + "name": "Network Manager Network Group Static Members", + "description": "This module deploys a Network Manager Network Group Static Member.\nStatic membership allows you to explicitly add virtual networks to a group by manually selecting individual virtual networks." + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "networkGroupName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network group. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the static member." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the virtual network." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkManagers/networkGroups/staticMembers", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('networkGroupName'), parameters('name'))]", + "properties": { + "resourceId": "[parameters('resourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed static member." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed static member." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/networkGroups/staticMembers', parameters('networkManagerName'), parameters('networkGroupName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the static member was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-manager/routing-configuration/README.md b/avm/1.1.0/res/network/network-manager/routing-configuration/README.md new file mode 100644 index 000000000..e35018573 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/routing-configuration/README.md @@ -0,0 +1,245 @@ +# Network Manager Routing Configurations `[Microsoft.Network/networkManagers/routingConfigurations]` + +This module deploys an Network Manager Routing Configuration. +Routing configurations are the building blocks of UDR management. They're used to describe the desired routing behavior for a network group. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkManagers/routingConfigurations` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/routingConfigurations) | +| `Microsoft.Network/networkManagers/routingConfigurations/ruleCollections` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/routingConfigurations/ruleCollections) | +| `Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/routingConfigurations/ruleCollections/rules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the routing configuration. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkManagerName`](#parameter-networkmanagername) | string | The name of the parent network manager. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | A description of the routing configuration. | +| [`ruleCollections`](#parameter-rulecollections) | array | A routing configuration contains a set of rule collections that are applied to network groups. Each rule collection contains one or more routing rules. | + +### Parameter: `name` + +The name of the routing configuration. + +- Required: Yes +- Type: string + +### Parameter: `networkManagerName` + +The name of the parent network manager. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `description` + +A description of the routing configuration. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `ruleCollections` + +A routing configuration contains a set of rule collections that are applied to network groups. Each rule collection contains one or more routing rules. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appliesTo`](#parameter-rulecollectionsappliesto) | array | List of network groups for configuration. A routing rule collection must be associated to at least one network group. | +| [`name`](#parameter-rulecollectionsname) | string | The name of the rule collection. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-rulecollectionsdescription) | string | A description of the rule collection. | +| [`disableBgpRoutePropagation`](#parameter-rulecollectionsdisablebgproutepropagation) | bool | Disables BGP route propagation for the rule collection. Defaults to true. | +| [`rules`](#parameter-rulecollectionsrules) | array | List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager. | + +### Parameter: `ruleCollections.appliesTo` + +List of network groups for configuration. A routing rule collection must be associated to at least one network group. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkGroupResourceId`](#parameter-rulecollectionsappliestonetworkgroupresourceid) | string | The resource ID of the network group. | + +### Parameter: `ruleCollections.appliesTo.networkGroupResourceId` + +The resource ID of the network group. + +- Required: Yes +- Type: string + +### Parameter: `ruleCollections.name` + +The name of the rule collection. + +- Required: Yes +- Type: string + +### Parameter: `ruleCollections.description` + +A description of the rule collection. + +- Required: No +- Type: string + +### Parameter: `ruleCollections.disableBgpRoutePropagation` + +Disables BGP route propagation for the rule collection. Defaults to true. + +- Required: No +- Type: bool + +### Parameter: `ruleCollections.rules` + +List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`destination`](#parameter-rulecollectionsrulesdestination) | object | The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. | +| [`name`](#parameter-rulecollectionsrulesname) | string | The name of the rule. | +| [`nextHop`](#parameter-rulecollectionsrulesnexthop) | object | The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-rulecollectionsrulesdescription) | string | A description of the rule. | + +### Parameter: `ruleCollections.rules.destination` + +The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`destinationAddress`](#parameter-rulecollectionsrulesdestinationdestinationaddress) | string | The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be "AzureCloud", "Storage.AustraliaEast", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags. | +| [`type`](#parameter-rulecollectionsrulesdestinationtype) | string | The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. | + +### Parameter: `ruleCollections.rules.destination.destinationAddress` + +The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be "AzureCloud", "Storage.AustraliaEast", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags. + +- Required: Yes +- Type: string + +### Parameter: `ruleCollections.rules.destination.type` + +The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'AddressPrefix' + 'ServiceTag' + ] + ``` + +### Parameter: `ruleCollections.rules.name` + +The name of the rule. + +- Required: Yes +- Type: string + +### Parameter: `ruleCollections.rules.nextHop` + +The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`nextHopType`](#parameter-rulecollectionsrulesnexthopnexthoptype) | string | The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`nextHopAddress`](#parameter-rulecollectionsrulesnexthopnexthopaddress) | string | The IP address of the next hop. Required if the next hop type is VirtualAppliance. | + +### Parameter: `ruleCollections.rules.nextHop.nextHopType` + +The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Internet' + 'NoNextHop' + 'VirtualAppliance' + 'VirtualNetworkGateway' + 'VnetLocal' + ] + ``` + +### Parameter: `ruleCollections.rules.nextHop.nextHopAddress` + +The IP address of the next hop. Required if the next hop type is VirtualAppliance. + +- Required: No +- Type: string + +### Parameter: `ruleCollections.rules.description` + +A description of the rule. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed routing configuration. | +| `resourceGroupName` | string | The resource group the routing configuration was deployed into. | +| `resourceId` | string | The resource ID of the deployed routing configuration. | diff --git a/avm/1.1.0/res/network/network-manager/routing-configuration/main.bicep b/avm/1.1.0/res/network/network-manager/routing-configuration/main.bicep new file mode 100644 index 000000000..40d421252 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/routing-configuration/main.bicep @@ -0,0 +1,76 @@ +metadata name = 'Network Manager Routing Configurations' +metadata description = '''This module deploys an Network Manager Routing Configuration. +Routing configurations are the building blocks of UDR management. They're used to describe the desired routing behavior for a network group.''' + +@sys.description('Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment.') +param networkManagerName string + +@maxLength(64) +@sys.description('Required. The name of the routing configuration.') +param name string + +@maxLength(500) +@sys.description('Optional. A description of the routing configuration.') +param description string = '' + +@sys.description('Optional. A routing configuration contains a set of rule collections that are applied to network groups. Each rule collection contains one or more routing rules.') +param ruleCollections routingConfigurationRuleCollectionType + +resource networkManager 'Microsoft.Network/networkManagers@2024-05-01' existing = { + name: networkManagerName +} + +resource routingConfigurations 'Microsoft.Network/networkManagers/routingConfigurations@2024-05-01' = { + name: name + parent: networkManager + properties: { + description: description + } +} + +module routingConfigurations_ruleCollections 'rule-collection/main.bicep' = [ + for (ruleCollection, index) in ruleCollections ?? []: { + name: '${uniqueString(deployment().name)}-RoutingConfigurations-RuleCollections-${index}' + params: { + networkManagerName: networkManager.name + routingConfigurationName: routingConfigurations.name + name: ruleCollection.name + description: ruleCollection.?description + appliesTo: ruleCollection.appliesTo + disableBgpRoutePropagation: ruleCollection.?disableBgpRoutePropagation + rules: ruleCollection.?rules ?? [] + } + } +] + +@sys.description('The name of the deployed routing configuration.') +output name string = routingConfigurations.name + +@sys.description('The resource ID of the deployed routing configuration.') +output resourceId string = routingConfigurations.id + +@sys.description('The resource group the routing configuration was deployed into.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +import { appliesToType, rulesType } from 'rule-collection/main.bicep' +@export() +type routingConfigurationRuleCollectionType = { + @sys.description('Required. The name of the rule collection.') + name: string + + @sys.description('Optional. A description of the rule collection.') + description: string? + + @sys.description('Required. List of network groups for configuration. A routing rule collection must be associated to at least one network group.') + appliesTo: appliesToType + + @sys.description('Optional. Disables BGP route propagation for the rule collection. Defaults to true.') + disableBgpRoutePropagation: bool? + + @sys.description('Optional. List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager.') + rules: rulesType? +}[]? diff --git a/avm/1.1.0/res/network/network-manager/routing-configuration/main.json b/avm/1.1.0/res/network/network-manager/routing-configuration/main.json new file mode 100644 index 000000000..5be5db197 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/routing-configuration/main.json @@ -0,0 +1,714 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "5470663689877325880" + }, + "name": "Network Manager Routing Configurations", + "description": "This module deploys an Network Manager Routing Configuration.\nRouting configurations are the building blocks of UDR management. They're used to describe the desired routing behavior for a network group." + }, + "definitions": { + "routingConfigurationRuleCollectionType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule collection." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule collection." + } + }, + "appliesTo": { + "$ref": "#/definitions/appliesToType", + "metadata": { + "description": "Required. List of network groups for configuration. A routing rule collection must be associated to at least one network group." + } + }, + "disableBgpRoutePropagation": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Disables BGP route propagation for the rule collection. Defaults to true." + } + }, + "rules": { + "$ref": "#/definitions/rulesType", + "nullable": true, + "metadata": { + "description": "Optional. List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "_1.destinationType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "AddressPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "destinationAddress": { + "type": "string", + "metadata": { + "description": "Required. The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be \"AzureCloud\", \"Storage.AustraliaEast\", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/rule/main.bicep" + } + } + }, + "_1.nextHopType": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "NoNextHop", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + }, + "nextHopAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The IP address of the next hop. Required if the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/rule/main.bicep" + } + } + }, + "appliesToType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the network group." + } + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/main.bicep" + } + } + }, + "rulesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destination": { + "$ref": "#/definitions/_1.destinationType", + "metadata": { + "description": "Required. The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "nextHop": { + "$ref": "#/definitions/_1.nextHopType", + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/main.bicep" + } + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the routing configuration." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the routing configuration." + } + }, + "ruleCollections": { + "$ref": "#/definitions/routingConfigurationRuleCollectionType", + "metadata": { + "description": "Optional. A routing configuration contains a set of rule collections that are applied to network groups. Each rule collection contains one or more routing rules." + } + } + }, + "resources": { + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "routingConfigurations": { + "type": "Microsoft.Network/networkManagers/routingConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]" + } + }, + "routingConfigurations_ruleCollections": { + "copy": { + "name": "routingConfigurations_ruleCollections", + "count": "[length(coalesce(parameters('ruleCollections'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-RoutingConfigurations-RuleCollections-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkManagerName": { + "value": "[parameters('networkManagerName')]" + }, + "routingConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('ruleCollections'), createArray())[copyIndex()].name]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('ruleCollections'), createArray())[copyIndex()], 'description')]" + }, + "appliesTo": { + "value": "[coalesce(parameters('ruleCollections'), createArray())[copyIndex()].appliesTo]" + }, + "disableBgpRoutePropagation": { + "value": "[tryGet(coalesce(parameters('ruleCollections'), createArray())[copyIndex()], 'disableBgpRoutePropagation')]" + }, + "rules": { + "value": "[coalesce(tryGet(coalesce(parameters('ruleCollections'), createArray())[copyIndex()], 'rules'), createArray())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9240364702512586570" + }, + "name": "Network Manager Routing Configuration Rule Collections", + "description": "This module deploys an Network Manager Routing Configuration Rule Collection.\nRouting configurations are the building blocks of UDR management. They're used to describe the desired routing behavior for a network group. Each routing configuration contains one ore more rule collections. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager." + }, + "definitions": { + "appliesToType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the network group." + } + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "rulesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "metadata": { + "description": "Required. The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "nextHop": { + "$ref": "#/definitions/nextHopType", + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "destinationType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "AddressPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "destinationAddress": { + "type": "string", + "metadata": { + "description": "Required. The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be \"AzureCloud\", \"Storage.AustraliaEast\", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + }, + "nextHopType": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "NoNextHop", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + }, + "nextHopAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The IP address of the next hop. Required if the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "routingConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Routing Configuration. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the routing rule collection." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the routing rule collection." + } + }, + "appliesTo": { + "$ref": "#/definitions/appliesToType", + "metadata": { + "description": "Required. List of network groups for configuration. A routing rule collection must be associated to at least one network group." + } + }, + "disableBgpRoutePropagation": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether BGP route propagation is enabled for the routing rule collection. Defaults to true." + } + }, + "rules": { + "$ref": "#/definitions/rulesType", + "metadata": { + "description": "Optional. List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager." + } + } + }, + "resources": { + "networkManager::routingConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/routingConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('routingConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "ruleCollection": { + "type": "Microsoft.Network/networkManagers/routingConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "appliesTo": "[map(parameters('appliesTo'), lambda('group', createObject('networkGroupId', lambdaVariables('group').networkGroupResourceId)))]", + "disableBgpRoutePropagation": "[string(parameters('disableBgpRoutePropagation'))]" + } + }, + "ruleCollection_rules": { + "copy": { + "name": "ruleCollection_rules", + "count": "[length(coalesce(parameters('rules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-RuleCollections-Rules-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkManagerName": { + "value": "[parameters('networkManagerName')]" + }, + "routingConfigurationName": { + "value": "[parameters('routingConfigurationName')]" + }, + "ruleCollectionName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].name]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'description')]" + }, + "destination": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].destination]" + }, + "nextHop": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].nextHop]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10535917161454379553" + }, + "name": "Network Manager Routing configuration Rule Collection Rules", + "description": "This module deploys an Azure Virtual Network Manager (AVNM) Routing Configuration Rule Collection Rule.\nA Routing configuration contains a set of rule collections. Each rule collection contains one or more routing rules." + }, + "definitions": { + "destinationType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "AddressPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "destinationAddress": { + "type": "string", + "metadata": { + "description": "Required. The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be \"AzureCloud\", \"Storage.AustraliaEast\", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "nextHopType": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "NoNextHop", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + }, + "nextHopAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The IP address of the next hop. Required if the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "routingConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Routing configuration. Required if the template is used in a standalone deployment." + } + }, + "ruleCollectionName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent rule collection. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "metadata": { + "description": "Required. The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "nextHop": { + "$ref": "#/definitions/nextHopType", + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + } + }, + "resources": { + "networkManager::routingConfiguration::ruleCollection": { + "existing": true, + "type": "Microsoft.Network/networkManagers/routingConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('ruleCollectionName'))]" + }, + "networkManager::routingConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/routingConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('routingConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "rule": { + "type": "Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "destination": "[parameters('destination')]", + "nextHop": "[parameters('nextHop')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed rule." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "ruleCollection" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed routing rule collection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed routing rule collection." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/routingConfigurations/ruleCollections', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the routing rule collection was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "routingConfigurations" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed routing configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed routing configuration." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/routingConfigurations', parameters('networkManagerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the routing configuration was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/README.md b/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/README.md new file mode 100644 index 000000000..5b9db1704 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/README.md @@ -0,0 +1,219 @@ +# Network Manager Routing Configuration Rule Collections `[Microsoft.Network/networkManagers/routingConfigurations/ruleCollections]` + +This module deploys an Network Manager Routing Configuration Rule Collection. +Routing configurations are the building blocks of UDR management. They're used to describe the desired routing behavior for a network group. Each routing configuration contains one ore more rule collections. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkManagers/routingConfigurations/ruleCollections` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/routingConfigurations/ruleCollections) | +| `Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/routingConfigurations/ruleCollections/rules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appliesTo`](#parameter-appliesto) | array | List of network groups for configuration. A routing rule collection must be associated to at least one network group. | +| [`name`](#parameter-name) | string | The name of the routing rule collection. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkManagerName`](#parameter-networkmanagername) | string | The name of the parent network manager. Required if the template is used in a standalone deployment. | +| [`routingConfigurationName`](#parameter-routingconfigurationname) | string | The name of the parent Routing Configuration. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | A description of the routing rule collection. | +| [`disableBgpRoutePropagation`](#parameter-disablebgproutepropagation) | bool | Determines whether BGP route propagation is enabled for the routing rule collection. Defaults to true. | +| [`rules`](#parameter-rules) | array | List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager. | + +### Parameter: `appliesTo` + +List of network groups for configuration. A routing rule collection must be associated to at least one network group. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkGroupResourceId`](#parameter-appliestonetworkgroupresourceid) | string | The resource ID of the network group. | + +### Parameter: `appliesTo.networkGroupResourceId` + +The resource ID of the network group. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the routing rule collection. + +- Required: Yes +- Type: string + +### Parameter: `networkManagerName` + +The name of the parent network manager. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `routingConfigurationName` + +The name of the parent Routing Configuration. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `description` + +A description of the routing rule collection. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `disableBgpRoutePropagation` + +Determines whether BGP route propagation is enabled for the routing rule collection. Defaults to true. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `rules` + +List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`destination`](#parameter-rulesdestination) | object | The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. | +| [`name`](#parameter-rulesname) | string | The name of the rule. | +| [`nextHop`](#parameter-rulesnexthop) | object | The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-rulesdescription) | string | A description of the rule. | + +### Parameter: `rules.destination` + +The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`destinationAddress`](#parameter-rulesdestinationdestinationaddress) | string | The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be "AzureCloud", "Storage.AustraliaEast", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags. | +| [`type`](#parameter-rulesdestinationtype) | string | The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. | + +### Parameter: `rules.destination.destinationAddress` + +The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be "AzureCloud", "Storage.AustraliaEast", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags. + +- Required: Yes +- Type: string + +### Parameter: `rules.destination.type` + +The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'AddressPrefix' + 'ServiceTag' + ] + ``` + +### Parameter: `rules.name` + +The name of the rule. + +- Required: Yes +- Type: string + +### Parameter: `rules.nextHop` + +The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`nextHopType`](#parameter-rulesnexthopnexthoptype) | string | The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`nextHopAddress`](#parameter-rulesnexthopnexthopaddress) | string | The IP address of the next hop. Required if the next hop type is VirtualAppliance. | + +### Parameter: `rules.nextHop.nextHopType` + +The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Internet' + 'NoNextHop' + 'VirtualAppliance' + 'VirtualNetworkGateway' + 'VnetLocal' + ] + ``` + +### Parameter: `rules.nextHop.nextHopAddress` + +The IP address of the next hop. Required if the next hop type is VirtualAppliance. + +- Required: No +- Type: string + +### Parameter: `rules.description` + +A description of the rule. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed routing rule collection. | +| `resourceGroupName` | string | The resource group the routing rule collection was deployed into. | +| `resourceId` | string | The resource ID of the deployed routing rule collection. | diff --git a/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/main.bicep b/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/main.bicep new file mode 100644 index 000000000..7424e5906 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/main.bicep @@ -0,0 +1,96 @@ +metadata name = 'Network Manager Routing Configuration Rule Collections' +metadata description = '''This module deploys an Network Manager Routing Configuration Rule Collection. +Routing configurations are the building blocks of UDR management. They're used to describe the desired routing behavior for a network group. Each routing configuration contains one ore more rule collections. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager.''' + +@sys.description('Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment.') +param networkManagerName string + +@sys.description('Conditional. The name of the parent Routing Configuration. Required if the template is used in a standalone deployment.') +param routingConfigurationName string + +@maxLength(64) +@sys.description('Required. The name of the routing rule collection.') +param name string + +@maxLength(500) +@sys.description('Optional. A description of the routing rule collection.') +param description string = '' + +@sys.description('Required. List of network groups for configuration. A routing rule collection must be associated to at least one network group.') +param appliesTo appliesToType + +@sys.description('Optional. Determines whether BGP route propagation is enabled for the routing rule collection. Defaults to true.') +param disableBgpRoutePropagation bool = true + +@sys.description('Optional. List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager.') +param rules rulesType + +resource networkManager 'Microsoft.Network/networkManagers@2024-05-01' existing = { + name: networkManagerName + + resource routingConfiguration 'routingConfigurations' existing = { + name: routingConfigurationName + } +} + +resource ruleCollection 'Microsoft.Network/networkManagers/routingConfigurations/ruleCollections@2024-05-01' = { + name: name + parent: networkManager::routingConfiguration + properties: { + description: description + appliesTo: map(appliesTo, (group) => { + networkGroupId: any(group.networkGroupResourceId) + }) + disableBgpRoutePropagation: string(disableBgpRoutePropagation) + } +} + +module ruleCollection_rules 'rule/main.bicep' = [ + for (rule, index) in rules ?? []: { + name: '${uniqueString(deployment().name)}-RuleCollections-Rules-${index}' + params: { + networkManagerName: networkManager.name + routingConfigurationName: routingConfigurationName + ruleCollectionName: ruleCollection.name + name: rule.name + description: rule.?description + destination: rule.destination + nextHop: rule.nextHop + } + } +] + +@sys.description('The name of the deployed routing rule collection.') +output name string = ruleCollection.name + +@sys.description('The resource ID of the deployed routing rule collection.') +output resourceId string = ruleCollection.id + +@sys.description('The resource group the routing rule collection was deployed into.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +@export() +type appliesToType = { + @sys.description('Required. The resource ID of the network group.') + networkGroupResourceId: string +}[] + +import { destinationType, nextHopType } from 'rule/main.bicep' +@export() +type rulesType = { + @sys.description('Required. The name of the rule.') + name: string + + @sys.description('Optional. A description of the rule.') + description: string? + + @sys.description('Required. The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure.') + destination: destinationType + + @sys.description('Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified.') + nextHop: nextHopType +}[]? diff --git a/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/main.json b/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/main.json new file mode 100644 index 000000000..70ed47943 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/main.json @@ -0,0 +1,430 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9240364702512586570" + }, + "name": "Network Manager Routing Configuration Rule Collections", + "description": "This module deploys an Network Manager Routing Configuration Rule Collection.\nRouting configurations are the building blocks of UDR management. They're used to describe the desired routing behavior for a network group. Each routing configuration contains one ore more rule collections. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager." + }, + "definitions": { + "appliesToType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the network group." + } + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "rulesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "metadata": { + "description": "Required. The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "nextHop": { + "$ref": "#/definitions/nextHopType", + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "destinationType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "AddressPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "destinationAddress": { + "type": "string", + "metadata": { + "description": "Required. The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be \"AzureCloud\", \"Storage.AustraliaEast\", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + }, + "nextHopType": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "NoNextHop", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + }, + "nextHopAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The IP address of the next hop. Required if the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "routingConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Routing Configuration. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the routing rule collection." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the routing rule collection." + } + }, + "appliesTo": { + "$ref": "#/definitions/appliesToType", + "metadata": { + "description": "Required. List of network groups for configuration. A routing rule collection must be associated to at least one network group." + } + }, + "disableBgpRoutePropagation": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether BGP route propagation is enabled for the routing rule collection. Defaults to true." + } + }, + "rules": { + "$ref": "#/definitions/rulesType", + "metadata": { + "description": "Optional. List of rules for the routing rules collection. Warning: A rule collection without a rule will cause a deployment of routing configuration to fail in network manager." + } + } + }, + "resources": { + "networkManager::routingConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/routingConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('routingConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "ruleCollection": { + "type": "Microsoft.Network/networkManagers/routingConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "appliesTo": "[map(parameters('appliesTo'), lambda('group', createObject('networkGroupId', lambdaVariables('group').networkGroupResourceId)))]", + "disableBgpRoutePropagation": "[string(parameters('disableBgpRoutePropagation'))]" + } + }, + "ruleCollection_rules": { + "copy": { + "name": "ruleCollection_rules", + "count": "[length(coalesce(parameters('rules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-RuleCollections-Rules-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkManagerName": { + "value": "[parameters('networkManagerName')]" + }, + "routingConfigurationName": { + "value": "[parameters('routingConfigurationName')]" + }, + "ruleCollectionName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].name]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'description')]" + }, + "destination": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].destination]" + }, + "nextHop": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].nextHop]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10535917161454379553" + }, + "name": "Network Manager Routing configuration Rule Collection Rules", + "description": "This module deploys an Azure Virtual Network Manager (AVNM) Routing Configuration Rule Collection Rule.\nA Routing configuration contains a set of rule collections. Each rule collection contains one or more routing rules." + }, + "definitions": { + "destinationType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "AddressPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "destinationAddress": { + "type": "string", + "metadata": { + "description": "Required. The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be \"AzureCloud\", \"Storage.AustraliaEast\", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "nextHopType": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "NoNextHop", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + }, + "nextHopAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The IP address of the next hop. Required if the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "routingConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Routing configuration. Required if the template is used in a standalone deployment." + } + }, + "ruleCollectionName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent rule collection. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "metadata": { + "description": "Required. The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "nextHop": { + "$ref": "#/definitions/nextHopType", + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + } + }, + "resources": { + "networkManager::routingConfiguration::ruleCollection": { + "existing": true, + "type": "Microsoft.Network/networkManagers/routingConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('ruleCollectionName'))]" + }, + "networkManager::routingConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/routingConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('routingConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "rule": { + "type": "Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "destination": "[parameters('destination')]", + "nextHop": "[parameters('nextHop')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed rule." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "ruleCollection" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed routing rule collection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed routing rule collection." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/routingConfigurations/ruleCollections', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the routing rule collection was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/rule/README.md b/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/rule/README.md new file mode 100644 index 000000000..fc357bee3 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/rule/README.md @@ -0,0 +1,162 @@ +# Network Manager Routing configuration Rule Collection Rules `[Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules]` + +This module deploys an Azure Virtual Network Manager (AVNM) Routing Configuration Rule Collection Rule. +A Routing configuration contains a set of rule collections. Each rule collection contains one or more routing rules. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/routingConfigurations/ruleCollections/rules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`destination`](#parameter-destination) | object | The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. | +| [`name`](#parameter-name) | string | The name of the rule. | +| [`nextHop`](#parameter-nexthop) | object | The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkManagerName`](#parameter-networkmanagername) | string | The name of the parent network manager. Required if the template is used in a standalone deployment. | +| [`routingConfigurationName`](#parameter-routingconfigurationname) | string | The name of the parent Routing configuration. Required if the template is used in a standalone deployment. | +| [`ruleCollectionName`](#parameter-rulecollectionname) | string | The name of the parent rule collection. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | A description of the rule. | + +### Parameter: `destination` + +The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`destinationAddress`](#parameter-destinationdestinationaddress) | string | The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be "AzureCloud", "Storage.AustraliaEast", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags. | +| [`type`](#parameter-destinationtype) | string | The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. | + +### Parameter: `destination.destinationAddress` + +The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be "AzureCloud", "Storage.AustraliaEast", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags. + +- Required: Yes +- Type: string + +### Parameter: `destination.type` + +The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'AddressPrefix' + 'ServiceTag' + ] + ``` + +### Parameter: `name` + +The name of the rule. + +- Required: Yes +- Type: string + +### Parameter: `nextHop` + +The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`nextHopType`](#parameter-nexthopnexthoptype) | string | The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`nextHopAddress`](#parameter-nexthopnexthopaddress) | string | The IP address of the next hop. Required if the next hop type is VirtualAppliance. | + +### Parameter: `nextHop.nextHopType` + +The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Internet' + 'NoNextHop' + 'VirtualAppliance' + 'VirtualNetworkGateway' + 'VnetLocal' + ] + ``` + +### Parameter: `nextHop.nextHopAddress` + +The IP address of the next hop. Required if the next hop type is VirtualAppliance. + +- Required: No +- Type: string + +### Parameter: `networkManagerName` + +The name of the parent network manager. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `routingConfigurationName` + +The name of the parent Routing configuration. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `ruleCollectionName` + +The name of the parent rule collection. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `description` + +A description of the rule. + +- Required: No +- Type: string +- Default: `''` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed rule. | +| `resourceGroupName` | string | The resource group the rule was deployed into. | +| `resourceId` | string | The resource ID of the deployed rule. | diff --git a/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/rule/main.bicep b/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/rule/main.bicep new file mode 100644 index 000000000..9f4352351 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/rule/main.bicep @@ -0,0 +1,79 @@ +metadata name = 'Network Manager Routing configuration Rule Collection Rules' +metadata description = '''This module deploys an Azure Virtual Network Manager (AVNM) Routing Configuration Rule Collection Rule. +A Routing configuration contains a set of rule collections. Each rule collection contains one or more routing rules.''' + +@sys.description('Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment.') +param networkManagerName string + +@sys.description('Conditional. The name of the parent Routing configuration. Required if the template is used in a standalone deployment.') +param routingConfigurationName string + +@sys.description('Conditional. The name of the parent rule collection. Required if the template is used in a standalone deployment.') +param ruleCollectionName string + +@maxLength(64) +@sys.description('Required. The name of the rule.') +param name string + +@maxLength(500) +@sys.description('Optional. A description of the rule.') +param description string = '' + +@sys.description('Required. The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure.') +param destination destinationType + +@sys.description('Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified.') +param nextHop nextHopType + +resource networkManager 'Microsoft.Network/networkManagers@2024-05-01' existing = { + name: networkManagerName + + resource routingConfiguration 'routingConfigurations' existing = { + name: routingConfigurationName + + resource ruleCollection 'ruleCollections' existing = { + name: ruleCollectionName + } + } +} + +resource rule 'Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules@2024-05-01' = { + name: name + parent: networkManager::routingConfiguration::ruleCollection + properties: { + description: description + destination: destination + nextHop: nextHop + } +} + +@sys.description('The name of the deployed rule.') +output name string = rule.name + +@sys.description('The resource ID of the deployed rule.') +output resourceId string = rule.id + +@sys.description('The resource group the rule was deployed into.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +@export() +type destinationType = { + @sys.description('Required. The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure.') + type: 'AddressPrefix' | 'ServiceTag' + + @sys.description('Required. The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be "AzureCloud", "Storage.AustraliaEast", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags.') + destinationAddress: string +} + +@export() +type nextHopType = { + @sys.description('Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified.') + nextHopType: 'Internet' | 'NoNextHop' | 'VirtualAppliance' | 'VirtualNetworkGateway' | 'VnetLocal' + + @sys.description('Conditional. The IP address of the next hop. Required if the next hop type is VirtualAppliance.') + nextHopAddress: string? +} diff --git a/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/rule/main.json b/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/rule/main.json new file mode 100644 index 000000000..eb9fafa0e --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/routing-configuration/rule-collection/rule/main.json @@ -0,0 +1,168 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10535917161454379553" + }, + "name": "Network Manager Routing configuration Rule Collection Rules", + "description": "This module deploys an Azure Virtual Network Manager (AVNM) Routing Configuration Rule Collection Rule.\nA Routing configuration contains a set of rule collections. Each rule collection contains one or more routing rules." + }, + "definitions": { + "destinationType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "AddressPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. The destination type can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "destinationAddress": { + "type": "string", + "metadata": { + "description": "Required. The destination IP addresses or Service Tag for this route. For IP addresses, it is the IP address range in CIDR notation that this route applies to. If the destination IP address of a packet falls in this range, it matches this route. As for Service Tags, valid identifiers can be \"AzureCloud\", \"Storage.AustraliaEast\", etc. See https://docs.microsoft.com/en-us/azure/virtual-network/service-tags-overview for more information on service tags." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "nextHopType": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "NoNextHop", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + }, + "nextHopAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The IP address of the next hop. Required if the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "routingConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Routing configuration. Required if the template is used in a standalone deployment." + } + }, + "ruleCollectionName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent rule collection. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "metadata": { + "description": "Required. The destination can be IP addresses or Service Tag for this route. Address Prefixes are defined using the CIDR format, while Service tags are predefined identifiers that represent a category of IP addresses, which are managed by Azure." + } + }, + "nextHop": { + "$ref": "#/definitions/nextHopType", + "metadata": { + "description": "Required. The next hop handles the matching packets for this route. It can be the virtual network, the virtual network gateway, the internet, a virtual appliance, or none. Virtual network gateways cannot be used if the address prefix is IPv6. If the next hop type is VirtualAppliance, the next hop address must be specified." + } + } + }, + "resources": { + "networkManager::routingConfiguration::ruleCollection": { + "existing": true, + "type": "Microsoft.Network/networkManagers/routingConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('ruleCollectionName'))]" + }, + "networkManager::routingConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/routingConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('routingConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "rule": { + "type": "Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "destination": "[parameters('destination')]", + "nextHop": "[parameters('nextHop')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed rule." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/routingConfigurations/ruleCollections/rules', parameters('networkManagerName'), parameters('routingConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-manager/scope-connection/README.md b/avm/1.1.0/res/network/network-manager/scope-connection/README.md new file mode 100644 index 000000000..753788744 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/scope-connection/README.md @@ -0,0 +1,82 @@ +# Network Manager Scope Connections `[Microsoft.Network/networkManagers/scopeConnections]` + +This module deploys a Network Manager Scope Connection. +Create a cross-tenant connection to manage a resource from another tenant. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkManagers/scopeConnections` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/scopeConnections) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the scope connection. | +| [`resourceId`](#parameter-resourceid) | string | Enter the subscription or management group resource ID that you want to add to this network manager's scope. | +| [`tenantId`](#parameter-tenantid) | string | Tenant ID of the subscription or management group that you want to manage. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkManagerName`](#parameter-networkmanagername) | string | The name of the parent network manager. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | A description of the scope connection. | + +### Parameter: `name` + +The name of the scope connection. + +- Required: Yes +- Type: string + +### Parameter: `resourceId` + +Enter the subscription or management group resource ID that you want to add to this network manager's scope. + +- Required: Yes +- Type: string + +### Parameter: `tenantId` + +Tenant ID of the subscription or management group that you want to manage. + +- Required: Yes +- Type: string + +### Parameter: `networkManagerName` + +The name of the parent network manager. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `description` + +A description of the scope connection. + +- Required: No +- Type: string +- Default: `''` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed scope connection. | +| `resourceGroupName` | string | The resource group the scope connection was deployed into. | +| `resourceId` | string | The resource ID of the deployed scope connection. | diff --git a/avm/1.1.0/res/network/network-manager/scope-connection/main.bicep b/avm/1.1.0/res/network/network-manager/scope-connection/main.bicep new file mode 100644 index 000000000..8aaa7a551 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/scope-connection/main.bicep @@ -0,0 +1,43 @@ +metadata name = 'Network Manager Scope Connections' +metadata description = '''This module deploys a Network Manager Scope Connection. +Create a cross-tenant connection to manage a resource from another tenant.''' + +@sys.description('Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment.') +param networkManagerName string + +@maxLength(64) +@sys.description('Required. The name of the scope connection.') +param name string + +@maxLength(500) +@sys.description('Optional. A description of the scope connection.') +param description string = '' + +@sys.description('Required. Enter the subscription or management group resource ID that you want to add to this network manager\'s scope.') +param resourceId string + +@sys.description('Required. Tenant ID of the subscription or management group that you want to manage.') +param tenantId string + +resource networkManager 'Microsoft.Network/networkManagers@2024-05-01' existing = { + name: networkManagerName +} + +resource scopeConnection 'Microsoft.Network/networkManagers/scopeConnections@2024-05-01' = { + name: name + parent: networkManager + properties: { + description: description + resourceId: resourceId + tenantId: tenantId + } +} + +@sys.description('The name of the deployed scope connection.') +output name string = scopeConnection.name + +@sys.description('The resource ID of the deployed scope connection.') +output resourceId string = scopeConnection.id + +@sys.description('The resource group the scope connection was deployed into.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/network/network-manager/scope-connection/main.json b/avm/1.1.0/res/network/network-manager/scope-connection/main.json new file mode 100644 index 000000000..5eb545bd4 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/scope-connection/main.json @@ -0,0 +1,83 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "2901273702758810148" + }, + "name": "Network Manager Scope Connections", + "description": "This module deploys a Network Manager Scope Connection.\nCreate a cross-tenant connection to manage a resource from another tenant." + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the scope connection." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the scope connection." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. Enter the subscription or management group resource ID that you want to add to this network manager's scope." + } + }, + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. Tenant ID of the subscription or management group that you want to manage." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkManagers/scopeConnections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "resourceId": "[parameters('resourceId')]", + "tenantId": "[parameters('tenantId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed scope connection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed scope connection." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/scopeConnections', parameters('networkManagerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the scope connection was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-manager/security-admin-configuration/README.md b/avm/1.1.0/res/network/network-manager/security-admin-configuration/README.md new file mode 100644 index 000000000..2706a6742 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/security-admin-configuration/README.md @@ -0,0 +1,357 @@ +# Network Manager Security Admin Configurations `[Microsoft.Network/networkManagers/securityAdminConfigurations]` + +This module deploys an Network Manager Security Admin Configuration. +A security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkManagers/securityAdminConfigurations` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/securityAdminConfigurations) | +| `Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/securityAdminConfigurations/ruleCollections) | +| `Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/securityAdminConfigurations/ruleCollections/rules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applyOnNetworkIntentPolicyBasedServices`](#parameter-applyonnetworkintentpolicybasedservices) | array | Enum list of network intent policy based services. | +| [`name`](#parameter-name) | string | The name of the security admin configuration. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkManagerName`](#parameter-networkmanagername) | string | The name of the parent network manager. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | A description of the security admin configuration. | +| [`networkGroupAddressSpaceAggregationOption`](#parameter-networkgroupaddressspaceaggregationoption) | string | Determine update behavior for changes to network groups referenced within the rules in this configuration. | +| [`ruleCollections`](#parameter-rulecollections) | array | A security admin configuration contains a set of rule collections that are applied to network groups. Each rule collection contains one or more security admin rules. | + +### Parameter: `applyOnNetworkIntentPolicyBasedServices` + +Enum list of network intent policy based services. + +- Required: Yes +- Type: array +- Allowed: + ```Bicep + [ + 'All' + 'AllowRulesOnly' + 'None' + ] + ``` + +### Parameter: `name` + +The name of the security admin configuration. + +- Required: Yes +- Type: string + +### Parameter: `networkManagerName` + +The name of the parent network manager. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `description` + +A description of the security admin configuration. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `networkGroupAddressSpaceAggregationOption` + +Determine update behavior for changes to network groups referenced within the rules in this configuration. + +- Required: No +- Type: string +- Default: `'None'` +- Allowed: + ```Bicep + [ + 'Manual' + 'None' + ] + ``` + +### Parameter: `ruleCollections` + +A security admin configuration contains a set of rule collections that are applied to network groups. Each rule collection contains one or more security admin rules. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appliesToGroups`](#parameter-rulecollectionsappliestogroups) | array | List of network groups for configuration. An admin rule collection must be associated to at least one network group. | +| [`name`](#parameter-rulecollectionsname) | string | The name of the admin rule collection. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-rulecollectionsdescription) | string | A description of the admin rule collection. | +| [`rules`](#parameter-rulecollectionsrules) | array | List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail. | + +### Parameter: `ruleCollections.appliesToGroups` + +List of network groups for configuration. An admin rule collection must be associated to at least one network group. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkGroupResourceId`](#parameter-rulecollectionsappliestogroupsnetworkgroupresourceid) | string | The resource ID of the network group. | + +### Parameter: `ruleCollections.appliesToGroups.networkGroupResourceId` + +The resource ID of the network group. + +- Required: Yes +- Type: string + +### Parameter: `ruleCollections.name` + +The name of the admin rule collection. + +- Required: Yes +- Type: string + +### Parameter: `ruleCollections.description` + +A description of the admin rule collection. + +- Required: No +- Type: string + +### Parameter: `ruleCollections.rules` + +List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`access`](#parameter-rulecollectionsrulesaccess) | string | Indicates the access allowed for this particular rule. "Allow" means traffic matching this rule will be allowed. "Deny" means traffic matching this rule will be blocked. "AlwaysAllow" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs. | +| [`direction`](#parameter-rulecollectionsrulesdirection) | string | Indicates if the traffic matched against the rule in inbound or outbound. | +| [`name`](#parameter-rulecollectionsrulesname) | string | The name of the rule. | +| [`priority`](#parameter-rulecollectionsrulespriority) | int | The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule. | +| [`protocol`](#parameter-rulecollectionsrulesprotocol) | string | Network protocol this rule applies to. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-rulecollectionsrulesdescription) | string | A description of the rule. | +| [`destinationPortRanges`](#parameter-rulecollectionsrulesdestinationportranges) | array | List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. | +| [`destinations`](#parameter-rulecollectionsrulesdestinations) | array | The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. | +| [`sourcePortRanges`](#parameter-rulecollectionsrulessourceportranges) | array | List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. | +| [`sources`](#parameter-rulecollectionsrulessources) | array | The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. | + +### Parameter: `ruleCollections.rules.access` + +Indicates the access allowed for this particular rule. "Allow" means traffic matching this rule will be allowed. "Deny" means traffic matching this rule will be blocked. "AlwaysAllow" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Allow' + 'AlwaysAllow' + 'Deny' + ] + ``` + +### Parameter: `ruleCollections.rules.direction` + +Indicates if the traffic matched against the rule in inbound or outbound. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Inbound' + 'Outbound' + ] + ``` + +### Parameter: `ruleCollections.rules.name` + +The name of the rule. + +- Required: Yes +- Type: string + +### Parameter: `ruleCollections.rules.priority` + +The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule. + +- Required: Yes +- Type: int +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `ruleCollections.rules.protocol` + +Network protocol this rule applies to. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Ah' + 'Any' + 'Esp' + 'Icmp' + 'Tcp' + 'Udp' + ] + ``` +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `ruleCollections.rules.description` + +A description of the rule. + +- Required: No +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `ruleCollections.rules.destinationPortRanges` + +List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `ruleCollections.rules.destinations` + +The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefix`](#parameter-rulecollectionsrulesdestinationsaddressprefix) | string | Address prefix. | +| [`addressPrefixType`](#parameter-rulecollectionsrulesdestinationsaddressprefixtype) | string | Address prefix type. | + +### Parameter: `ruleCollections.rules.destinations.addressPrefix` + +Address prefix. + +- Required: Yes +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `ruleCollections.rules.destinations.addressPrefixType` + +Address prefix type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'IPPrefix' + 'ServiceTag' + ] + ``` +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `ruleCollections.rules.sourcePortRanges` + +List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `ruleCollections.rules.sources` + +The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefix`](#parameter-rulecollectionsrulessourcesaddressprefix) | string | Address prefix. | +| [`addressPrefixType`](#parameter-rulecollectionsrulessourcesaddressprefixtype) | string | Address prefix type. | + +### Parameter: `ruleCollections.rules.sources.addressPrefix` + +Address prefix. + +- Required: Yes +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `ruleCollections.rules.sources.addressPrefixType` + +Address prefix type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'IPPrefix' + 'ServiceTag' + ] + ``` +- MinValue: 1 +- MaxValue: 4096 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed security admin configuration. | +| `resourceGroupName` | string | The resource group the security admin configuration was deployed into. | +| `resourceId` | string | The resource ID of the deployed security admin configuration. | diff --git a/avm/1.1.0/res/network/network-manager/security-admin-configuration/main.bicep b/avm/1.1.0/res/network/network-manager/security-admin-configuration/main.bicep new file mode 100644 index 000000000..92b82b4d9 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/security-admin-configuration/main.bicep @@ -0,0 +1,87 @@ +metadata name = 'Network Manager Security Admin Configurations' +metadata description = '''This module deploys an Network Manager Security Admin Configuration. +A security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules.''' + +@sys.description('Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment.') +param networkManagerName string + +@maxLength(64) +@sys.description('Required. The name of the security admin configuration.') +param name string + +@maxLength(500) +@sys.description('Optional. A description of the security admin configuration.') +param description string = '' + +@sys.description('Required. Enum list of network intent policy based services.') +param applyOnNetworkIntentPolicyBasedServices applyOnNetworkIntentPolicyBasedServicesType + +@allowed([ + 'None' + 'Manual' +]) +@sys.description('Optional. Determine update behavior for changes to network groups referenced within the rules in this configuration.') +param networkGroupAddressSpaceAggregationOption string = 'None' + +@sys.description('Optional. A security admin configuration contains a set of rule collections that are applied to network groups. Each rule collection contains one or more security admin rules.') +param ruleCollections securityAdminConfigurationRuleCollectionType + +resource networkManager 'Microsoft.Network/networkManagers@2024-05-01' existing = { + name: networkManagerName +} + +resource securityAdminConfigurations 'Microsoft.Network/networkManagers/securityAdminConfigurations@2024-05-01' = { + name: name + parent: networkManager + properties: { + description: description + applyOnNetworkIntentPolicyBasedServices: applyOnNetworkIntentPolicyBasedServices + networkGroupAddressSpaceAggregationOption: networkGroupAddressSpaceAggregationOption + } +} + +module securityAdminConfigurations_ruleCollections 'rule-collection/main.bicep' = [ + for (ruleCollection, index) in ruleCollections ?? []: { + name: '${uniqueString(deployment().name)}-SecurityAdminConfigurations-RuleCollections-${index}' + params: { + networkManagerName: networkManager.name + securityAdminConfigurationName: securityAdminConfigurations.name + name: ruleCollection.name + description: ruleCollection.?description + appliesToGroups: ruleCollection.appliesToGroups + rules: ruleCollection.?rules ?? [] + } + } +] + +@sys.description('The name of the deployed security admin configuration.') +output name string = securityAdminConfigurations.name + +@sys.description('The resource ID of the deployed security admin configuration.') +output resourceId string = securityAdminConfigurations.id + +@sys.description('The resource group the security admin configuration was deployed into.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +@export() +type applyOnNetworkIntentPolicyBasedServicesType = ('None' | 'All' | 'AllowRulesOnly')[] + +import { appliesToGroupsType, rulesType } from './rule-collection/main.bicep' +@export() +type securityAdminConfigurationRuleCollectionType = { + @sys.description('Required. The name of the admin rule collection.') + name: string + + @sys.description('Optional. A description of the admin rule collection.') + description: string? + + @sys.description('Required. List of network groups for configuration. An admin rule collection must be associated to at least one network group.') + appliesToGroups: appliesToGroupsType + + @sys.description('Optional. List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail.') + rules: rulesType? +}[]? diff --git a/avm/1.1.0/res/network/network-manager/security-admin-configuration/main.json b/avm/1.1.0/res/network/network-manager/security-admin-configuration/main.json new file mode 100644 index 000000000..351475f5b --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/security-admin-configuration/main.json @@ -0,0 +1,1012 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15398119849930180416" + }, + "name": "Network Manager Security Admin Configurations", + "description": "This module deploys an Network Manager Security Admin Configuration.\nA security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules." + }, + "definitions": { + "applyOnNetworkIntentPolicyBasedServicesType": { + "type": "array", + "allowedValues": [ + "All", + "AllowRulesOnly", + "None" + ], + "metadata": { + "__bicep_export!": true + } + }, + "securityAdminConfigurationRuleCollectionType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the admin rule collection." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the admin rule collection." + } + }, + "appliesToGroups": { + "$ref": "#/definitions/appliesToGroupsType", + "metadata": { + "description": "Required. List of network groups for configuration. An admin rule collection must be associated to at least one network group." + } + }, + "rules": { + "$ref": "#/definitions/rulesType", + "nullable": true, + "metadata": { + "description": "Optional. List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "_1.destinationPortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/rule/main.bicep" + } + } + }, + "_1.destinationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/rule/main.bicep" + } + } + }, + "_1.sourcePortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/rule/main.bicep" + } + } + }, + "_1.sourcesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/rule/main.bicep" + } + } + }, + "appliesToGroupsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the network group." + } + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/main.bicep" + } + } + }, + "rulesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule." + } + }, + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "AlwaysAllow", + "Deny" + ], + "metadata": { + "description": "Required. Indicates the access allowed for this particular rule. \"Allow\" means traffic matching this rule will be allowed. \"Deny\" means traffic matching this rule will be blocked. \"AlwaysAllow\" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destinationPortRanges": { + "$ref": "#/definitions/_1.destinationPortRangesType", + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "destinations": { + "$ref": "#/definitions/_1.destinationsType", + "nullable": true, + "metadata": { + "description": "Optional. The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. Indicates if the traffic matched against the rule in inbound or outbound." + } + }, + "priority": { + "type": "int", + "minValue": 1, + "maxValue": 4096, + "metadata": { + "description": "Required. The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Ah", + "Any", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourcePortRanges": { + "$ref": "#/definitions/_1.sourcePortRangesType", + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "sources": { + "$ref": "#/definitions/_1.sourcesType", + "nullable": true, + "metadata": { + "description": "Optional. The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule-collection/main.bicep" + } + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the security admin configuration." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the security admin configuration." + } + }, + "applyOnNetworkIntentPolicyBasedServices": { + "$ref": "#/definitions/applyOnNetworkIntentPolicyBasedServicesType", + "metadata": { + "description": "Required. Enum list of network intent policy based services." + } + }, + "networkGroupAddressSpaceAggregationOption": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "None", + "Manual" + ], + "metadata": { + "description": "Optional. Determine update behavior for changes to network groups referenced within the rules in this configuration." + } + }, + "ruleCollections": { + "$ref": "#/definitions/securityAdminConfigurationRuleCollectionType", + "metadata": { + "description": "Optional. A security admin configuration contains a set of rule collections that are applied to network groups. Each rule collection contains one or more security admin rules." + } + } + }, + "resources": { + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "securityAdminConfigurations": { + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "applyOnNetworkIntentPolicyBasedServices": "[parameters('applyOnNetworkIntentPolicyBasedServices')]", + "networkGroupAddressSpaceAggregationOption": "[parameters('networkGroupAddressSpaceAggregationOption')]" + } + }, + "securityAdminConfigurations_ruleCollections": { + "copy": { + "name": "securityAdminConfigurations_ruleCollections", + "count": "[length(coalesce(parameters('ruleCollections'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-SecurityAdminConfigurations-RuleCollections-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkManagerName": { + "value": "[parameters('networkManagerName')]" + }, + "securityAdminConfigurationName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('ruleCollections'), createArray())[copyIndex()].name]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('ruleCollections'), createArray())[copyIndex()], 'description')]" + }, + "appliesToGroups": { + "value": "[coalesce(parameters('ruleCollections'), createArray())[copyIndex()].appliesToGroups]" + }, + "rules": { + "value": "[coalesce(tryGet(coalesce(parameters('ruleCollections'), createArray())[copyIndex()], 'rules'), createArray())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "17868772067986931575" + }, + "name": "Network Manager Security Admin Configuration Rule Collections", + "description": "This module deploys an Network Manager Security Admin Configuration Rule Collection.\nA security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail." + }, + "definitions": { + "appliesToGroupsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the network group." + } + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "rulesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule." + } + }, + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "AlwaysAllow", + "Deny" + ], + "metadata": { + "description": "Required. Indicates the access allowed for this particular rule. \"Allow\" means traffic matching this rule will be allowed. \"Deny\" means traffic matching this rule will be blocked. \"AlwaysAllow\" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destinationPortRanges": { + "$ref": "#/definitions/destinationPortRangesType", + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "destinations": { + "$ref": "#/definitions/destinationsType", + "nullable": true, + "metadata": { + "description": "Optional. The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. Indicates if the traffic matched against the rule in inbound or outbound." + } + }, + "priority": { + "type": "int", + "minValue": 1, + "maxValue": 4096, + "metadata": { + "description": "Required. The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Ah", + "Any", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourcePortRanges": { + "$ref": "#/definitions/sourcePortRangesType", + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "sources": { + "$ref": "#/definitions/sourcesType", + "nullable": true, + "metadata": { + "description": "Optional. The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "destinationPortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + }, + "destinationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + }, + "sourcePortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + }, + "sourcesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "securityAdminConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent security admin configuration. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the admin rule collection." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the admin rule collection." + } + }, + "appliesToGroups": { + "$ref": "#/definitions/appliesToGroupsType", + "metadata": { + "description": "Required. List of network groups for configuration. An admin rule collection must be associated to at least one network group." + } + }, + "rules": { + "$ref": "#/definitions/rulesType", + "metadata": { + "description": "Optional. List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail." + } + } + }, + "resources": { + "networkManager::securityAdminConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "ruleCollection": { + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "appliesToGroups": "[map(parameters('appliesToGroups'), lambda('group', createObject('networkGroupId', lambdaVariables('group').networkGroupResourceId)))]" + } + }, + "ruleCollection_rules": { + "copy": { + "name": "ruleCollection_rules", + "count": "[length(coalesce(parameters('rules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-RuleCollections-Rules-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkManagerName": { + "value": "[parameters('networkManagerName')]" + }, + "securityAdminConfigurationName": { + "value": "[parameters('securityAdminConfigurationName')]" + }, + "ruleCollectionName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].name]" + }, + "access": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].access]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'description')]" + }, + "destinationPortRanges": { + "value": "[coalesce(tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'destinationPortRanges'), createArray())]" + }, + "destinations": { + "value": "[coalesce(tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'destinations'), createArray())]" + }, + "direction": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].direction]" + }, + "priority": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].priority]" + }, + "protocol": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].protocol]" + }, + "sourcePortRanges": { + "value": "[coalesce(tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'sourcePortRanges'), createArray())]" + }, + "sources": { + "value": "[coalesce(tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'sources'), createArray())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3195100427454268317" + }, + "name": "Network Manager Security Admin Configuration Rule Collection Rules", + "description": "This module deploys an Azure Virtual Network Manager (AVNM) Security Admin Configuration Rule Collection Rule.\nA security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules." + }, + "definitions": { + "destinationPortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "destinationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "sourcePortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "sourcesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "securityAdminConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent security admin configuration. Required if the template is used in a standalone deployment." + } + }, + "ruleCollectionName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent rule collection. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "AlwaysAllow", + "Deny" + ], + "metadata": { + "description": "Required. Indicates the access allowed for this particular rule. \"Allow\" means traffic matching this rule will be allowed. \"Deny\" means traffic matching this rule will be blocked. \"AlwaysAllow\" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs." + } + }, + "destinationPortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "destinations": { + "$ref": "#/definitions/destinationsType", + "metadata": { + "description": "Optional. The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. Indicates if the traffic matched against the rule in inbound or outbound." + } + }, + "priority": { + "type": "int", + "minValue": 1, + "maxValue": 4096, + "metadata": { + "description": "Required. The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Ah", + "Any", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourcePortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "sources": { + "$ref": "#/definitions/sourcesType", + "metadata": { + "description": "Optional. The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + } + }, + "resources": { + "networkManager::securityAdminConfiguration::ruleCollection": { + "existing": true, + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('ruleCollectionName'))]" + }, + "networkManager::securityAdminConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "rule": { + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]", + "kind": "Custom", + "properties": { + "access": "[parameters('access')]", + "description": "[parameters('description')]", + "destinationPortRanges": "[parameters('destinationPortRanges')]", + "destinations": "[parameters('destinations')]", + "direction": "[parameters('direction')]", + "priority": "[parameters('priority')]", + "protocol": "[parameters('protocol')]", + "sourcePortRanges": "[parameters('sourcePortRanges')]", + "sources": "[parameters('sources')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed rule." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "ruleCollection" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed admin rule collection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed admin rule collection." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the admin rule collection was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "securityAdminConfigurations" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed security admin configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed security admin configuration." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/securityAdminConfigurations', parameters('networkManagerName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the security admin configuration was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/README.md b/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/README.md new file mode 100644 index 000000000..695ecbbf5 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/README.md @@ -0,0 +1,298 @@ +# Network Manager Security Admin Configuration Rule Collections `[Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections]` + +This module deploys an Network Manager Security Admin Configuration Rule Collection. +A security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/securityAdminConfigurations/ruleCollections) | +| `Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/securityAdminConfigurations/ruleCollections/rules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appliesToGroups`](#parameter-appliestogroups) | array | List of network groups for configuration. An admin rule collection must be associated to at least one network group. | +| [`name`](#parameter-name) | string | The name of the admin rule collection. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkManagerName`](#parameter-networkmanagername) | string | The name of the parent network manager. Required if the template is used in a standalone deployment. | +| [`securityAdminConfigurationName`](#parameter-securityadminconfigurationname) | string | The name of the parent security admin configuration. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | A description of the admin rule collection. | +| [`rules`](#parameter-rules) | array | List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail. | + +### Parameter: `appliesToGroups` + +List of network groups for configuration. An admin rule collection must be associated to at least one network group. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkGroupResourceId`](#parameter-appliestogroupsnetworkgroupresourceid) | string | The resource ID of the network group. | + +### Parameter: `appliesToGroups.networkGroupResourceId` + +The resource ID of the network group. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the admin rule collection. + +- Required: Yes +- Type: string + +### Parameter: `networkManagerName` + +The name of the parent network manager. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `securityAdminConfigurationName` + +The name of the parent security admin configuration. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `description` + +A description of the admin rule collection. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `rules` + +List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`access`](#parameter-rulesaccess) | string | Indicates the access allowed for this particular rule. "Allow" means traffic matching this rule will be allowed. "Deny" means traffic matching this rule will be blocked. "AlwaysAllow" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs. | +| [`direction`](#parameter-rulesdirection) | string | Indicates if the traffic matched against the rule in inbound or outbound. | +| [`name`](#parameter-rulesname) | string | The name of the rule. | +| [`priority`](#parameter-rulespriority) | int | The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule. | +| [`protocol`](#parameter-rulesprotocol) | string | Network protocol this rule applies to. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-rulesdescription) | string | A description of the rule. | +| [`destinationPortRanges`](#parameter-rulesdestinationportranges) | array | List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. | +| [`destinations`](#parameter-rulesdestinations) | array | The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. | +| [`sourcePortRanges`](#parameter-rulessourceportranges) | array | List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. | +| [`sources`](#parameter-rulessources) | array | The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. | + +### Parameter: `rules.access` + +Indicates the access allowed for this particular rule. "Allow" means traffic matching this rule will be allowed. "Deny" means traffic matching this rule will be blocked. "AlwaysAllow" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Allow' + 'AlwaysAllow' + 'Deny' + ] + ``` + +### Parameter: `rules.direction` + +Indicates if the traffic matched against the rule in inbound or outbound. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Inbound' + 'Outbound' + ] + ``` + +### Parameter: `rules.name` + +The name of the rule. + +- Required: Yes +- Type: string + +### Parameter: `rules.priority` + +The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule. + +- Required: Yes +- Type: int +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `rules.protocol` + +Network protocol this rule applies to. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Ah' + 'Any' + 'Esp' + 'Icmp' + 'Tcp' + 'Udp' + ] + ``` +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `rules.description` + +A description of the rule. + +- Required: No +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `rules.destinationPortRanges` + +List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `rules.destinations` + +The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefix`](#parameter-rulesdestinationsaddressprefix) | string | Address prefix. | +| [`addressPrefixType`](#parameter-rulesdestinationsaddressprefixtype) | string | Address prefix type. | + +### Parameter: `rules.destinations.addressPrefix` + +Address prefix. + +- Required: Yes +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `rules.destinations.addressPrefixType` + +Address prefix type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'IPPrefix' + 'ServiceTag' + ] + ``` +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `rules.sourcePortRanges` + +List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `rules.sources` + +The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefix`](#parameter-rulessourcesaddressprefix) | string | Address prefix. | +| [`addressPrefixType`](#parameter-rulessourcesaddressprefixtype) | string | Address prefix type. | + +### Parameter: `rules.sources.addressPrefix` + +Address prefix. + +- Required: Yes +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `rules.sources.addressPrefixType` + +Address prefix type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'IPPrefix' + 'ServiceTag' + ] + ``` +- MinValue: 1 +- MaxValue: 4096 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed admin rule collection. | +| `resourceGroupName` | string | The resource group the admin rule collection was deployed into. | +| `resourceId` | string | The resource ID of the deployed admin rule collection. | diff --git a/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/main.bicep b/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/main.bicep new file mode 100644 index 000000000..7a99f9b56 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/main.bicep @@ -0,0 +1,118 @@ +metadata name = 'Network Manager Security Admin Configuration Rule Collections' +metadata description = '''This module deploys an Network Manager Security Admin Configuration Rule Collection. +A security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail.''' + +@sys.description('Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment.') +param networkManagerName string + +@sys.description('Conditional. The name of the parent security admin configuration. Required if the template is used in a standalone deployment.') +param securityAdminConfigurationName string + +@maxLength(64) +@sys.description('Required. The name of the admin rule collection.') +param name string + +@maxLength(500) +@sys.description('Optional. A description of the admin rule collection.') +param description string = '' + +@sys.description('Required. List of network groups for configuration. An admin rule collection must be associated to at least one network group.') +param appliesToGroups appliesToGroupsType + +@sys.description('Optional. List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail.') +param rules rulesType + +resource networkManager 'Microsoft.Network/networkManagers@2024-05-01' existing = { + name: networkManagerName + + resource securityAdminConfiguration 'securityAdminConfigurations' existing = { + name: securityAdminConfigurationName + } +} + +resource ruleCollection 'Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections@2024-05-01' = { + name: name + parent: networkManager::securityAdminConfiguration + properties: { + description: description + appliesToGroups: map(appliesToGroups, (group) => { + networkGroupId: any(group.networkGroupResourceId) + }) + } +} + +module ruleCollection_rules 'rule/main.bicep' = [ + for (rule, index) in rules ?? []: { + name: '${uniqueString(deployment().name)}-RuleCollections-Rules-${index}' + params: { + networkManagerName: networkManager.name + securityAdminConfigurationName: securityAdminConfigurationName + ruleCollectionName: ruleCollection.name + name: rule.name + access: rule.access + description: rule.?description + destinationPortRanges: rule.?destinationPortRanges ?? [] + destinations: rule.?destinations ?? [] + direction: rule.direction + priority: rule.priority + protocol: rule.protocol + sourcePortRanges: rule.?sourcePortRanges ?? [] + sources: rule.?sources ?? [] + } + } +] + +@sys.description('The name of the deployed admin rule collection.') +output name string = ruleCollection.name + +@sys.description('The resource ID of the deployed admin rule collection.') +output resourceId string = ruleCollection.id + +@sys.description('The resource group the admin rule collection was deployed into.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +@export() +type appliesToGroupsType = { + @sys.description('Required. The resource ID of the network group.') + networkGroupResourceId: string +}[] + +import { destinationPortRangesType, destinationsType, sourcePortRangesType, sourcesType } from './rule/main.bicep' +@export() +type rulesType = { + @sys.description('Required. The name of the rule.') + name: string + + @sys.description('Required. Indicates the access allowed for this particular rule. "Allow" means traffic matching this rule will be allowed. "Deny" means traffic matching this rule will be blocked. "AlwaysAllow" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs.') + access: 'Allow' | 'AlwaysAllow' | 'Deny' + + @sys.description('Optional. A description of the rule.') + description: string? + + @sys.description('Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535.') + destinationPortRanges: destinationPortRangesType? + + @sys.description('Optional. The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted.') + destinations: destinationsType? + + @sys.description('Required. Indicates if the traffic matched against the rule in inbound or outbound.') + direction: 'Inbound' | 'Outbound' + + @minValue(1) + @maxValue(4096) + @sys.description('Required. The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule.') + priority: int + + @sys.description('Required. Network protocol this rule applies to.') + protocol: 'Ah' | 'Any' | 'Esp' | 'Icmp' | 'Tcp' | 'Udp' + + @sys.description('Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535.') + sourcePortRanges: sourcePortRangesType? + + @sys.description('Optional. The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted.') + sources: sourcesType? +}[]? diff --git a/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/main.json b/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/main.json new file mode 100644 index 000000000..26a7fd816 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/main.json @@ -0,0 +1,621 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "17868772067986931575" + }, + "name": "Network Manager Security Admin Configuration Rule Collections", + "description": "This module deploys an Network Manager Security Admin Configuration Rule Collection.\nA security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail." + }, + "definitions": { + "appliesToGroupsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "networkGroupResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the network group." + } + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "rulesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the rule." + } + }, + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "AlwaysAllow", + "Deny" + ], + "metadata": { + "description": "Required. Indicates the access allowed for this particular rule. \"Allow\" means traffic matching this rule will be allowed. \"Deny\" means traffic matching this rule will be blocked. \"AlwaysAllow\" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "destinationPortRanges": { + "$ref": "#/definitions/destinationPortRangesType", + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "destinations": { + "$ref": "#/definitions/destinationsType", + "nullable": true, + "metadata": { + "description": "Optional. The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. Indicates if the traffic matched against the rule in inbound or outbound." + } + }, + "priority": { + "type": "int", + "minValue": 1, + "maxValue": 4096, + "metadata": { + "description": "Required. The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Ah", + "Any", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourcePortRanges": { + "$ref": "#/definitions/sourcePortRangesType", + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "sources": { + "$ref": "#/definitions/sourcesType", + "nullable": true, + "metadata": { + "description": "Optional. The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "destinationPortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + }, + "destinationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + }, + "sourcePortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + }, + "sourcesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "rule/main.bicep" + } + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "securityAdminConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent security admin configuration. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the admin rule collection." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the admin rule collection." + } + }, + "appliesToGroups": { + "$ref": "#/definitions/appliesToGroupsType", + "metadata": { + "description": "Required. List of network groups for configuration. An admin rule collection must be associated to at least one network group." + } + }, + "rules": { + "$ref": "#/definitions/rulesType", + "metadata": { + "description": "Optional. List of rules for the admin rules collection. Security admin rules allows enforcing security policy criteria that matches the conditions set. Warning: A rule collection without rule will cause a deployment configuration for security admin goal state in network manager to fail." + } + } + }, + "resources": { + "networkManager::securityAdminConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "ruleCollection": { + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "appliesToGroups": "[map(parameters('appliesToGroups'), lambda('group', createObject('networkGroupId', lambdaVariables('group').networkGroupResourceId)))]" + } + }, + "ruleCollection_rules": { + "copy": { + "name": "ruleCollection_rules", + "count": "[length(coalesce(parameters('rules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-RuleCollections-Rules-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkManagerName": { + "value": "[parameters('networkManagerName')]" + }, + "securityAdminConfigurationName": { + "value": "[parameters('securityAdminConfigurationName')]" + }, + "ruleCollectionName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].name]" + }, + "access": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].access]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'description')]" + }, + "destinationPortRanges": { + "value": "[coalesce(tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'destinationPortRanges'), createArray())]" + }, + "destinations": { + "value": "[coalesce(tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'destinations'), createArray())]" + }, + "direction": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].direction]" + }, + "priority": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].priority]" + }, + "protocol": { + "value": "[coalesce(parameters('rules'), createArray())[copyIndex()].protocol]" + }, + "sourcePortRanges": { + "value": "[coalesce(tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'sourcePortRanges'), createArray())]" + }, + "sources": { + "value": "[coalesce(tryGet(coalesce(parameters('rules'), createArray())[copyIndex()], 'sources'), createArray())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3195100427454268317" + }, + "name": "Network Manager Security Admin Configuration Rule Collection Rules", + "description": "This module deploys an Azure Virtual Network Manager (AVNM) Security Admin Configuration Rule Collection Rule.\nA security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules." + }, + "definitions": { + "destinationPortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "destinationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "sourcePortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "sourcesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "securityAdminConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent security admin configuration. Required if the template is used in a standalone deployment." + } + }, + "ruleCollectionName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent rule collection. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "AlwaysAllow", + "Deny" + ], + "metadata": { + "description": "Required. Indicates the access allowed for this particular rule. \"Allow\" means traffic matching this rule will be allowed. \"Deny\" means traffic matching this rule will be blocked. \"AlwaysAllow\" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs." + } + }, + "destinationPortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "destinations": { + "$ref": "#/definitions/destinationsType", + "metadata": { + "description": "Optional. The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. Indicates if the traffic matched against the rule in inbound or outbound." + } + }, + "priority": { + "type": "int", + "minValue": 1, + "maxValue": 4096, + "metadata": { + "description": "Required. The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Ah", + "Any", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourcePortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "sources": { + "$ref": "#/definitions/sourcesType", + "metadata": { + "description": "Optional. The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + } + }, + "resources": { + "networkManager::securityAdminConfiguration::ruleCollection": { + "existing": true, + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('ruleCollectionName'))]" + }, + "networkManager::securityAdminConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "rule": { + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]", + "kind": "Custom", + "properties": { + "access": "[parameters('access')]", + "description": "[parameters('description')]", + "destinationPortRanges": "[parameters('destinationPortRanges')]", + "destinations": "[parameters('destinations')]", + "direction": "[parameters('direction')]", + "priority": "[parameters('priority')]", + "protocol": "[parameters('protocol')]", + "sourcePortRanges": "[parameters('sourcePortRanges')]", + "sources": "[parameters('sources')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed rule." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "ruleCollection" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed admin rule collection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed admin rule collection." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the admin rule collection was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/rule/README.md b/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/rule/README.md new file mode 100644 index 000000000..280bf5c7d --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/rule/README.md @@ -0,0 +1,256 @@ +# Network Manager Security Admin Configuration Rule Collection Rules `[Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules]` + +This module deploys an Azure Virtual Network Manager (AVNM) Security Admin Configuration Rule Collection Rule. +A security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkManagers/securityAdminConfigurations/ruleCollections/rules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`access`](#parameter-access) | string | Indicates the access allowed for this particular rule. "Allow" means traffic matching this rule will be allowed. "Deny" means traffic matching this rule will be blocked. "AlwaysAllow" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs. | +| [`direction`](#parameter-direction) | string | Indicates if the traffic matched against the rule in inbound or outbound. | +| [`name`](#parameter-name) | string | The name of the rule. | +| [`priority`](#parameter-priority) | int | The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule. | +| [`protocol`](#parameter-protocol) | string | Network protocol this rule applies to. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`networkManagerName`](#parameter-networkmanagername) | string | The name of the parent network manager. Required if the template is used in a standalone deployment. | +| [`ruleCollectionName`](#parameter-rulecollectionname) | string | The name of the parent rule collection. Required if the template is used in a standalone deployment. | +| [`securityAdminConfigurationName`](#parameter-securityadminconfigurationname) | string | The name of the parent security admin configuration. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-description) | string | A description of the rule. | +| [`destinationPortRanges`](#parameter-destinationportranges) | array | List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. | +| [`destinations`](#parameter-destinations) | array | The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. | +| [`sourcePortRanges`](#parameter-sourceportranges) | array | List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. | +| [`sources`](#parameter-sources) | array | The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. | + +### Parameter: `access` + +Indicates the access allowed for this particular rule. "Allow" means traffic matching this rule will be allowed. "Deny" means traffic matching this rule will be blocked. "AlwaysAllow" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Allow' + 'AlwaysAllow' + 'Deny' + ] + ``` + +### Parameter: `direction` + +Indicates if the traffic matched against the rule in inbound or outbound. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Inbound' + 'Outbound' + ] + ``` + +### Parameter: `name` + +The name of the rule. + +- Required: Yes +- Type: string + +### Parameter: `priority` + +The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule. + +- Required: Yes +- Type: int +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `protocol` + +Network protocol this rule applies to. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Ah' + 'Any' + 'Esp' + 'Icmp' + 'Tcp' + 'Udp' + ] + ``` +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `networkManagerName` + +The name of the parent network manager. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `ruleCollectionName` + +The name of the parent rule collection. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `securityAdminConfigurationName` + +The name of the parent security admin configuration. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `description` + +A description of the rule. + +- Required: No +- Type: string +- Default: `''` +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `destinationPortRanges` + +List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `destinations` + +The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefix`](#parameter-destinationsaddressprefix) | string | Address prefix. | +| [`addressPrefixType`](#parameter-destinationsaddressprefixtype) | string | Address prefix type. | + +### Parameter: `destinations.addressPrefix` + +Address prefix. + +- Required: Yes +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `destinations.addressPrefixType` + +Address prefix type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'IPPrefix' + 'ServiceTag' + ] + ``` +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `sourcePortRanges` + +List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `sources` + +The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 4096 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefix`](#parameter-sourcesaddressprefix) | string | Address prefix. | +| [`addressPrefixType`](#parameter-sourcesaddressprefixtype) | string | Address prefix type. | + +### Parameter: `sources.addressPrefix` + +Address prefix. + +- Required: Yes +- Type: string +- MinValue: 1 +- MaxValue: 4096 + +### Parameter: `sources.addressPrefixType` + +Address prefix type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'IPPrefix' + 'ServiceTag' + ] + ``` +- MinValue: 1 +- MaxValue: 4096 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed rule. | +| `resourceGroupName` | string | The resource group the rule was deployed into. | +| `resourceId` | string | The resource ID of the deployed rule. | diff --git a/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/rule/main.bicep b/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/rule/main.bicep new file mode 100644 index 000000000..e7b8f95fa --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/rule/main.bicep @@ -0,0 +1,129 @@ +metadata name = 'Network Manager Security Admin Configuration Rule Collection Rules' +metadata description = '''This module deploys an Azure Virtual Network Manager (AVNM) Security Admin Configuration Rule Collection Rule. +A security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules.''' + +@sys.description('Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment.') +param networkManagerName string + +@sys.description('Conditional. The name of the parent security admin configuration. Required if the template is used in a standalone deployment.') +param securityAdminConfigurationName string + +@sys.description('Conditional. The name of the parent rule collection. Required if the template is used in a standalone deployment.') +param ruleCollectionName string + +@maxLength(64) +@sys.description('Required. The name of the rule.') +param name string + +@maxLength(500) +@sys.description('Optional. A description of the rule.') +param description string = '' + +@allowed([ + 'Allow' + 'AlwaysAllow' + 'Deny' +]) +@sys.description('Required. Indicates the access allowed for this particular rule. "Allow" means traffic matching this rule will be allowed. "Deny" means traffic matching this rule will be blocked. "AlwaysAllow" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs.') +param access string + +@sys.description('Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535.') +param destinationPortRanges string[]? + +@sys.description('Optional. The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted.') +param destinations destinationsType + +@allowed([ + 'Inbound' + 'Outbound' +]) +@sys.description('Required. Indicates if the traffic matched against the rule in inbound or outbound.') +param direction string + +@minValue(1) +@maxValue(4096) +@sys.description('Required. The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule.') +param priority int + +@allowed([ + 'Ah' + 'Any' + 'Esp' + 'Icmp' + 'Tcp' + 'Udp' +]) +@sys.description('Required. Network protocol this rule applies to.') +param protocol string + +@sys.description('Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535.') +param sourcePortRanges string[]? + +@sys.description('Optional. The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted.') +param sources sourcesType + +resource networkManager 'Microsoft.Network/networkManagers@2024-05-01' existing = { + name: networkManagerName + + resource securityAdminConfiguration 'securityAdminConfigurations' existing = { + name: securityAdminConfigurationName + + resource ruleCollection 'ruleCollections' existing = { + name: ruleCollectionName + } + } +} + +resource rule 'Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules@2024-05-01' = { + name: name + parent: networkManager::securityAdminConfiguration::ruleCollection + kind: 'Custom' + properties: { + access: access + description: description + destinationPortRanges: destinationPortRanges + destinations: destinations + direction: direction + priority: priority + protocol: protocol + sourcePortRanges: sourcePortRanges + sources: sources + } +} + +@sys.description('The name of the deployed rule.') +output name string = rule.name + +@sys.description('The resource ID of the deployed rule.') +output resourceId string = rule.id + +@sys.description('The resource group the rule was deployed into.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +@export() +type destinationPortRangesType = string[]? + +@export() +type destinationsType = { + @sys.description('Required. Address prefix type.') + addressPrefixType: 'IPPrefix' | 'ServiceTag' + + @sys.description('Required. Address prefix.') + addressPrefix: string +}[]? + +@export() +type sourcePortRangesType = string[]? + +@export() +type sourcesType = { + @sys.description('Required. Address prefix type.') + addressPrefixType: 'IPPrefix' | 'ServiceTag' + + @sys.description('Required. Address prefix.') + addressPrefix: string +}[]? diff --git a/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/rule/main.json b/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/rule/main.json new file mode 100644 index 000000000..a91a17310 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/security-admin-configuration/rule-collection/rule/main.json @@ -0,0 +1,262 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "3195100427454268317" + }, + "name": "Network Manager Security Admin Configuration Rule Collection Rules", + "description": "This module deploys an Azure Virtual Network Manager (AVNM) Security Admin Configuration Rule Collection Rule.\nA security admin configuration contains a set of rule collections. Each rule collection contains one or more security admin rules." + }, + "definitions": { + "destinationPortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "destinationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "sourcePortRangesType": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + }, + "sourcesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixType": { + "type": "string", + "allowedValues": [ + "IPPrefix", + "ServiceTag" + ], + "metadata": { + "description": "Required. Address prefix type." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address prefix." + } + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "networkManagerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network manager. Required if the template is used in a standalone deployment." + } + }, + "securityAdminConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent security admin configuration. Required if the template is used in a standalone deployment." + } + }, + "ruleCollectionName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent rule collection. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. The name of the rule." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 500, + "metadata": { + "description": "Optional. A description of the rule." + } + }, + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "AlwaysAllow", + "Deny" + ], + "metadata": { + "description": "Required. Indicates the access allowed for this particular rule. \"Allow\" means traffic matching this rule will be allowed. \"Deny\" means traffic matching this rule will be blocked. \"AlwaysAllow\" means that traffic matching this rule will be allowed regardless of other rules with lower priority or user-defined NSGs." + } + }, + "destinationPortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "destinations": { + "$ref": "#/definitions/destinationsType", + "metadata": { + "description": "Optional. The destnations filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. Indicates if the traffic matched against the rule in inbound or outbound." + } + }, + "priority": { + "type": "int", + "minValue": 1, + "maxValue": 4096, + "metadata": { + "description": "Required. The priority of the rule. The value can be between 1 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "Ah", + "Any", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourcePortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535." + } + }, + "sources": { + "$ref": "#/definitions/sourcesType", + "metadata": { + "description": "Optional. The source filter can be an IP Address or a service tag. Each filter contains the properties AddressPrefixType (IPPrefix or ServiceTag) and AddressPrefix (using CIDR notation (e.g. 192.168.99.0/24 or 2001:1234::/64) or a service tag (e.g. AppService.WestEurope)). Combining CIDR and Service tags in one rule filter is not permitted." + } + } + }, + "resources": { + "networkManager::securityAdminConfiguration::ruleCollection": { + "existing": true, + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('ruleCollectionName'))]" + }, + "networkManager::securityAdminConfiguration": { + "existing": true, + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'))]" + }, + "networkManager": { + "existing": true, + "type": "Microsoft.Network/networkManagers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkManagerName')]" + }, + "rule": { + "type": "Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]", + "kind": "Custom", + "properties": { + "access": "[parameters('access')]", + "description": "[parameters('description')]", + "destinationPortRanges": "[parameters('destinationPortRanges')]", + "destinations": "[parameters('destinations')]", + "direction": "[parameters('direction')]", + "priority": "[parameters('priority')]", + "protocol": "[parameters('protocol')]", + "sourcePortRanges": "[parameters('sourcePortRanges')]", + "sources": "[parameters('sources')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed rule." + }, + "value": "[resourceId('Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules', parameters('networkManagerName'), parameters('securityAdminConfigurationName'), parameters('ruleCollectionName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-manager/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/network-manager/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..2137e9896 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,53 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.networkmanagers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnmmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + networkManagerScopes: { + subscriptions: [ + subscription().id + ] + } + } + } +] diff --git a/avm/1.1.0/res/network/network-manager/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/network-manager/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..109c4210d --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/tests/e2e/max/dependencies.bicep @@ -0,0 +1,129 @@ +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Hub Virtual Network to create.') +param virtualNetworkHubName string + +@description('Required. The name of the Spoke 1 Virtual Network to create.') +param virtualNetworkSpoke1Name string + +@description('Required. The name of the Spoke 2 Virtual Network to create.') +param virtualNetworkSpoke2Name string + +@description('Required. The name of the Spoke 3 Virtual Network to create.') +param virtualNetworkSpoke3Name string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +var addressPrefixHub = '10.0.0.0/16' +var addressPrefixSpoke1 = '172.16.0.0/12' +var addressPrefixSpoke2 = '192.168.0.0/24' +var addressPrefixSpoke3 = '192.168.1.0/24' +var subnetName = 'defaultSubnet' + +resource virtualNetworkHub 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkHubName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefixHub + ] + } + subnets: [ + { + name: subnetName + properties: { + addressPrefix: addressPrefixHub + } + } + ] + } +} + +resource virtualNetworkSpoke1 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkSpoke1Name + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefixSpoke1 + ] + } + subnets: [ + { + name: subnetName + properties: { + addressPrefix: addressPrefixSpoke1 + } + } + ] + } +} + +resource virtualNetworkSpoke2 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkSpoke2Name + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefixSpoke2 + ] + } + subnets: [ + { + name: subnetName + properties: { + addressPrefix: addressPrefixSpoke2 + } + } + ] + } +} + +resource virtualNetworkSpoke3 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkSpoke3Name + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefixSpoke3 + ] + } + subnets: [ + { + name: subnetName + properties: { + addressPrefix: addressPrefixSpoke3 + } + } + ] + } +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Hub Virtual Network.') +output virtualNetworkHubId string = virtualNetworkHub.id + +@description('The resource ID of the created Spoke 1 Virtual Network.') +output virtualNetworkSpoke1Id string = virtualNetworkSpoke1.id + +@description('The resource ID of the created Spoke 1 Virtual Network subnet.') +output virtualNetworkSpoke1SubnetId string = virtualNetworkSpoke1.properties.subnets[0].id + +@description('The resource ID of the created Spoke 2 Virtual Network.') +output virtualNetworkSpoke2Id string = virtualNetworkSpoke2.id + +@description('The resource ID of the created Spoke 2 Virtual Network subnet.') +output virtualNetworkSpoke2SubnetId string = virtualNetworkSpoke2.properties.subnets[0].id + +@description('The resource ID of the created Spoke 3 Virtual Network.') +output virtualNetworkSpoke3Id string = virtualNetworkSpoke3.id diff --git a/avm/1.1.0/res/network/network-manager/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/network-manager/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..af3866209 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/tests/e2e/max/main.test.bicep @@ -0,0 +1,372 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.networkmanagers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnmmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + virtualNetworkHubName: 'dep-${namePrefix}-vnetHub-${serviceShort}' + virtualNetworkSpoke1Name: 'dep-${namePrefix}-vnetSpoke1-${serviceShort}' + virtualNetworkSpoke2Name: 'dep-${namePrefix}-vnetSpoke2-${serviceShort}' + virtualNetworkSpoke3Name: 'dep-${namePrefix}-vnetSpoke3-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +var networkManagerName = '${namePrefix}${serviceShort}001' +var networkManagerExpecetedResourceID = '${resourceGroup.id}/providers/Microsoft.Network/networkManagers/${networkManagerName}' + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: networkManagerName + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'e8472331-308c-4c77-aa31-017279d8e5b6' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + networkManagerScopeAccesses: [ + 'Connectivity' + 'SecurityAdmin' + 'Routing' + ] + networkManagerScopes: { + managementGroups: [ + // Note: Required the `Microsoft.Network` provider to be registered at management group level via `az provider register --namespace Microsoft.Network -m ''` + '/providers/Microsoft.Management/managementGroups/#_managementGroupId_#' + ] + } + networkGroups: [ + { + name: 'network-group-spokes-1' + description: 'network-group-spokes description' + memberType: 'VirtualNetwork' + staticMembers: [ + { + name: 'virtualNetworkSpoke1' + resourceId: nestedDependencies.outputs.virtualNetworkSpoke1Id + } + { + name: 'virtualNetworkSpoke2' + resourceId: nestedDependencies.outputs.virtualNetworkSpoke2Id + } + ] + } + { + name: 'network-group-spokes-2' + memberType: 'VirtualNetwork' + staticMembers: [ + { + name: 'default' + resourceId: nestedDependencies.outputs.virtualNetworkSpoke3Id + } + ] + } + { + name: 'network-group-spokes-3' + memberType: 'VirtualNetwork' + } + { + name: 'network-groups-subnets-1' + memberType: 'Subnet' + staticMembers: [ + { + name: 'virtualNetworkSpoke1-defaultSubnet' + resourceId: nestedDependencies.outputs.virtualNetworkSpoke1SubnetId + } + { + name: 'virtualNetworkSpoke2-defaultSubnet' + resourceId: nestedDependencies.outputs.virtualNetworkSpoke2SubnetId + } + ] + } + ] + connectivityConfigurations: [ + { + name: 'hubSpokeConnectivity' + description: 'hubSpokeConnectivity description' + connectivityTopology: 'HubAndSpoke' + hubs: [ + { + resourceId: nestedDependencies.outputs.virtualNetworkHubId + resourceType: 'Microsoft.Network/virtualNetworks' + } + ] + deleteExistingPeering: true + isGlobal: false + appliesToGroups: [ + { + networkGroupResourceId: '${networkManagerExpecetedResourceID}/networkGroups/network-group-spokes-1' + useHubGateway: false + groupConnectivity: 'None' + isGlobal: false + } + ] + } + { + name: 'MeshConnectivity-1' + description: 'MeshConnectivity description' + connectivityTopology: 'Mesh' + deleteExistingPeering: true + isGlobal: true + appliesToGroups: [ + { + networkGroupResourceId: '${networkManagerExpecetedResourceID}/networkGroups/network-group-spokes-3' + useHubGateway: false + groupConnectivity: 'DirectlyConnected' + isGlobal: true + } + ] + } + { + name: 'MeshConnectivity-2' + connectivityTopology: 'Mesh' + appliesToGroups: [ + { + networkGroupResourceId: '${networkManagerExpecetedResourceID}/networkGroups/network-group-spokes-2' + useHubGateway: false + groupConnectivity: 'DirectlyConnected' + isGlobal: false + } + ] + isGlobal: false + } + ] + scopeConnections: [ + { + name: 'scope-connection-test' + description: 'description of the scope connection' + resourceId: subscription().id + tenantId: tenant().tenantId + } + ] + securityAdminConfigurations: [ + { + name: 'test-security-admin-config-1' + description: 'description of the security admin config' + applyOnNetworkIntentPolicyBasedServices: [ + 'AllowRulesOnly' + ] + ruleCollections: [ + { + name: 'test-rule-collection-1' + description: 'test-rule-collection-description' + appliesToGroups: [ + { + networkGroupResourceId: '${networkManagerExpecetedResourceID}/networkGroups/network-group-spokes-1' + } + ] + rules: [ + { + name: 'test-inbound-allow-rule-1' + description: 'test-inbound-allow-rule-1-description' + access: 'Allow' + direction: 'Inbound' + priority: 150 + protocol: 'Tcp' + } + { + name: 'test-outbound-deny-rule-2' + description: 'test-outbound-deny-rule-2-description' + access: 'Deny' + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourcePortRanges: [ + '80' + '442-445' + ] + sources: [ + { + addressPrefix: 'AppService.WestEurope' + addressPrefixType: 'ServiceTag' + } + ] + } + ] + } + { + name: 'test-rule-collection-2' + appliesToGroups: [ + { + networkGroupResourceId: '${networkManagerExpecetedResourceID}/networkGroups/network-group-spokes-2' + } + { + networkGroupResourceId: '${networkManagerExpecetedResourceID}/networkGroups/network-group-spokes-3' + } + ] + rules: [ + { + name: 'test-inbound-allow-rule-3' + access: 'Allow' + direction: 'Inbound' + destinationPortRanges: [ + '80' + '442-445' + ] + destinations: [ + { + addressPrefix: '192.168.20.20' + addressPrefixType: 'IPPrefix' + } + ] + priority: 250 + protocol: 'Tcp' + } + { + name: 'test-inbound-allow-rule-4' + description: 'test-inbound-allow-rule-4-description' + access: 'Allow' + direction: 'Inbound' + sources: [ + { + addressPrefix: '10.0.0.0/24' + addressPrefixType: 'IPPrefix' + } + { + addressPrefix: '100.100.100.100' + addressPrefixType: 'IPPrefix' + } + ] + destinations: [ + { + addressPrefix: '172.16.0.0/24' + addressPrefixType: 'IPPrefix' + } + { + addressPrefix: '172.16.1.0/24' + addressPrefixType: 'IPPrefix' + } + ] + priority: 260 + protocol: 'Tcp' + } + ] + } + ] + } + ] + routingConfigurations: [ + { + name: 'test-routing-config-1' + description: 'description of the routing config' + } + { + name: 'test-routing-config-2' + ruleCollections: [ + { + name: 'test-routing-rule-collection-1-subnet' + appliesTo: [ + { + networkGroupResourceId: '${networkManagerExpecetedResourceID}/networkGroups/network-groups-subnets-1' + } + ] + disableBgpRoutePropagation: false + rules: [ + { + name: 'test-routing-rule-1' + destination: { + destinationAddress: 'AzureCloud' + type: 'ServiceTag' + } + nextHop: { + nextHopType: 'VnetLocal' + } + } + { + name: 'test-routing-rule-2' + destination: { + destinationAddress: '10.10.10.10/32' + type: 'AddressPrefix' + } + nextHop: { + nextHopType: 'VirtualAppliance' + nextHopAddress: '192.168.1.1' + } + } + ] + } + ] + } + { + name: 'test-routing-config-3' + ruleCollections: [ + { + name: 'test-routing-rule-collection-2-virtual-network' + appliesTo: [ + { + networkGroupResourceId: '${networkManagerExpecetedResourceID}/networkGroups/network-group-spokes-1' + } + ] + } + ] + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/network-manager/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/network-manager/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..1d025f410 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,61 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.networkmanagers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnmwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + networkManagerScopeAccesses: [ + 'SecurityAdmin' + ] + networkManagerScopes: { + subscriptions: [ + subscription().id + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/network-manager/version.json b/avm/1.1.0/res/network/network-manager/version.json new file mode 100644 index 000000000..04a0dd1a8 --- /dev/null +++ b/avm/1.1.0/res/network/network-manager/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/res/network/network-security-group/README.md b/avm/1.1.0/res/network/network-security-group/README.md new file mode 100644 index 000000000..cf086b177 --- /dev/null +++ b/avm/1.1.0/res/network/network-security-group/README.md @@ -0,0 +1,1218 @@ +# Network Security Groups `[Microsoft.Network/networkSecurityGroups]` + +This module deploys a Network security Group (NSG). + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/networkSecurityGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/networkSecurityGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/network-security-group:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module networkSecurityGroup 'br/public:avm/res/network/network-security-group:' = { + name: 'networkSecurityGroupDeployment' + params: { + // Required parameters + name: 'nnsgmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nnsgmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-security-group:' + +// Required parameters +param name = 'nnsgmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module networkSecurityGroup 'br/public:avm/res/network/network-security-group:' = { + name: 'networkSecurityGroupDeployment' + params: { + // Required parameters + name: 'nnsgmax001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'b6d38ee8-4058-42b1-af6a-b8d585cf61ef' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + securityRules: [ + { + name: 'Specific' + properties: { + access: 'Allow' + description: 'Tests specific IPs and ports' + destinationAddressPrefix: '*' + destinationPortRange: '8080' + direction: 'Inbound' + priority: 100 + protocol: '*' + sourceAddressPrefix: '*' + sourcePortRange: '*' + } + } + { + name: 'Ranges' + properties: { + access: 'Allow' + description: 'Tests Ranges' + destinationAddressPrefixes: [ + '10.2.0.0/16' + '10.3.0.0/16' + ] + destinationPortRanges: [ + '90' + '91' + ] + direction: 'Inbound' + priority: 101 + protocol: '*' + sourceAddressPrefixes: [ + '10.0.0.0/16' + '10.1.0.0/16' + ] + sourcePortRanges: [ + '80' + '81' + ] + } + } + { + name: 'Port_8082' + properties: { + access: 'Allow' + description: 'Allow inbound access on TCP 8082' + destinationApplicationSecurityGroupResourceIds: [ + '' + ] + destinationPortRange: '8082' + direction: 'Inbound' + priority: 102 + protocol: '*' + sourceApplicationSecurityGroupResourceIds: [ + '' + ] + sourcePortRange: '*' + } + } + { + name: 'Deny-All-Inbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRange: '*' + direction: 'Inbound' + priority: 4095 + protocol: '*' + sourceAddressPrefix: '*' + sourcePortRange: '*' + } + } + { + name: 'Allow-AzureCloud-Tcp' + properties: { + access: 'Allow' + destinationAddressPrefix: 'AzureCloud' + destinationPortRange: '443' + direction: 'Outbound' + priority: 250 + protocol: 'Tcp' + sourceAddressPrefixes: [ + '10.10.10.0/24' + '192.168.1.0/24' + ] + sourcePortRange: '*' + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nnsgmax001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "b6d38ee8-4058-42b1-af6a-b8d585cf61ef", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "securityRules": { + "value": [ + { + "name": "Specific", + "properties": { + "access": "Allow", + "description": "Tests specific IPs and ports", + "destinationAddressPrefix": "*", + "destinationPortRange": "8080", + "direction": "Inbound", + "priority": 100, + "protocol": "*", + "sourceAddressPrefix": "*", + "sourcePortRange": "*" + } + }, + { + "name": "Ranges", + "properties": { + "access": "Allow", + "description": "Tests Ranges", + "destinationAddressPrefixes": [ + "10.2.0.0/16", + "10.3.0.0/16" + ], + "destinationPortRanges": [ + "90", + "91" + ], + "direction": "Inbound", + "priority": 101, + "protocol": "*", + "sourceAddressPrefixes": [ + "10.0.0.0/16", + "10.1.0.0/16" + ], + "sourcePortRanges": [ + "80", + "81" + ] + } + }, + { + "name": "Port_8082", + "properties": { + "access": "Allow", + "description": "Allow inbound access on TCP 8082", + "destinationApplicationSecurityGroupResourceIds": [ + "" + ], + "destinationPortRange": "8082", + "direction": "Inbound", + "priority": 102, + "protocol": "*", + "sourceApplicationSecurityGroupResourceIds": [ + "" + ], + "sourcePortRange": "*" + } + }, + { + "name": "Deny-All-Inbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRange": "*", + "direction": "Inbound", + "priority": 4095, + "protocol": "*", + "sourceAddressPrefix": "*", + "sourcePortRange": "*" + } + }, + { + "name": "Allow-AzureCloud-Tcp", + "properties": { + "access": "Allow", + "destinationAddressPrefix": "AzureCloud", + "destinationPortRange": "443", + "direction": "Outbound", + "priority": 250, + "protocol": "Tcp", + "sourceAddressPrefixes": [ + "10.10.10.0/24", + "192.168.1.0/24" + ], + "sourcePortRange": "*" + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-security-group:' + +// Required parameters +param name = 'nnsgmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'b6d38ee8-4058-42b1-af6a-b8d585cf61ef' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param securityRules = [ + { + name: 'Specific' + properties: { + access: 'Allow' + description: 'Tests specific IPs and ports' + destinationAddressPrefix: '*' + destinationPortRange: '8080' + direction: 'Inbound' + priority: 100 + protocol: '*' + sourceAddressPrefix: '*' + sourcePortRange: '*' + } + } + { + name: 'Ranges' + properties: { + access: 'Allow' + description: 'Tests Ranges' + destinationAddressPrefixes: [ + '10.2.0.0/16' + '10.3.0.0/16' + ] + destinationPortRanges: [ + '90' + '91' + ] + direction: 'Inbound' + priority: 101 + protocol: '*' + sourceAddressPrefixes: [ + '10.0.0.0/16' + '10.1.0.0/16' + ] + sourcePortRanges: [ + '80' + '81' + ] + } + } + { + name: 'Port_8082' + properties: { + access: 'Allow' + description: 'Allow inbound access on TCP 8082' + destinationApplicationSecurityGroupResourceIds: [ + '' + ] + destinationPortRange: '8082' + direction: 'Inbound' + priority: 102 + protocol: '*' + sourceApplicationSecurityGroupResourceIds: [ + '' + ] + sourcePortRange: '*' + } + } + { + name: 'Deny-All-Inbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRange: '*' + direction: 'Inbound' + priority: 4095 + protocol: '*' + sourceAddressPrefix: '*' + sourcePortRange: '*' + } + } + { + name: 'Allow-AzureCloud-Tcp' + properties: { + access: 'Allow' + destinationAddressPrefix: 'AzureCloud' + destinationPortRange: '443' + direction: 'Outbound' + priority: 250 + protocol: 'Tcp' + sourceAddressPrefixes: [ + '10.10.10.0/24' + '192.168.1.0/24' + ] + sourcePortRange: '*' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module networkSecurityGroup 'br/public:avm/res/network/network-security-group:' = { + name: 'networkSecurityGroupDeployment' + params: { + // Required parameters + name: 'nnsgwaf001' + // Non-required parameters + location: '' + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: [ + '22' + '3389' + ] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nnsgwaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "securityRules": { + "value": [ + { + "name": "deny-hop-outbound", + "properties": { + "access": "Deny", + "destinationAddressPrefix": "*", + "destinationPortRanges": [ + "22", + "3389" + ], + "direction": "Outbound", + "priority": 200, + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*" + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-security-group:' + +// Required parameters +param name = 'nnsgwaf001' +// Non-required parameters +param location = '' +param securityRules = [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: [ + '22' + '3389' + ] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Network Security Group. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`flushConnection`](#parameter-flushconnection) | bool | When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`securityRules`](#parameter-securityrules) | array | Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed. | +| [`tags`](#parameter-tags) | object | Tags of the NSG resource. | + +### Parameter: `name` + +Name of the Network Security Group. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `flushConnection` + +When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `securityRules` + +Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-securityrulesname) | string | The name of the security rule. | +| [`properties`](#parameter-securityrulesproperties) | object | The properties of the security rule. | + +### Parameter: `securityRules.name` + +The name of the security rule. + +- Required: Yes +- Type: string + +### Parameter: `securityRules.properties` + +The properties of the security rule. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`access`](#parameter-securityrulespropertiesaccess) | string | Whether network traffic is allowed or denied. | +| [`direction`](#parameter-securityrulespropertiesdirection) | string | The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic. | +| [`priority`](#parameter-securityrulespropertiespriority) | int | Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule. | +| [`protocol`](#parameter-securityrulespropertiesprotocol) | string | Network protocol this rule applies to. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-securityrulespropertiesdescription) | string | The description of the security rule. | +| [`destinationAddressPrefix`](#parameter-securityrulespropertiesdestinationaddressprefix) | string | Optional. The destination address prefix. CIDR or destination IP range. Asterisk "*" can also be used to match all source IPs. Default tags such as "VirtualNetwork", "AzureLoadBalancer" and "Internet" can also be used. | +| [`destinationAddressPrefixes`](#parameter-securityrulespropertiesdestinationaddressprefixes) | array | The destination address prefixes. CIDR or destination IP ranges. | +| [`destinationApplicationSecurityGroupResourceIds`](#parameter-securityrulespropertiesdestinationapplicationsecuritygroupresourceids) | array | The resource IDs of the application security groups specified as destination. | +| [`destinationPortRange`](#parameter-securityrulespropertiesdestinationportrange) | string | The destination port or range. Integer or range between 0 and 65535. Asterisk "*" can also be used to match all ports. | +| [`destinationPortRanges`](#parameter-securityrulespropertiesdestinationportranges) | array | The destination port ranges. | +| [`sourceAddressPrefix`](#parameter-securityrulespropertiessourceaddressprefix) | string | The CIDR or source IP range. Asterisk "*" can also be used to match all source IPs. Default tags such as "VirtualNetwork", "AzureLoadBalancer" and "Internet" can also be used. If this is an ingress rule, specifies where network traffic originates from. | +| [`sourceAddressPrefixes`](#parameter-securityrulespropertiessourceaddressprefixes) | array | The CIDR or source IP ranges. | +| [`sourceApplicationSecurityGroupResourceIds`](#parameter-securityrulespropertiessourceapplicationsecuritygroupresourceids) | array | The resource IDs of the application security groups specified as source. | +| [`sourcePortRange`](#parameter-securityrulespropertiessourceportrange) | string | The source port or range. Integer or range between 0 and 65535. Asterisk "*" can also be used to match all ports. | +| [`sourcePortRanges`](#parameter-securityrulespropertiessourceportranges) | array | The source port ranges. | + +### Parameter: `securityRules.properties.access` + +Whether network traffic is allowed or denied. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Allow' + 'Deny' + ] + ``` + +### Parameter: `securityRules.properties.direction` + +The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Inbound' + 'Outbound' + ] + ``` + +### Parameter: `securityRules.properties.priority` + +Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule. + +- Required: Yes +- Type: int +- MinValue: 100 +- MaxValue: 4096 + +### Parameter: `securityRules.properties.protocol` + +Network protocol this rule applies to. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + '*' + 'Ah' + 'Esp' + 'Icmp' + 'Tcp' + 'Udp' + ] + ``` +- MinValue: 100 +- MaxValue: 4096 + +### Parameter: `securityRules.properties.description` + +The description of the security rule. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 4096 + +### Parameter: `securityRules.properties.destinationAddressPrefix` + +Optional. The destination address prefix. CIDR or destination IP range. Asterisk "*" can also be used to match all source IPs. Default tags such as "VirtualNetwork", "AzureLoadBalancer" and "Internet" can also be used. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 4096 + +### Parameter: `securityRules.properties.destinationAddressPrefixes` + +The destination address prefixes. CIDR or destination IP ranges. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 4096 + +### Parameter: `securityRules.properties.destinationApplicationSecurityGroupResourceIds` + +The resource IDs of the application security groups specified as destination. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 4096 + +### Parameter: `securityRules.properties.destinationPortRange` + +The destination port or range. Integer or range between 0 and 65535. Asterisk "*" can also be used to match all ports. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 4096 + +### Parameter: `securityRules.properties.destinationPortRanges` + +The destination port ranges. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 4096 + +### Parameter: `securityRules.properties.sourceAddressPrefix` + +The CIDR or source IP range. Asterisk "*" can also be used to match all source IPs. Default tags such as "VirtualNetwork", "AzureLoadBalancer" and "Internet" can also be used. If this is an ingress rule, specifies where network traffic originates from. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 4096 + +### Parameter: `securityRules.properties.sourceAddressPrefixes` + +The CIDR or source IP ranges. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 4096 + +### Parameter: `securityRules.properties.sourceApplicationSecurityGroupResourceIds` + +The resource IDs of the application security groups specified as source. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 4096 + +### Parameter: `securityRules.properties.sourcePortRange` + +The source port or range. Integer or range between 0 and 65535. Asterisk "*" can also be used to match all ports. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 4096 + +### Parameter: `securityRules.properties.sourcePortRanges` + +The source port ranges. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 4096 + +### Parameter: `tags` + +Tags of the NSG resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the network security group. | +| `resourceGroupName` | string | The resource group the network security group was deployed into. | +| `resourceId` | string | The resource ID of the network security group. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/network-security-group/main.bicep b/avm/1.1.0/res/network/network-security-group/main.bicep new file mode 100644 index 000000000..d87eef556 --- /dev/null +++ b/avm/1.1.0/res/network/network-security-group/main.bicep @@ -0,0 +1,311 @@ +metadata name = 'Network Security Groups' +metadata description = 'This module deploys a Network security Group (NSG).' + +@description('Required. Name of the Network Security Group.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed.') +param securityRules securityRulesType + +@description('Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions.') +param flushConnection bool = false + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the NSG resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-networksecuritygroup.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-11-01' = { + name: name + location: location + tags: tags + properties: { + flushConnection: flushConnection + securityRules: [ + for securityRule in securityRules ?? []: { + name: securityRule.name + properties: { + access: securityRule.properties.access + description: securityRule.properties.?description ?? '' + destinationAddressPrefix: securityRule.properties.?destinationAddressPrefix ?? '' + destinationAddressPrefixes: securityRule.properties.?destinationAddressPrefixes ?? [] + destinationApplicationSecurityGroups: map( + securityRule.properties.?destinationApplicationSecurityGroupResourceIds ?? [], + (destinationApplicationSecurityGroupResourceId) => { + id: destinationApplicationSecurityGroupResourceId + } + ) + destinationPortRange: securityRule.properties.?destinationPortRange ?? '' + destinationPortRanges: securityRule.properties.?destinationPortRanges ?? [] + direction: securityRule.properties.direction + priority: securityRule.properties.priority + protocol: securityRule.properties.protocol + sourceAddressPrefix: securityRule.properties.?sourceAddressPrefix ?? '' + sourceAddressPrefixes: securityRule.properties.?sourceAddressPrefixes ?? [] + sourceApplicationSecurityGroups: map( + securityRule.properties.?sourceApplicationSecurityGroupResourceIds ?? [], + (sourceApplicationSecurityGroupResourceId) => { + id: sourceApplicationSecurityGroupResourceId + } + ) + sourcePortRange: securityRule.properties.?sourcePortRange ?? '' + sourcePortRanges: securityRule.properties.?sourcePortRanges ?? [] + } + } + ] + } +} + +resource networkSecurityGroup_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: networkSecurityGroup +} + +resource networkSecurityGroup_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: networkSecurityGroup + } +] + +resource networkSecurityGroup_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + networkSecurityGroup.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: networkSecurityGroup + } +] + +@description('The resource group the network security group was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the network security group.') +output resourceId string = networkSecurityGroup.id + +@description('The name of the network security group.') +output name string = networkSecurityGroup.name + +@description('The location the resource was deployed into.') +output location string = networkSecurityGroup.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? + +type securityRulesType = { + @description('Required. The name of the security rule.') + name: string + + @description('Required. The properties of the security rule.') + properties: { + @description('Required. Whether network traffic is allowed or denied.') + access: ('Allow' | 'Deny') + + @description('Optional. The description of the security rule.') + description: string? + + @description('Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk "*" can also be used to match all source IPs. Default tags such as "VirtualNetwork", "AzureLoadBalancer" and "Internet" can also be used.') + destinationAddressPrefix: string? + + @description('Optional. The destination address prefixes. CIDR or destination IP ranges.') + destinationAddressPrefixes: string[]? + + @description('Optional. The resource IDs of the application security groups specified as destination.') + destinationApplicationSecurityGroupResourceIds: string[]? + + @description('Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk "*" can also be used to match all ports.') + destinationPortRange: string? + + @description('Optional. The destination port ranges.') + destinationPortRanges: string[]? + + @description('Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic.') + direction: ('Inbound' | 'Outbound') + + @minValue(100) + @maxValue(4096) + @description('Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule.') + priority: int + + @description('Required. Network protocol this rule applies to.') + protocol: ('Ah' | 'Esp' | 'Icmp' | 'Tcp' | 'Udp' | '*') + + @description('Optional. The CIDR or source IP range. Asterisk "*" can also be used to match all source IPs. Default tags such as "VirtualNetwork", "AzureLoadBalancer" and "Internet" can also be used. If this is an ingress rule, specifies where network traffic originates from.') + sourceAddressPrefix: string? + + @description('Optional. The CIDR or source IP ranges.') + sourceAddressPrefixes: string[]? + + @description('Optional. The resource IDs of the application security groups specified as source.') + sourceApplicationSecurityGroupResourceIds: string[]? + + @description('Optional. The source port or range. Integer or range between 0 and 65535. Asterisk "*" can also be used to match all ports.') + sourcePortRange: string? + + @description('Optional. The source port ranges.') + sourcePortRanges: string[]? + } +}[]? diff --git a/avm/1.1.0/res/network/network-security-group/main.json b/avm/1.1.0/res/network/network-security-group/main.json new file mode 100644 index 000000000..dfe4381ac --- /dev/null +++ b/avm/1.1.0/res/network/network-security-group/main.json @@ -0,0 +1,602 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "16084722191408836988" + }, + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG)." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "securityRulesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security rule." + } + }, + "properties": { + "type": "object", + "properties": { + "access": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Required. Whether network traffic is allowed or denied." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the security rule." + } + }, + "destinationAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + } + }, + "destinationApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as destination." + } + }, + "destinationPortRange": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "minValue": 100, + "maxValue": 4096, + "metadata": { + "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of the application security groups specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The source port ranges." + } + } + }, + "metadata": { + "description": "Required. The properties of the security rule." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Network Security Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "securityRules": { + "$ref": "#/definitions/securityRulesType", + "metadata": { + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." + } + }, + "flushConnection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the NSG resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "securityRules", + "count": "[length(coalesce(parameters('securityRules'), createArray()))]", + "input": { + "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", + "properties": { + "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", + "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", + "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", + "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", + "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", + "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", + "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", + "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", + "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", + "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", + "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", + "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", + "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", + "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", + "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" + } + } + } + ], + "flushConnection": "[parameters('flushConnection')]" + } + }, + "networkSecurityGroup_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_roleAssignments": { + "copy": { + "name": "networkSecurityGroup_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network security group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the network security group." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the network security group." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-security-group/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/network-security-group/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..29e1730be --- /dev/null +++ b/avm/1.1.0/res/network/network-security-group/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.networksecuritygroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnsgmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/network/network-security-group/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/network-security-group/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..951c71af9 --- /dev/null +++ b/avm/1.1.0/res/network/network-security-group/tests/e2e/max/dependencies.bicep @@ -0,0 +1,24 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Application Security Group to create.') +param applicationSecurityGroupName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource applicationSecurityGroup 'Microsoft.Network/applicationSecurityGroups@2023-04-01' = { + name: applicationSecurityGroupName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Application Security Group.') +output applicationSecurityGroupResourceId string = applicationSecurityGroup.id diff --git a/avm/1.1.0/res/network/network-security-group/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/network-security-group/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..783e2b4e9 --- /dev/null +++ b/avm/1.1.0/res/network/network-security-group/tests/e2e/max/main.test.bicep @@ -0,0 +1,205 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.networksecuritygroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnsgmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + applicationSecurityGroupName: 'dep-${namePrefix}-asg-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + diagnosticSettings: [ + { + name: 'customSetting' + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'b6d38ee8-4058-42b1-af6a-b8d585cf61ef' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + securityRules: [ + { + name: 'Specific' + properties: { + access: 'Allow' + description: 'Tests specific IPs and ports' + destinationAddressPrefix: '*' + destinationPortRange: '8080' + direction: 'Inbound' + priority: 100 + protocol: '*' + sourceAddressPrefix: '*' + sourcePortRange: '*' + } + } + { + name: 'Ranges' + properties: { + access: 'Allow' + description: 'Tests Ranges' + destinationAddressPrefixes: [ + '10.2.0.0/16' + '10.3.0.0/16' + ] + destinationPortRanges: [ + '90' + '91' + ] + direction: 'Inbound' + priority: 101 + protocol: '*' + sourceAddressPrefixes: [ + '10.0.0.0/16' + '10.1.0.0/16' + ] + sourcePortRanges: [ + '80' + '81' + ] + } + } + { + name: 'Port_8082' + properties: { + access: 'Allow' + description: 'Allow inbound access on TCP 8082' + destinationApplicationSecurityGroupResourceIds: [ + nestedDependencies.outputs.applicationSecurityGroupResourceId + ] + destinationPortRange: '8082' + direction: 'Inbound' + priority: 102 + protocol: '*' + sourceApplicationSecurityGroupResourceIds: [ + nestedDependencies.outputs.applicationSecurityGroupResourceId + ] + sourcePortRange: '*' + } + } + { + name: 'Deny-All-Inbound' + properties: { + access: 'Deny' + direction: 'Inbound' + priority: 4095 + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + } + } + { + name: 'Allow-AzureCloud-Tcp' + properties: { + access: 'Allow' + direction: 'Outbound' + priority: 250 + protocol: 'Tcp' + destinationAddressPrefix: 'AzureCloud' + sourceAddressPrefixes: [ + '10.10.10.0/24' + '192.168.1.0/24' + ] + sourcePortRange: '*' + destinationPortRange: '443' + } + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/network-security-group/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/network-security-group/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..aa50dd135 --- /dev/null +++ b/avm/1.1.0/res/network/network-security-group/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,71 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.networksecuritygroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnsgwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + priority: 200 + access: 'Deny' + protocol: 'Tcp' + direction: 'Outbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRanges: [ + '3389' + '22' + ] + } + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/network-security-group/version.json b/avm/1.1.0/res/network/network-security-group/version.json new file mode 100644 index 000000000..a8eda3102 --- /dev/null +++ b/avm/1.1.0/res/network/network-security-group/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-watcher/README.md b/avm/1.1.0/res/network/network-watcher/README.md new file mode 100644 index 000000000..281e9fc54 --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/README.md @@ -0,0 +1,932 @@ +# Network Watchers `[Microsoft.Network/networkWatchers]` + +This module deploys a Network Watcher. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/networkWatchers` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkWatchers) | +| `Microsoft.Network/networkWatchers/connectionMonitors` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkWatchers/connectionMonitors) | +| `Microsoft.Network/networkWatchers/flowLogs` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkWatchers/flowLogs) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/network-watcher:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module networkWatcher 'br/public:avm/res/network/network-watcher:' = { + name: 'networkWatcherDeployment' + params: { + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-watcher:' + +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module networkWatcher 'br/public:avm/res/network/network-watcher:' = { + name: 'networkWatcherDeployment' + params: { + connectionMonitors: [ + { + endpoints: [ + { + name: '' + resourceId: '' + type: 'AzureVM' + } + { + address: 'www.bing.com' + name: 'Bing' + type: 'ExternalAddress' + } + ] + name: 'nnwmax-cm-001' + testConfigurations: [ + { + httpConfiguration: { + method: 'Get' + port: 80 + preferHTTPS: false + requestHeaders: [] + validStatusCodeRanges: [ + '200' + ] + } + name: 'HTTP Bing Test' + protocol: 'Http' + successThreshold: { + checksFailedPercent: 5 + roundTripTimeMs: 100 + } + testFrequencySec: 30 + } + ] + testGroups: [ + { + destinations: [ + 'Bing' + ] + disable: false + name: 'test-http-Bing' + sources: [ + 'subnet-001()' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: '' + } + ] + flowLogs: [ + { + enabled: false + storageId: '' + targetResourceId: '' + } + { + formatVersion: 1 + name: 'nnwmax-fl-001' + retentionInDays: 8 + storageId: '' + targetResourceId: '' + trafficAnalyticsInterval: 10 + workspaceResourceId: '' + } + ] + location: '' + name: '' + roleAssignments: [ + { + name: 'e8e93fb7-f450-41d5-ae86-a32d34e72578' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "connectionMonitors": { + "value": [ + { + "endpoints": [ + { + "name": "", + "resourceId": "", + "type": "AzureVM" + }, + { + "address": "www.bing.com", + "name": "Bing", + "type": "ExternalAddress" + } + ], + "name": "nnwmax-cm-001", + "testConfigurations": [ + { + "httpConfiguration": { + "method": "Get", + "port": 80, + "preferHTTPS": false, + "requestHeaders": [], + "validStatusCodeRanges": [ + "200" + ] + }, + "name": "HTTP Bing Test", + "protocol": "Http", + "successThreshold": { + "checksFailedPercent": 5, + "roundTripTimeMs": 100 + }, + "testFrequencySec": 30 + } + ], + "testGroups": [ + { + "destinations": [ + "Bing" + ], + "disable": false, + "name": "test-http-Bing", + "sources": [ + "subnet-001()" + ], + "testConfigurations": [ + "HTTP Bing Test" + ] + } + ], + "workspaceResourceId": "" + } + ] + }, + "flowLogs": { + "value": [ + { + "enabled": false, + "storageId": "", + "targetResourceId": "" + }, + { + "formatVersion": 1, + "name": "nnwmax-fl-001", + "retentionInDays": 8, + "storageId": "", + "targetResourceId": "", + "trafficAnalyticsInterval": 10, + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "name": { + "value": "" + }, + "roleAssignments": { + "value": [ + { + "name": "e8e93fb7-f450-41d5-ae86-a32d34e72578", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-watcher:' + +param connectionMonitors = [ + { + endpoints: [ + { + name: '' + resourceId: '' + type: 'AzureVM' + } + { + address: 'www.bing.com' + name: 'Bing' + type: 'ExternalAddress' + } + ] + name: 'nnwmax-cm-001' + testConfigurations: [ + { + httpConfiguration: { + method: 'Get' + port: 80 + preferHTTPS: false + requestHeaders: [] + validStatusCodeRanges: [ + '200' + ] + } + name: 'HTTP Bing Test' + protocol: 'Http' + successThreshold: { + checksFailedPercent: 5 + roundTripTimeMs: 100 + } + testFrequencySec: 30 + } + ] + testGroups: [ + { + destinations: [ + 'Bing' + ] + disable: false + name: 'test-http-Bing' + sources: [ + 'subnet-001()' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: '' + } +] +param flowLogs = [ + { + enabled: false + storageId: '' + targetResourceId: '' + } + { + formatVersion: 1 + name: 'nnwmax-fl-001' + retentionInDays: 8 + storageId: '' + targetResourceId: '' + trafficAnalyticsInterval: 10 + workspaceResourceId: '' + } +] +param location = '' +param name = '' +param roleAssignments = [ + { + name: 'e8e93fb7-f450-41d5-ae86-a32d34e72578' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module networkWatcher 'br/public:avm/res/network/network-watcher:' = { + name: 'networkWatcherDeployment' + params: { + connectionMonitors: [ + { + endpoints: [ + { + name: '' + resourceId: '' + type: 'AzureVM' + } + { + address: 'www.bing.com' + name: 'Bing' + type: 'ExternalAddress' + } + ] + name: 'nnwwaf-cm-001' + testConfigurations: [ + { + httpConfiguration: { + method: 'Get' + port: 80 + preferHTTPS: false + requestHeaders: [] + validStatusCodeRanges: [ + '200' + ] + } + name: 'HTTP Bing Test' + protocol: 'Http' + successThreshold: { + checksFailedPercent: 5 + roundTripTimeMs: 100 + } + testFrequencySec: 30 + } + ] + testGroups: [ + { + destinations: [ + 'Bing' + ] + disable: false + name: 'test-http-Bing' + sources: [ + 'subnet-001()' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: '' + } + ] + flowLogs: [ + { + enabled: false + storageId: '' + targetResourceId: '' + } + { + formatVersion: 1 + name: 'nnwwaf-fl-001' + retentionInDays: 8 + storageId: '' + targetResourceId: '' + trafficAnalyticsInterval: 10 + workspaceResourceId: '' + } + ] + location: '' + name: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "connectionMonitors": { + "value": [ + { + "endpoints": [ + { + "name": "", + "resourceId": "", + "type": "AzureVM" + }, + { + "address": "www.bing.com", + "name": "Bing", + "type": "ExternalAddress" + } + ], + "name": "nnwwaf-cm-001", + "testConfigurations": [ + { + "httpConfiguration": { + "method": "Get", + "port": 80, + "preferHTTPS": false, + "requestHeaders": [], + "validStatusCodeRanges": [ + "200" + ] + }, + "name": "HTTP Bing Test", + "protocol": "Http", + "successThreshold": { + "checksFailedPercent": 5, + "roundTripTimeMs": 100 + }, + "testFrequencySec": 30 + } + ], + "testGroups": [ + { + "destinations": [ + "Bing" + ], + "disable": false, + "name": "test-http-Bing", + "sources": [ + "subnet-001()" + ], + "testConfigurations": [ + "HTTP Bing Test" + ] + } + ], + "workspaceResourceId": "" + } + ] + }, + "flowLogs": { + "value": [ + { + "enabled": false, + "storageId": "", + "targetResourceId": "" + }, + { + "formatVersion": 1, + "name": "nnwwaf-fl-001", + "retentionInDays": 8, + "storageId": "", + "targetResourceId": "", + "trafficAnalyticsInterval": 10, + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "name": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-watcher:' + +param connectionMonitors = [ + { + endpoints: [ + { + name: '' + resourceId: '' + type: 'AzureVM' + } + { + address: 'www.bing.com' + name: 'Bing' + type: 'ExternalAddress' + } + ] + name: 'nnwwaf-cm-001' + testConfigurations: [ + { + httpConfiguration: { + method: 'Get' + port: 80 + preferHTTPS: false + requestHeaders: [] + validStatusCodeRanges: [ + '200' + ] + } + name: 'HTTP Bing Test' + protocol: 'Http' + successThreshold: { + checksFailedPercent: 5 + roundTripTimeMs: 100 + } + testFrequencySec: 30 + } + ] + testGroups: [ + { + destinations: [ + 'Bing' + ] + disable: false + name: 'test-http-Bing' + sources: [ + 'subnet-001()' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: '' + } +] +param flowLogs = [ + { + enabled: false + storageId: '' + targetResourceId: '' + } + { + formatVersion: 1 + name: 'nnwwaf-fl-001' + retentionInDays: 8 + storageId: '' + targetResourceId: '' + trafficAnalyticsInterval: 10 + workspaceResourceId: '' + } +] +param location = '' +param name = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`connectionMonitors`](#parameter-connectionmonitors) | array | Array that contains the Connection Monitors. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`flowLogs`](#parameter-flowlogs) | array | Array that contains the Flow Logs. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`name`](#parameter-name) | string | Name of the Network Watcher resource (hidden). | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `connectionMonitors` + +Array that contains the Connection Monitors. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `flowLogs` + +Array that contains the Flow Logs. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `name` + +Name of the Network Watcher resource (hidden). + +- Required: No +- Type: string +- Default: `[format('NetworkWatcher_{0}', parameters('location'))]` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed network watcher. | +| `resourceGroupName` | string | The resource group the network watcher was deployed into. | +| `resourceId` | string | The resource ID of the deployed network watcher. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/network-watcher/connection-monitor/README.md b/avm/1.1.0/res/network/network-watcher/connection-monitor/README.md new file mode 100644 index 000000000..8a53f28af --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/connection-monitor/README.md @@ -0,0 +1,106 @@ +# Network Watchers Connection Monitors `[Microsoft.Network/networkWatchers/connectionMonitors]` + +This module deploys a Network Watcher Connection Monitor. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkWatchers/connectionMonitors` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkWatchers/connectionMonitors) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the resource. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`endpoints`](#parameter-endpoints) | array | List of connection monitor endpoints. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`networkWatcherName`](#parameter-networkwatchername) | string | Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`testConfigurations`](#parameter-testconfigurations) | array | List of connection monitor test configurations. | +| [`testGroups`](#parameter-testgroups) | array | List of connection monitor test groups. | +| [`workspaceResourceId`](#parameter-workspaceresourceid) | string | Specify the Log Analytics Workspace Resource ID. | + +### Parameter: `name` + +Name of the resource. + +- Required: Yes +- Type: string + +### Parameter: `endpoints` + +List of connection monitor endpoints. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `networkWatcherName` + +Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG. + +- Required: No +- Type: string +- Default: `[format('NetworkWatcher_{0}', resourceGroup().location)]` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `testConfigurations` + +List of connection monitor test configurations. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `testGroups` + +List of connection monitor test groups. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `workspaceResourceId` + +Specify the Log Analytics Workspace Resource ID. + +- Required: No +- Type: string +- Default: `''` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed connection monitor. | +| `resourceGroupName` | string | The resource group the connection monitor was deployed into. | +| `resourceId` | string | The resource ID of the deployed connection monitor. | diff --git a/avm/1.1.0/res/network/network-watcher/connection-monitor/main.bicep b/avm/1.1.0/res/network/network-watcher/connection-monitor/main.bicep new file mode 100644 index 000000000..0d490b300 --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/connection-monitor/main.bicep @@ -0,0 +1,64 @@ +metadata name = 'Network Watchers Connection Monitors' +metadata description = 'This module deploys a Network Watcher Connection Monitor.' + +@description('Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG.') +param networkWatcherName string = 'NetworkWatcher_${resourceGroup().location}' + +@description('Required. Name of the resource.') +param name string + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. List of connection monitor endpoints.') +param endpoints array = [] + +@description('Optional. List of connection monitor test configurations.') +param testConfigurations array = [] + +@description('Optional. List of connection monitor test groups.') +param testGroups array = [] + +@description('Optional. Specify the Log Analytics Workspace Resource ID.') +param workspaceResourceId string = '' + +resource networkWatcher 'Microsoft.Network/networkWatchers@2024-05-01' existing = { + name: networkWatcherName +} + +resource connectionMonitor 'Microsoft.Network/networkWatchers/connectionMonitors@2024-05-01' = { + name: name + parent: networkWatcher + tags: tags + location: location + properties: { + endpoints: endpoints + testConfigurations: testConfigurations + testGroups: testGroups + outputs: !empty(workspaceResourceId) + ? [ + { + type: 'Workspace' + workspaceSettings: { + workspaceResourceId: workspaceResourceId + } + } + ] + : null + } +} + +@description('The name of the deployed connection monitor.') +output name string = connectionMonitor.name + +@description('The resource ID of the deployed connection monitor.') +output resourceId string = connectionMonitor.id + +@description('The resource group the connection monitor was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = connectionMonitor.location diff --git a/avm/1.1.0/res/network/network-watcher/connection-monitor/main.json b/avm/1.1.0/res/network/network-watcher/connection-monitor/main.json new file mode 100644 index 000000000..02aa1b30a --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/connection-monitor/main.json @@ -0,0 +1,122 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "708993782418157673" + }, + "name": "Network Watchers Connection Monitors", + "description": "This module deploys a Network Watcher Connection Monitor." + }, + "parameters": { + "networkWatcherName": { + "type": "string", + "defaultValue": "[format('NetworkWatcher_{0}', resourceGroup().location)]", + "metadata": { + "description": "Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "endpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of connection monitor endpoints." + } + }, + "testConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of connection monitor test configurations." + } + }, + "testGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of connection monitor test groups." + } + }, + "workspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specify the Log Analytics Workspace Resource ID." + } + } + }, + "resources": { + "networkWatcher": { + "existing": true, + "type": "Microsoft.Network/networkWatchers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkWatcherName')]" + }, + "connectionMonitor": { + "type": "Microsoft.Network/networkWatchers/connectionMonitors", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkWatcherName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "endpoints": "[parameters('endpoints')]", + "testConfigurations": "[parameters('testConfigurations')]", + "testGroups": "[parameters('testGroups')]", + "outputs": "[if(not(empty(parameters('workspaceResourceId'))), createArray(createObject('type', 'Workspace', 'workspaceSettings', createObject('workspaceResourceId', parameters('workspaceResourceId')))), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed connection monitor." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed connection monitor." + }, + "value": "[resourceId('Microsoft.Network/networkWatchers/connectionMonitors', parameters('networkWatcherName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the connection monitor was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('connectionMonitor', '2024-05-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-watcher/flow-log/README.md b/avm/1.1.0/res/network/network-watcher/flow-log/README.md new file mode 100644 index 000000000..47bb0ca86 --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/flow-log/README.md @@ -0,0 +1,155 @@ +# NSG Flow Logs `[Microsoft.Network/networkWatchers/flowLogs]` + +This module controls the Network Security Group Flow Logs and analytics settings. +**Note: this module must be run on the Resource Group where Network Watcher is deployed** + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkWatchers/flowLogs` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/networkWatchers/flowLogs) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageId`](#parameter-storageid) | string | Resource ID of the diagnostic storage account. | +| [`targetResourceId`](#parameter-targetresourceid) | string | Resource ID of the NSG that must be enabled for Flow Logs. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-enabled) | bool | If the flow log should be enabled. | +| [`formatVersion`](#parameter-formatversion) | int | The flow log format version. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`name`](#parameter-name) | string | Name of the resource. | +| [`networkWatcherName`](#parameter-networkwatchername) | string | Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG. | +| [`retentionInDays`](#parameter-retentionindays) | int | Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`trafficAnalyticsInterval`](#parameter-trafficanalyticsinterval) | int | The interval in minutes which would decide how frequently TA service should do flow analytics. | +| [`workspaceResourceId`](#parameter-workspaceresourceid) | string | Specify the Log Analytics Workspace Resource ID. | + +### Parameter: `storageId` + +Resource ID of the diagnostic storage account. + +- Required: Yes +- Type: string + +### Parameter: `targetResourceId` + +Resource ID of the NSG that must be enabled for Flow Logs. + +- Required: Yes +- Type: string + +### Parameter: `enabled` + +If the flow log should be enabled. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `formatVersion` + +The flow log format version. + +- Required: No +- Type: int +- Default: `2` +- Allowed: + ```Bicep + [ + 1 + 2 + ] + ``` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `name` + +Name of the resource. + +- Required: No +- Type: string +- Default: `[format('{0}-{1}-flowlog', last(split(parameters('targetResourceId'), '/')), split(parameters('targetResourceId'), '/')[4])]` + +### Parameter: `networkWatcherName` + +Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG. + +- Required: No +- Type: string +- Default: `[format('NetworkWatcher_{0}', resourceGroup().location)]` + +### Parameter: `retentionInDays` + +Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely. + +- Required: No +- Type: int +- Default: `365` +- MinValue: 0 +- MaxValue: 365 + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 365 + +### Parameter: `trafficAnalyticsInterval` + +The interval in minutes which would decide how frequently TA service should do flow analytics. + +- Required: No +- Type: int +- Default: `60` +- Allowed: + ```Bicep + [ + 10 + 60 + ] + ``` +- MinValue: 0 +- MaxValue: 365 + +### Parameter: `workspaceResourceId` + +Specify the Log Analytics Workspace Resource ID. + +- Required: No +- Type: string +- Default: `''` +- MinValue: 0 +- MaxValue: 365 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the flow log. | +| `resourceGroupName` | string | The resource group the flow log was deployed into. | +| `resourceId` | string | The resource ID of the flow log. | diff --git a/avm/1.1.0/res/network/network-watcher/flow-log/main.bicep b/avm/1.1.0/res/network/network-watcher/flow-log/main.bicep new file mode 100644 index 000000000..e5b650b79 --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/flow-log/main.bicep @@ -0,0 +1,96 @@ +metadata name = 'NSG Flow Logs' +metadata description = '''This module controls the Network Security Group Flow Logs and analytics settings. +**Note: this module must be run on the Resource Group where Network Watcher is deployed**''' + +@description('Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG.') +param networkWatcherName string = 'NetworkWatcher_${resourceGroup().location}' + +@description('Optional. Name of the resource.') +param name string = '${last(split(targetResourceId, '/'))}-${split(targetResourceId, '/')[4]}-flowlog' + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Required. Resource ID of the NSG that must be enabled for Flow Logs.') +param targetResourceId string + +@description('Required. Resource ID of the diagnostic storage account.') +param storageId string + +@description('Optional. If the flow log should be enabled.') +param enabled bool = true + +@description('Optional. The flow log format version.') +@allowed([ + 1 + 2 +]) +param formatVersion int = 2 + +@description('Optional. Specify the Log Analytics Workspace Resource ID.') +param workspaceResourceId string = '' + +@description('Optional. The interval in minutes which would decide how frequently TA service should do flow analytics.') +@allowed([ + 10 + 60 +]) +param trafficAnalyticsInterval int = 60 + +@description('Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely.') +@minValue(0) +@maxValue(365) +param retentionInDays int = 365 + +var flowAnalyticsConfiguration = !empty(workspaceResourceId) && enabled == true + ? { + networkWatcherFlowAnalyticsConfiguration: { + enabled: true + workspaceResourceId: workspaceResourceId + trafficAnalyticsInterval: trafficAnalyticsInterval + } + } + : { + networkWatcherFlowAnalyticsConfiguration: { + enabled: false + } + } + +resource networkWatcher 'Microsoft.Network/networkWatchers@2024-05-01' existing = { + name: networkWatcherName +} + +resource flowLog 'Microsoft.Network/networkWatchers/flowLogs@2024-05-01' = { + name: name + parent: networkWatcher + tags: tags + location: location + properties: { + targetResourceId: targetResourceId + storageId: storageId + enabled: enabled + retentionPolicy: { + days: retentionInDays + enabled: retentionInDays == 0 ? false : true + } + format: { + type: 'JSON' + version: formatVersion + } + flowAnalyticsConfiguration: flowAnalyticsConfiguration + } +} +@description('The name of the flow log.') +output name string = flowLog.name + +@description('The resource ID of the flow log.') +output resourceId string = flowLog.id + +@description('The resource group the flow log was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = flowLog.location diff --git a/avm/1.1.0/res/network/network-watcher/flow-log/main.json b/avm/1.1.0/res/network/network-watcher/flow-log/main.json new file mode 100644 index 000000000..2f0648876 --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/flow-log/main.json @@ -0,0 +1,163 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "18017322852547669945" + }, + "name": "NSG Flow Logs", + "description": "This module controls the Network Security Group Flow Logs and analytics settings.\n**Note: this module must be run on the Resource Group where Network Watcher is deployed**" + }, + "parameters": { + "networkWatcherName": { + "type": "string", + "defaultValue": "[format('NetworkWatcher_{0}', resourceGroup().location)]", + "metadata": { + "description": "Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-{1}-flowlog', last(split(parameters('targetResourceId'), '/')), split(parameters('targetResourceId'), '/')[4])]", + "metadata": { + "description": "Optional. Name of the resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "targetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the NSG that must be enabled for Flow Logs." + } + }, + "storageId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the diagnostic storage account." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If the flow log should be enabled." + } + }, + "formatVersion": { + "type": "int", + "defaultValue": 2, + "allowedValues": [ + 1, + 2 + ], + "metadata": { + "description": "Optional. The flow log format version." + } + }, + "workspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specify the Log Analytics Workspace Resource ID." + } + }, + "trafficAnalyticsInterval": { + "type": "int", + "defaultValue": 60, + "allowedValues": [ + 10, + 60 + ], + "metadata": { + "description": "Optional. The interval in minutes which would decide how frequently TA service should do flow analytics." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + } + }, + "variables": { + "flowAnalyticsConfiguration": "[if(and(not(empty(parameters('workspaceResourceId'))), equals(parameters('enabled'), true())), createObject('networkWatcherFlowAnalyticsConfiguration', createObject('enabled', true(), 'workspaceResourceId', parameters('workspaceResourceId'), 'trafficAnalyticsInterval', parameters('trafficAnalyticsInterval'))), createObject('networkWatcherFlowAnalyticsConfiguration', createObject('enabled', false())))]" + }, + "resources": { + "networkWatcher": { + "existing": true, + "type": "Microsoft.Network/networkWatchers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkWatcherName')]" + }, + "flowLog": { + "type": "Microsoft.Network/networkWatchers/flowLogs", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkWatcherName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "targetResourceId": "[parameters('targetResourceId')]", + "storageId": "[parameters('storageId')]", + "enabled": "[parameters('enabled')]", + "retentionPolicy": { + "days": "[parameters('retentionInDays')]", + "enabled": "[if(equals(parameters('retentionInDays'), 0), false(), true())]" + }, + "format": { + "type": "JSON", + "version": "[parameters('formatVersion')]" + }, + "flowAnalyticsConfiguration": "[variables('flowAnalyticsConfiguration')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the flow log." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the flow log." + }, + "value": "[resourceId('Microsoft.Network/networkWatchers/flowLogs', parameters('networkWatcherName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the flow log was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('flowLog', '2024-05-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-watcher/main.bicep b/avm/1.1.0/res/network/network-watcher/main.bicep new file mode 100644 index 000000000..a3f8ce2da --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/main.bicep @@ -0,0 +1,194 @@ +metadata name = 'Network Watchers' +metadata description = 'This module deploys a Network Watcher.' + +@description('Optional. Name of the Network Watcher resource (hidden).') +@minLength(1) +param name string = 'NetworkWatcher_${location}' + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Array that contains the Connection Monitors.') +param connectionMonitors array = [] + +@description('Optional. Array that contains the Flow Logs.') +param flowLogs array = [] + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-networkwatcher.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource networkWatcher 'Microsoft.Network/networkWatchers@2024-05-01' = { + name: name + location: location + tags: tags + properties: {} +} + +resource networkWatcher_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: networkWatcher +} + +resource networkWatcher_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(networkWatcher.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: networkWatcher + } +] + +module networkWatcher_connectionMonitors 'connection-monitor/main.bicep' = [ + for (connectionMonitor, index) in connectionMonitors: { + name: '${uniqueString(deployment().name, location)}-NW-ConnectionMonitor-${index}' + params: { + tags: tags + endpoints: connectionMonitor.?endpoints ?? [] + name: connectionMonitor.name + location: location + networkWatcherName: networkWatcher.name + testConfigurations: connectionMonitor.?testConfigurations ?? [] + testGroups: connectionMonitor.?testGroups ?? [] + workspaceResourceId: connectionMonitor.?workspaceResourceId ?? '' + } + } +] + +module networkWatcher_flowLogs 'flow-log/main.bicep' = [ + for (flowLog, index) in flowLogs: { + name: '${uniqueString(deployment().name, location)}-NW-FlowLog-${index}' + params: { + tags: tags + enabled: flowLog.?enabled ?? true + formatVersion: flowLog.?formatVersion ?? 2 + location: flowLog.?location ?? location + name: flowLog.?name ?? '${last(split(flowLog.targetResourceId, '/'))}-${split(flowLog.targetResourceId, '/')[4]}-flowlog' + networkWatcherName: networkWatcher.name + retentionInDays: flowLog.?retentionInDays ?? 365 + storageId: flowLog.storageId + targetResourceId: flowLog.targetResourceId + trafficAnalyticsInterval: flowLog.?trafficAnalyticsInterval ?? 60 + workspaceResourceId: flowLog.?workspaceResourceId ?? '' + } + } +] + +@description('The name of the deployed network watcher.') +output name string = networkWatcher.name + +@description('The resource ID of the deployed network watcher.') +output resourceId string = networkWatcher.id + +@description('The resource group the network watcher was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = networkWatcher.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/network-watcher/main.json b/avm/1.1.0/res/network/network-watcher/main.json new file mode 100644 index 000000000..59ea3e9f6 --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/main.json @@ -0,0 +1,666 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "7475359439448984364" + }, + "name": "Network Watchers", + "description": "This module deploys a Network Watcher." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('NetworkWatcher_{0}', parameters('location'))]", + "minLength": 1, + "metadata": { + "description": "Optional. Name of the Network Watcher resource (hidden)." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "connectionMonitors": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array that contains the Connection Monitors." + } + }, + "flowLogs": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array that contains the Flow Logs." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networkwatcher.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkWatcher": { + "type": "Microsoft.Network/networkWatchers", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + }, + "networkWatcher_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkWatchers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "networkWatcher" + ] + }, + "networkWatcher_roleAssignments": { + "copy": { + "name": "networkWatcher_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkWatchers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkWatchers', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkWatcher" + ] + }, + "networkWatcher_connectionMonitors": { + "copy": { + "name": "networkWatcher_connectionMonitors", + "count": "[length(parameters('connectionMonitors'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NW-ConnectionMonitor-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "tags": { + "value": "[parameters('tags')]" + }, + "endpoints": { + "value": "[coalesce(tryGet(parameters('connectionMonitors')[copyIndex()], 'endpoints'), createArray())]" + }, + "name": { + "value": "[parameters('connectionMonitors')[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "networkWatcherName": { + "value": "[parameters('name')]" + }, + "testConfigurations": { + "value": "[coalesce(tryGet(parameters('connectionMonitors')[copyIndex()], 'testConfigurations'), createArray())]" + }, + "testGroups": { + "value": "[coalesce(tryGet(parameters('connectionMonitors')[copyIndex()], 'testGroups'), createArray())]" + }, + "workspaceResourceId": { + "value": "[coalesce(tryGet(parameters('connectionMonitors')[copyIndex()], 'workspaceResourceId'), '')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "708993782418157673" + }, + "name": "Network Watchers Connection Monitors", + "description": "This module deploys a Network Watcher Connection Monitor." + }, + "parameters": { + "networkWatcherName": { + "type": "string", + "defaultValue": "[format('NetworkWatcher_{0}', resourceGroup().location)]", + "metadata": { + "description": "Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "endpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of connection monitor endpoints." + } + }, + "testConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of connection monitor test configurations." + } + }, + "testGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of connection monitor test groups." + } + }, + "workspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specify the Log Analytics Workspace Resource ID." + } + } + }, + "resources": { + "networkWatcher": { + "existing": true, + "type": "Microsoft.Network/networkWatchers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkWatcherName')]" + }, + "connectionMonitor": { + "type": "Microsoft.Network/networkWatchers/connectionMonitors", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkWatcherName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "endpoints": "[parameters('endpoints')]", + "testConfigurations": "[parameters('testConfigurations')]", + "testGroups": "[parameters('testGroups')]", + "outputs": "[if(not(empty(parameters('workspaceResourceId'))), createArray(createObject('type', 'Workspace', 'workspaceSettings', createObject('workspaceResourceId', parameters('workspaceResourceId')))), null())]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed connection monitor." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed connection monitor." + }, + "value": "[resourceId('Microsoft.Network/networkWatchers/connectionMonitors', parameters('networkWatcherName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the connection monitor was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('connectionMonitor', '2024-05-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "networkWatcher" + ] + }, + "networkWatcher_flowLogs": { + "copy": { + "name": "networkWatcher_flowLogs", + "count": "[length(parameters('flowLogs'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NW-FlowLog-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "tags": { + "value": "[parameters('tags')]" + }, + "enabled": { + "value": "[coalesce(tryGet(parameters('flowLogs')[copyIndex()], 'enabled'), true())]" + }, + "formatVersion": { + "value": "[coalesce(tryGet(parameters('flowLogs')[copyIndex()], 'formatVersion'), 2)]" + }, + "location": { + "value": "[coalesce(tryGet(parameters('flowLogs')[copyIndex()], 'location'), parameters('location'))]" + }, + "name": { + "value": "[coalesce(tryGet(parameters('flowLogs')[copyIndex()], 'name'), format('{0}-{1}-flowlog', last(split(parameters('flowLogs')[copyIndex()].targetResourceId, '/')), split(parameters('flowLogs')[copyIndex()].targetResourceId, '/')[4]))]" + }, + "networkWatcherName": { + "value": "[parameters('name')]" + }, + "retentionInDays": { + "value": "[coalesce(tryGet(parameters('flowLogs')[copyIndex()], 'retentionInDays'), 365)]" + }, + "storageId": { + "value": "[parameters('flowLogs')[copyIndex()].storageId]" + }, + "targetResourceId": { + "value": "[parameters('flowLogs')[copyIndex()].targetResourceId]" + }, + "trafficAnalyticsInterval": { + "value": "[coalesce(tryGet(parameters('flowLogs')[copyIndex()], 'trafficAnalyticsInterval'), 60)]" + }, + "workspaceResourceId": { + "value": "[coalesce(tryGet(parameters('flowLogs')[copyIndex()], 'workspaceResourceId'), '')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "18017322852547669945" + }, + "name": "NSG Flow Logs", + "description": "This module controls the Network Security Group Flow Logs and analytics settings.\n**Note: this module must be run on the Resource Group where Network Watcher is deployed**" + }, + "parameters": { + "networkWatcherName": { + "type": "string", + "defaultValue": "[format('NetworkWatcher_{0}', resourceGroup().location)]", + "metadata": { + "description": "Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-{1}-flowlog', last(split(parameters('targetResourceId'), '/')), split(parameters('targetResourceId'), '/')[4])]", + "metadata": { + "description": "Optional. Name of the resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "targetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the NSG that must be enabled for Flow Logs." + } + }, + "storageId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the diagnostic storage account." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If the flow log should be enabled." + } + }, + "formatVersion": { + "type": "int", + "defaultValue": 2, + "allowedValues": [ + 1, + 2 + ], + "metadata": { + "description": "Optional. The flow log format version." + } + }, + "workspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specify the Log Analytics Workspace Resource ID." + } + }, + "trafficAnalyticsInterval": { + "type": "int", + "defaultValue": 60, + "allowedValues": [ + 10, + 60 + ], + "metadata": { + "description": "Optional. The interval in minutes which would decide how frequently TA service should do flow analytics." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + } + }, + "variables": { + "flowAnalyticsConfiguration": "[if(and(not(empty(parameters('workspaceResourceId'))), equals(parameters('enabled'), true())), createObject('networkWatcherFlowAnalyticsConfiguration', createObject('enabled', true(), 'workspaceResourceId', parameters('workspaceResourceId'), 'trafficAnalyticsInterval', parameters('trafficAnalyticsInterval'))), createObject('networkWatcherFlowAnalyticsConfiguration', createObject('enabled', false())))]" + }, + "resources": { + "networkWatcher": { + "existing": true, + "type": "Microsoft.Network/networkWatchers", + "apiVersion": "2024-05-01", + "name": "[parameters('networkWatcherName')]" + }, + "flowLog": { + "type": "Microsoft.Network/networkWatchers/flowLogs", + "apiVersion": "2024-05-01", + "name": "[format('{0}/{1}', parameters('networkWatcherName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "targetResourceId": "[parameters('targetResourceId')]", + "storageId": "[parameters('storageId')]", + "enabled": "[parameters('enabled')]", + "retentionPolicy": { + "days": "[parameters('retentionInDays')]", + "enabled": "[if(equals(parameters('retentionInDays'), 0), false(), true())]" + }, + "format": { + "type": "JSON", + "version": "[parameters('formatVersion')]" + }, + "flowAnalyticsConfiguration": "[variables('flowAnalyticsConfiguration')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the flow log." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the flow log." + }, + "value": "[resourceId('Microsoft.Network/networkWatchers/flowLogs', parameters('networkWatcherName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the flow log was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('flowLog', '2024-05-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "networkWatcher" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed network watcher." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed network watcher." + }, + "value": "[resourceId('Microsoft.Network/networkWatchers', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network watcher was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkWatcher', '2024-05-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/network-watcher/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/network-watcher/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..0495f2894 --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,50 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change. + +// Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnwmin' + +@description('Optional. A token to inject into the name of each resource.') +#disable-next-line no-unused-params +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + // Note: This value is not required and only set to enable testing + location: enforcedLocation + } + } +] diff --git a/avm/1.1.0/res/network/network-watcher/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/network-watcher/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..c20f841f3 --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/tests/e2e/max/dependencies.bicep @@ -0,0 +1,144 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the first Network Security Group to create.') +param firstNetworkSecurityGroupName string + +@description('Required. The name of the second Network Security Group to create.') +param secondNetworkSecurityGroupName string + +@description('Required. The name of the Virtual Machine to create.') +param virtualMachineName string + +@description('Optional. The password to leverage for the VM login.') +@secure() +param password string = newGuid() + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource firstNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: firstNetworkSecurityGroupName + location: location +} + +resource secondNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: secondNetworkSecurityGroupName + location: location +} + +resource networkInterface 'Microsoft.Network/networkInterfaces@2023-04-01' = { + name: '${virtualMachineName}-nic' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig01' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + } +} + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-08-01' = { + name: virtualMachineName + location: location + properties: { + networkProfile: { + networkInterfaces: [ + { + id: networkInterface.id + properties: { + deleteOption: 'Delete' + primary: true + } + } + ] + } + storageProfile: { + imageReference: { + publisher: 'Canonical' + offer: '0001-com-ubuntu-server-jammy' + sku: '22_04-lts-gen2' + version: 'latest' + } + osDisk: { + deleteOption: 'Delete' + createOption: 'FromImage' + } + } + hardwareProfile: { + vmSize: 'Standard_B1ms' + } + osProfile: { + adminUsername: '${virtualMachineName}cake' + adminPassword: password + computerName: virtualMachineName + linuxConfiguration: { + disablePasswordAuthentication: false + } + } + } +} + +resource extension 'Microsoft.Compute/virtualMachines/extensions@2021-07-01' = { + name: 'NetworkWatcherAgent' + parent: virtualMachine + location: location + properties: { + publisher: 'Microsoft.Azure.NetworkWatcher' + type: 'NetworkWatcherAgentLinux' + typeHandlerVersion: '1.4' + autoUpgradeMinorVersion: true + enableAutomaticUpgrade: false + settings: {} + protectedSettings: {} + suppressFailures: false + } +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Virtual Machine.') +output virtualMachineResourceId string = virtualMachine.id + +@description('The resource ID of the first created Network Security Group.') +output firstNetworkSecurityGroupResourceId string = firstNetworkSecurityGroup.id + +@description('The resource ID of the second created Network Security Group.') +output secondNetworkSecurityGroupResourceId string = secondNetworkSecurityGroup.id diff --git a/avm/1.1.0/res/network/network-watcher/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/network-watcher/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..1b0400cf6 --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/tests/e2e/max/main.test.bicep @@ -0,0 +1,176 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change. + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnwmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +resource resourceGroupDependencies 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'dep-${namePrefix}-network.networkwatcher-${serviceShort}-rg' + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroupDependencies + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + firstNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-1-${serviceShort}' + secondNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-2-${serviceShort}' + virtualMachineName: 'dep-${namePrefix}-vm-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: enforcedLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroupDependencies + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: enforcedLocation + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + name: 'NetworkWatcher_${enforcedLocation}' + location: enforcedLocation + connectionMonitors: [ + { + name: '${namePrefix}-${serviceShort}-cm-001' + endpoints: [ + { + name: '${namePrefix}-subnet-001(${resourceGroup.name})' + resourceId: nestedDependencies.outputs.virtualMachineResourceId + type: 'AzureVM' + } + { + address: 'www.bing.com' + name: 'Bing' + type: 'ExternalAddress' + } + ] + testConfigurations: [ + { + httpConfiguration: { + method: 'Get' + port: 80 + preferHTTPS: false + requestHeaders: [] + validStatusCodeRanges: [ + '200' + ] + } + name: 'HTTP Bing Test' + protocol: 'Http' + successThreshold: { + checksFailedPercent: 5 + roundTripTimeMs: 100 + } + testFrequencySec: 30 + } + ] + testGroups: [ + { + destinations: [ + 'Bing' + ] + disable: false + name: 'test-http-Bing' + sources: [ + '${namePrefix}-subnet-001(${resourceGroup.name})' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + flowLogs: [ + { + enabled: false + storageId: diagnosticDependencies.outputs.storageAccountResourceId + targetResourceId: nestedDependencies.outputs.firstNetworkSecurityGroupResourceId + } + { + formatVersion: 1 + name: '${namePrefix}-${serviceShort}-fl-001' + retentionInDays: 8 + storageId: diagnosticDependencies.outputs.storageAccountResourceId + targetResourceId: nestedDependencies.outputs.secondNetworkSecurityGroupResourceId + trafficAnalyticsInterval: 10 + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + roleAssignments: [ + { + name: 'e8e93fb7-f450-41d5-ae86-a32d34e72578' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/network-watcher/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/network-watcher/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..c20f841f3 --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,144 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the first Network Security Group to create.') +param firstNetworkSecurityGroupName string + +@description('Required. The name of the second Network Security Group to create.') +param secondNetworkSecurityGroupName string + +@description('Required. The name of the Virtual Machine to create.') +param virtualMachineName string + +@description('Optional. The password to leverage for the VM login.') +@secure() +param password string = newGuid() + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource firstNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: firstNetworkSecurityGroupName + location: location +} + +resource secondNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: secondNetworkSecurityGroupName + location: location +} + +resource networkInterface 'Microsoft.Network/networkInterfaces@2023-04-01' = { + name: '${virtualMachineName}-nic' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig01' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + } +} + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-08-01' = { + name: virtualMachineName + location: location + properties: { + networkProfile: { + networkInterfaces: [ + { + id: networkInterface.id + properties: { + deleteOption: 'Delete' + primary: true + } + } + ] + } + storageProfile: { + imageReference: { + publisher: 'Canonical' + offer: '0001-com-ubuntu-server-jammy' + sku: '22_04-lts-gen2' + version: 'latest' + } + osDisk: { + deleteOption: 'Delete' + createOption: 'FromImage' + } + } + hardwareProfile: { + vmSize: 'Standard_B1ms' + } + osProfile: { + adminUsername: '${virtualMachineName}cake' + adminPassword: password + computerName: virtualMachineName + linuxConfiguration: { + disablePasswordAuthentication: false + } + } + } +} + +resource extension 'Microsoft.Compute/virtualMachines/extensions@2021-07-01' = { + name: 'NetworkWatcherAgent' + parent: virtualMachine + location: location + properties: { + publisher: 'Microsoft.Azure.NetworkWatcher' + type: 'NetworkWatcherAgentLinux' + typeHandlerVersion: '1.4' + autoUpgradeMinorVersion: true + enableAutomaticUpgrade: false + settings: {} + protectedSettings: {} + suppressFailures: false + } +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Virtual Machine.') +output virtualMachineResourceId string = virtualMachine.id + +@description('The resource ID of the first created Network Security Group.') +output firstNetworkSecurityGroupResourceId string = firstNetworkSecurityGroup.id + +@description('The resource ID of the second created Network Security Group.') +output secondNetworkSecurityGroupResourceId string = secondNetworkSecurityGroup.id diff --git a/avm/1.1.0/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..b0f724756 --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,155 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change. + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnwwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +resource resourceGroupDependencies 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'dep-${namePrefix}-network.networkwatcher-${serviceShort}-rg' + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroupDependencies + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + firstNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-1-${serviceShort}' + secondNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-2-${serviceShort}' + virtualMachineName: 'dep-${namePrefix}-vm-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: enforcedLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroupDependencies + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: enforcedLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + name: 'NetworkWatcher_${enforcedLocation}' + location: enforcedLocation + connectionMonitors: [ + { + name: '${namePrefix}-${serviceShort}-cm-001' + endpoints: [ + { + name: '${namePrefix}-subnet-001(${resourceGroup.name})' + resourceId: nestedDependencies.outputs.virtualMachineResourceId + type: 'AzureVM' + } + { + address: 'www.bing.com' + name: 'Bing' + type: 'ExternalAddress' + } + ] + testConfigurations: [ + { + httpConfiguration: { + method: 'Get' + port: 80 + preferHTTPS: false + requestHeaders: [] + validStatusCodeRanges: [ + '200' + ] + } + name: 'HTTP Bing Test' + protocol: 'Http' + successThreshold: { + checksFailedPercent: 5 + roundTripTimeMs: 100 + } + testFrequencySec: 30 + } + ] + testGroups: [ + { + destinations: [ + 'Bing' + ] + disable: false + name: 'test-http-Bing' + sources: [ + '${namePrefix}-subnet-001(${resourceGroup.name})' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + flowLogs: [ + { + enabled: false + storageId: diagnosticDependencies.outputs.storageAccountResourceId + targetResourceId: nestedDependencies.outputs.firstNetworkSecurityGroupResourceId + } + { + formatVersion: 1 + name: '${namePrefix}-${serviceShort}-fl-001' + retentionInDays: 8 + storageId: diagnosticDependencies.outputs.storageAccountResourceId + targetResourceId: nestedDependencies.outputs.secondNetworkSecurityGroupResourceId + trafficAnalyticsInterval: 10 + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/network-watcher/version.json b/avm/1.1.0/res/network/network-watcher/version.json new file mode 100644 index 000000000..96236a61b --- /dev/null +++ b/avm/1.1.0/res/network/network-watcher/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/avm/1.1.0/res/network/p2s-vpn-gateway/README.md b/avm/1.1.0/res/network/p2s-vpn-gateway/README.md new file mode 100644 index 000000000..3b174d130 --- /dev/null +++ b/avm/1.1.0/res/network/p2s-vpn-gateway/README.md @@ -0,0 +1,679 @@ +# P2S VPN Gateway `[Microsoft.Network/p2svpnGateways]` + +This module deploys a Virtual Hub P2S Gateway. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Network/p2svpnGateways` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-01-01/p2svpnGateways) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/p2s-vpn-gateway:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module p2sVpnGateway 'br/public:avm/res/network/p2s-vpn-gateway:' = { + name: 'p2sVpnGatewayDeployment' + params: { + // Required parameters + name: 'npvgminp2sVpnGw' + virtualHubResourceId: '' + // Non-required parameters + associatedRouteTableName: 'defaultRouteTable' + p2SConnectionConfigurationsName: 'p2sConnectionConfig1' + vpnClientAddressPoolAddressPrefixes: [ + '10.0.2.0/24' + ] + vpnServerConfigurationResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npvgminp2sVpnGw" + }, + "virtualHubResourceId": { + "value": "" + }, + // Non-required parameters + "associatedRouteTableName": { + "value": "defaultRouteTable" + }, + "p2SConnectionConfigurationsName": { + "value": "p2sConnectionConfig1" + }, + "vpnClientAddressPoolAddressPrefixes": { + "value": [ + "10.0.2.0/24" + ] + }, + "vpnServerConfigurationResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/p2s-vpn-gateway:' + +// Required parameters +param name = 'npvgminp2sVpnGw' +param virtualHubResourceId = '' +// Non-required parameters +param associatedRouteTableName = 'defaultRouteTable' +p2SConnectionConfigurationsName: 'p2sConnectionConfig1' +param vpnClientAddressPoolAddressPrefixes = [ + '10.0.2.0/24' +] +param vpnServerConfigurationResourceId = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module p2sVpnGateway 'br/public:avm/res/network/p2s-vpn-gateway:' = { + name: 'p2sVpnGatewayDeployment' + params: { + // Required parameters + name: 'npvgmaxp2sVpnGw' + virtualHubResourceId: '' + // Non-required parameters + associatedRouteTableName: 'noneRouteTable' + customDnsServers: [ + '10.50.10.50' + '10.50.50.50' + ] + enableInternetSecurity: false + inboundRouteMapResourceId: '' + isRoutingPreferenceInternet: false + location: '' + outboundRouteMapResourceId: '' + p2SConnectionConfigurationsName: 'p2sConnectionConfig' + propagatedLabelNames: '' + propagatedRouteTableNames: [ + '' + ] + vpnClientAddressPoolAddressPrefixes: [ + '10.0.2.0/24' + '10.0.3.0/24' + ] + vpnGatewayScaleUnit: 5 + vpnServerConfigurationResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npvgmaxp2sVpnGw" + }, + "virtualHubResourceId": { + "value": "" + }, + // Non-required parameters + "associatedRouteTableName": { + "value": "noneRouteTable" + }, + "customDnsServers": { + "value": [ + "10.50.10.50", + "10.50.50.50" + ] + }, + "enableInternetSecurity": { + "value": false + }, + "inboundRouteMapResourceId": { + "value": "" + }, + "isRoutingPreferenceInternet": { + "value": false + }, + "location": { + "value": "" + }, + "outboundRouteMapResourceId": { + "value": "" + }, + "p2SConnectionConfigurationsName": { + "value": "p2sConnectionConfig" + }, + "propagatedLabelNames": { + "value": "" + }, + "propagatedRouteTableNames": { + "value": [ + "" + ] + }, + "vpnClientAddressPoolAddressPrefixes": { + "value": [ + "10.0.2.0/24", + "10.0.3.0/24" + ] + }, + "vpnGatewayScaleUnit": { + "value": 5 + }, + "vpnServerConfigurationResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/p2s-vpn-gateway:' + +// Required parameters +param name = 'npvgmaxp2sVpnGw' +param virtualHubResourceId = '' +// Non-required parameters +param associatedRouteTableName = 'noneRouteTable' +param customDnsServers = [ + '10.50.10.50' + '10.50.50.50' +] +param enableInternetSecurity = false +param inboundRouteMapResourceId = '' +param isRoutingPreferenceInternet = false +param location = '' +param outboundRouteMapResourceId = '' +p2SConnectionConfigurationsName: 'p2sConnectionConfig' +param propagatedLabelNames = '' +param propagatedRouteTableNames = [ + '' +] +param vpnClientAddressPoolAddressPrefixes = [ + '10.0.2.0/24' + '10.0.3.0/24' +] +param vpnGatewayScaleUnit = 5 +param vpnServerConfigurationResourceId = '' +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module p2sVpnGateway 'br/public:avm/res/network/p2s-vpn-gateway:' = { + name: 'p2sVpnGatewayDeployment' + params: { + // Required parameters + name: 'npvgwafp2sVpnGw' + virtualHubResourceId: '' + // Non-required parameters + associatedRouteTableName: 'defaultRouteTable' + enableInternetSecurity: true + isRoutingPreferenceInternet: false + location: '' + p2SConnectionConfigurationsName: 'p2sConnectionConfig1' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + vpnClientAddressPoolAddressPrefixes: [ + '10.0.2.0/24' + ] + vpnServerConfigurationResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npvgwafp2sVpnGw" + }, + "virtualHubResourceId": { + "value": "" + }, + // Non-required parameters + "associatedRouteTableName": { + "value": "defaultRouteTable" + }, + "enableInternetSecurity": { + "value": true + }, + "isRoutingPreferenceInternet": { + "value": false + }, + "location": { + "value": "" + }, + "p2SConnectionConfigurationsName": { + "value": "p2sConnectionConfig1" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "Role": "DeploymentValidation" + } + }, + "vpnClientAddressPoolAddressPrefixes": { + "value": [ + "10.0.2.0/24" + ] + }, + "vpnServerConfigurationResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/p2s-vpn-gateway:' + +// Required parameters +param name = 'npvgwafp2sVpnGw' +param virtualHubResourceId = '' +// Non-required parameters +param associatedRouteTableName = 'defaultRouteTable' +param enableInternetSecurity = true +param isRoutingPreferenceInternet = false +param location = '' +p2SConnectionConfigurationsName: 'p2sConnectionConfig1' +param tags = { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' +} +param vpnClientAddressPoolAddressPrefixes = [ + '10.0.2.0/24' +] +param vpnServerConfigurationResourceId = '' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the P2S VPN Gateway. | +| [`virtualHubResourceId`](#parameter-virtualhubresourceid) | string | The resource ID of the gateways virtual hub. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`associatedRouteTableName`](#parameter-associatedroutetablename) | string | The name of the associated route table. Required if deploying in a Secure Virtual Hub; cannot be a custom route table. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`customDnsServers`](#parameter-customdnsservers) | array | The custom DNS servers for the P2S VPN Gateway. | +| [`enableInternetSecurity`](#parameter-enableinternetsecurity) | bool | Enable/Disable Internet Security; "Propagate Default Route". | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`inboundRouteMapResourceId`](#parameter-inboundroutemapresourceid) | string | The Resource ID of the inbound route map. | +| [`isRoutingPreferenceInternet`](#parameter-isroutingpreferenceinternet) | bool | The routing preference for the P2S VPN Gateway, Internet or Microsoft network. | +| [`location`](#parameter-location) | string | Location where all resources will be created. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`outboundRouteMapResourceId`](#parameter-outboundroutemapresourceid) | string | The Resource ID of the outbound route map. | +| [`p2SConnectionConfigurationsName`](#parameter-p2sconnectionconfigurationsname) | string | The name of the P2S Connection Configuration. | +| [`propagatedLabelNames`](#parameter-propagatedlabelnames) | array | The Labels to propagate routes to. | +| [`propagatedRouteTableNames`](#parameter-propagatedroutetablenames) | array | The names of the route tables to propagate to the P2S VPN Gateway. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`vnetRoutesStaticRoutes`](#parameter-vnetroutesstaticroutes) | object | The routes from the virtual hub to virtual network connections. | +| [`vpnClientAddressPoolAddressPrefixes`](#parameter-vpnclientaddresspooladdressprefixes) | array | The address prefixes for the VPN Client Address Pool. | +| [`vpnGatewayScaleUnit`](#parameter-vpngatewayscaleunit) | int | The scale unit of the VPN Gateway. | +| [`vpnServerConfigurationResourceId`](#parameter-vpnserverconfigurationresourceid) | string | The resource ID of the VPN Server Configuration. | + +### Parameter: `name` + +The name of the P2S VPN Gateway. + +- Required: Yes +- Type: string + +### Parameter: `virtualHubResourceId` + +The resource ID of the gateways virtual hub. + +- Required: Yes +- Type: string + +### Parameter: `associatedRouteTableName` + +The name of the associated route table. Required if deploying in a Secure Virtual Hub; cannot be a custom route table. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'defaultRouteTable' + 'noneRouteTable' + ] + ``` + +### Parameter: `customDnsServers` + +The custom DNS servers for the P2S VPN Gateway. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `enableInternetSecurity` + +Enable/Disable Internet Security; "Propagate Default Route". + +- Required: No +- Type: bool + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `inboundRouteMapResourceId` + +The Resource ID of the inbound route map. + +- Required: No +- Type: string + +### Parameter: `isRoutingPreferenceInternet` + +The routing preference for the P2S VPN Gateway, Internet or Microsoft network. + +- Required: No +- Type: bool + +### Parameter: `location` + +Location where all resources will be created. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `outboundRouteMapResourceId` + +The Resource ID of the outbound route map. + +- Required: No +- Type: string + +### Parameter: `p2SConnectionConfigurationsName` + +The name of the P2S Connection Configuration. + +- Required: No +- Type: string + +### Parameter: `propagatedLabelNames` + +The Labels to propagate routes to. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `propagatedRouteTableNames` + +The names of the route tables to propagate to the P2S VPN Gateway. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `vnetRoutesStaticRoutes` + +The routes from the virtual hub to virtual network connections. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`staticRoutes`](#parameter-vnetroutesstaticroutesstaticroutes) | array | The static route configuration for the P2S VPN Gateway. | +| [`staticRoutesConfig`](#parameter-vnetroutesstaticroutesstaticroutesconfig) | object | The static route configuration for the P2S VPN Gateway. | + +### Parameter: `vnetRoutesStaticRoutes.staticRoutes` + +The static route configuration for the P2S VPN Gateway. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefixes`](#parameter-vnetroutesstaticroutesstaticroutesaddressprefixes) | array | The address prefixes of the static route. | +| [`name`](#parameter-vnetroutesstaticroutesstaticroutesname) | string | The name of the static route. | +| [`nextHopIpAddress`](#parameter-vnetroutesstaticroutesstaticroutesnexthopipaddress) | string | The next hop IP of the static route. | + +### Parameter: `vnetRoutesStaticRoutes.staticRoutes.addressPrefixes` + +The address prefixes of the static route. + +- Required: No +- Type: array + +### Parameter: `vnetRoutesStaticRoutes.staticRoutes.name` + +The name of the static route. + +- Required: No +- Type: string + +### Parameter: `vnetRoutesStaticRoutes.staticRoutes.nextHopIpAddress` + +The next hop IP of the static route. + +- Required: No +- Type: string + +### Parameter: `vnetRoutesStaticRoutes.staticRoutesConfig` + +The static route configuration for the P2S VPN Gateway. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`vnetLocalRouteOverrideCriteria`](#parameter-vnetroutesstaticroutesstaticroutesconfigvnetlocalrouteoverridecriteria) | string | Determines whether the NVA in a SPOKE VNET is bypassed for traffic with destination in spoke. | + +### Parameter: `vnetRoutesStaticRoutes.staticRoutesConfig.vnetLocalRouteOverrideCriteria` + +Determines whether the NVA in a SPOKE VNET is bypassed for traffic with destination in spoke. + +- Required: No +- Type: string + +### Parameter: `vpnClientAddressPoolAddressPrefixes` + +The address prefixes for the VPN Client Address Pool. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `vpnGatewayScaleUnit` + +The scale unit of the VPN Gateway. + +- Required: No +- Type: int + +### Parameter: `vpnServerConfigurationResourceId` + +The resource ID of the VPN Server Configuration. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the user VPN configuration. | +| `resourceGroupName` | string | The name of the resource group the user VPN configuration was deployed into. | +| `resourceId` | string | The resource ID of the user VPN configuration. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/p2s-vpn-gateway/main.bicep b/avm/1.1.0/res/network/p2s-vpn-gateway/main.bicep new file mode 100644 index 000000000..3dd5a5a4f --- /dev/null +++ b/avm/1.1.0/res/network/p2s-vpn-gateway/main.bicep @@ -0,0 +1,204 @@ +metadata name = 'P2S VPN Gateway' +metadata description = 'This module deploys a Virtual Hub P2S Gateway.' + +@description('Required. The name of the P2S VPN Gateway.') +param name string + +@description('Optional. Location where all resources will be created.') +param location string = resourceGroup().location + +@allowed([ + 'noneRouteTable' + 'defaultRouteTable' +]) +@description('Conditional. The name of the associated route table. Required if deploying in a Secure Virtual Hub; cannot be a custom route table.') +param associatedRouteTableName string? + +@description('Optional. The names of the route tables to propagate to the P2S VPN Gateway.') +param propagatedRouteTableNames string[] = [] + +@description('Optional. The custom DNS servers for the P2S VPN Gateway.') +param customDnsServers array = [] + +@description('Optional. The routing preference for the P2S VPN Gateway, Internet or Microsoft network.') +param isRoutingPreferenceInternet bool? + +@description('Optional. The name of the P2S Connection Configuration.') +param p2SConnectionConfigurationsName string? + +@description('Optional. Enable/Disable Internet Security; "Propagate Default Route".') +param enableInternetSecurity bool? + +@description('Optional. The Resource ID of the inbound route map.') +param inboundRouteMapResourceId string? + +@description('Optional. The Resource ID of the outbound route map.') +param outboundRouteMapResourceId string? + +@description('Optional. The Labels to propagate routes to.') +param propagatedLabelNames string[] = [] + +@description('Optional. The routes from the virtual hub to virtual network connections.') +param vnetRoutesStaticRoutes vnetRoutesStaticRoutesType? + +@description('Optional. The address prefixes for the VPN Client Address Pool.') +param vpnClientAddressPoolAddressPrefixes array = [] + +@description('Required. The resource ID of the gateways virtual hub.') +param virtualHubResourceId string + +@description('Optional. The scale unit of the VPN Gateway.') +param vpnGatewayScaleUnit int? + +@description('Optional. The resource ID of the VPN Server Configuration.') +param vpnServerConfigurationResourceId string? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// =============== // + +@description('Extract the virtual hub name from the virtual hub ID.') +var virtualHubName = split(virtualHubResourceId, '/')[8] + +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.res.network-p2svpngateway.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource p2sVpnGateway 'Microsoft.Network/p2svpnGateways@2024-01-01' = { + name: name + location: location + tags: tags + properties: { + customDnsServers: customDnsServers + isRoutingPreferenceInternet: isRoutingPreferenceInternet + p2SConnectionConfigurations: [ + { + name: p2SConnectionConfigurationsName + properties: { + enableInternetSecurity: enableInternetSecurity + routingConfiguration: { + associatedRouteTable: { + id: resourceId( + 'Microsoft.Network/virtualHubs/hubRouteTables', + '${virtualHubName}', + '${associatedRouteTableName}' + ) + } + inboundRouteMap: (!empty(inboundRouteMapResourceId)) + ? { + id: inboundRouteMapResourceId + } + : null + outboundRouteMap: (!empty(outboundRouteMapResourceId)) + ? { + id: outboundRouteMapResourceId + } + : null + propagatedRouteTables: { + ids: [ + for table in (propagatedRouteTableNames): { + id: resourceId('Microsoft.Network/virtualHubs/hubRouteTables', '${virtualHubName}', '${table}') + } + ] + labels: propagatedLabelNames + } + vnetRoutes: vnetRoutesStaticRoutes + } + vpnClientAddressPool: { + addressPrefixes: vpnClientAddressPoolAddressPrefixes + } + } + } + ] + virtualHub: { + id: virtualHubResourceId + } + vpnGatewayScaleUnit: vpnGatewayScaleUnit + vpnServerConfiguration: { + id: vpnServerConfigurationResourceId + } + } +} + +resource vpnGateway_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: p2sVpnGateway +} + +@description('The name of the user VPN configuration.') +output name string = p2sVpnGateway.name + +@description('The resource ID of the user VPN configuration.') +output resourceId string = p2sVpnGateway.id + +@description('The name of the resource group the user VPN configuration was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = p2sVpnGateway.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +@export() +@description('Optional. A Type representing the VNET static routes for the P2S VPN Gateway.') +type vnetRoutesStaticRoutesType = { + @description('Optional. The static route configuration for the P2S VPN Gateway.') + staticRoutes: { + @description('Optional. The address prefixes of the static route.') + addressPrefixes: string[]? + + @description('Optional. The name of the static route.') + name: string? + + @description('Optional. The next hop IP of the static route.') + nextHopIpAddress: string? + }[]? + @description('Optional. The static route configuration for the P2S VPN Gateway.') + staticRoutesConfig: { + @description('Optional. Determines whether the NVA in a SPOKE VNET is bypassed for traffic with destination in spoke.') + vnetLocalRouteOverrideCriteria: string? + }? +} diff --git a/avm/1.1.0/res/network/p2s-vpn-gateway/main.json b/avm/1.1.0/res/network/p2s-vpn-gateway/main.json new file mode 100644 index 000000000..1560c9099 --- /dev/null +++ b/avm/1.1.0/res/network/p2s-vpn-gateway/main.json @@ -0,0 +1,362 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "8499108879693824229" + }, + "name": "P2S VPN Gateway", + "description": "This module deploys a Virtual Hub P2S Gateway." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "vnetRoutesStaticRoutesType": { + "type": "object", + "properties": { + "staticRoutes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The address prefixes of the static route." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the static route." + } + }, + "nextHopIpAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The next hop IP of the static route." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The static route configuration for the P2S VPN Gateway." + } + }, + "staticRoutesConfig": { + "type": "object", + "properties": { + "vnetLocalRouteOverrideCriteria": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines whether the NVA in a SPOKE VNET is bypassed for traffic with destination in spoke." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The static route configuration for the P2S VPN Gateway." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Optional. A Type representing the VNET static routes for the P2S VPN Gateway." + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the P2S VPN Gateway." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location where all resources will be created." + } + }, + "associatedRouteTableName": { + "type": "string", + "nullable": true, + "allowedValues": [ + "noneRouteTable", + "defaultRouteTable" + ], + "metadata": { + "description": "Conditional. The name of the associated route table. Required if deploying in a Secure Virtual Hub; cannot be a custom route table." + } + }, + "propagatedRouteTableNames": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The names of the route tables to propagate to the P2S VPN Gateway." + } + }, + "customDnsServers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The custom DNS servers for the P2S VPN Gateway." + } + }, + "isRoutingPreferenceInternet": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The routing preference for the P2S VPN Gateway, Internet or Microsoft network." + } + }, + "p2SConnectionConfigurationsName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the P2S Connection Configuration." + } + }, + "enableInternetSecurity": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable Internet Security; \"Propagate Default Route\"." + } + }, + "inboundRouteMapResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource ID of the inbound route map." + } + }, + "outboundRouteMapResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource ID of the outbound route map." + } + }, + "propagatedLabelNames": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The Labels to propagate routes to." + } + }, + "vnetRoutesStaticRoutes": { + "$ref": "#/definitions/vnetRoutesStaticRoutesType", + "nullable": true, + "metadata": { + "description": "Optional. The routes from the virtual hub to virtual network connections." + } + }, + "vpnClientAddressPoolAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The address prefixes for the VPN Client Address Pool." + } + }, + "virtualHubResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the gateways virtual hub." + } + }, + "vpnGatewayScaleUnit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The scale unit of the VPN Gateway." + } + }, + "vpnServerConfigurationResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the VPN Server Configuration." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "virtualHubName": "[split(parameters('virtualHubResourceId'), '/')[8]]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.res.network-p2svpngateway.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "p2sVpnGateway": { + "type": "Microsoft.Network/p2svpnGateways", + "apiVersion": "2024-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "customDnsServers": "[parameters('customDnsServers')]", + "isRoutingPreferenceInternet": "[parameters('isRoutingPreferenceInternet')]", + "p2SConnectionConfigurations": [ + { + "name": "[parameters('p2SConnectionConfigurationsName')]", + "properties": { + "enableInternetSecurity": "[parameters('enableInternetSecurity')]", + "routingConfiguration": { + "associatedRouteTable": { + "id": "[resourceId('Microsoft.Network/virtualHubs/hubRouteTables', format('{0}', variables('virtualHubName')), format('{0}', parameters('associatedRouteTableName')))]" + }, + "inboundRouteMap": "[if(not(empty(parameters('inboundRouteMapResourceId'))), createObject('id', parameters('inboundRouteMapResourceId')), null())]", + "outboundRouteMap": "[if(not(empty(parameters('outboundRouteMapResourceId'))), createObject('id', parameters('outboundRouteMapResourceId')), null())]", + "propagatedRouteTables": { + "copy": [ + { + "name": "ids", + "count": "[length(parameters('propagatedRouteTableNames'))]", + "input": { + "id": "[resourceId('Microsoft.Network/virtualHubs/hubRouteTables', format('{0}', variables('virtualHubName')), format('{0}', parameters('propagatedRouteTableNames')[copyIndex('ids')]))]" + } + } + ], + "labels": "[parameters('propagatedLabelNames')]" + }, + "vnetRoutes": "[parameters('vnetRoutesStaticRoutes')]" + }, + "vpnClientAddressPool": { + "addressPrefixes": "[parameters('vpnClientAddressPoolAddressPrefixes')]" + } + } + } + ], + "virtualHub": { + "id": "[parameters('virtualHubResourceId')]" + }, + "vpnGatewayScaleUnit": "[parameters('vpnGatewayScaleUnit')]", + "vpnServerConfiguration": { + "id": "[parameters('vpnServerConfigurationResourceId')]" + } + } + }, + "vpnGateway_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/p2svpnGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "p2sVpnGateway" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user VPN configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user VPN configuration." + }, + "value": "[resourceId('Microsoft.Network/p2svpnGateways', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the user VPN configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('p2sVpnGateway', '2024-01-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..dfc78768e --- /dev/null +++ b/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,57 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource virtualWan 'Microsoft.Network/virtualWans@2024-01-01' = { + name: virtualWANName + location: location +} + +resource vpnServerConfiguration 'Microsoft.Network/vpnServerConfigurations@2024-01-01' = { + name: '${virtualWANName}-${location}-vpnServerConfiguration' + location: location + properties: { + aadAuthenticationParameters: { + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' + } + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnProtocols: [ + 'OpenVPN' + ] + } +} + +resource virtualHub 'Microsoft.Network/virtualHubs@2024-01-01' = { + name: '${virtualWANName}-${location}-hub' + location: location + properties: { + addressPrefix: '10.0.0.0/23' + virtualWan: { + id: virtualWan.id + } + } +} + +@description('The resource ID of the created Virtual WAN.') +output virtualWANResourceId string = virtualWan.id + +@description('The name of the created Virtual WAN.') +output virtualWANName string = virtualWan.name + +@description('The resource ID of the created Virtual Hub.') +output virtualHubResourceId string = virtualHub.id + +@description('The name of the created Virtual Hub.') +output virtualHubName string = virtualHub.name + +@description('The resource ID of the created VPN Server Configuration.') +output vpnServerConfigurationResourceId string = vpnServerConfiguration.id + +@description('The name of the created VPN Server Configuration.') +output vpnServerConfigurationName string = vpnServerConfiguration.name diff --git a/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..f87a9ffc1 --- /dev/null +++ b/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,65 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.p2svpngateway-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npvgmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + + + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}p2sVpnGw' + p2SConnectionConfigurationsName: 'p2sConnectionConfig1' + vpnClientAddressPoolAddressPrefixes: [ + '10.0.2.0/24' + ] + associatedRouteTableName: 'defaultRouteTable' + virtualHubResourceId: nestedDependencies.outputs.virtualHubResourceId + vpnServerConfigurationResourceId: nestedDependencies.outputs.vpnServerConfigurationResourceId + } + } +] diff --git a/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..0d7687194 --- /dev/null +++ b/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/max/dependencies.bicep @@ -0,0 +1,156 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource virtualWan 'Microsoft.Network/virtualWans@2024-01-01' = { + name: virtualWANName + location: location +} + +resource vpnServerConfiguration 'Microsoft.Network/vpnServerConfigurations@2024-01-01' = { + name: '${virtualWANName}-${location}-vpnServerConfiguration' + location: location + properties: { + aadAuthenticationParameters: { + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' + } + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnProtocols: [ + 'OpenVPN' + ] + } +} + +resource virtualHub 'Microsoft.Network/virtualHubs@2024-01-01' = { + name: '${virtualWANName}-${location}-hub' + location: location + properties: { + addressPrefix: '10.0.0.0/23' + virtualWan: { + id: virtualWan.id + } + } +} + +resource hubRouteTable 'Microsoft.Network/virtualHubs/hubRouteTables@2024-01-01' = { + name: 'VPNRouteTable' + parent: virtualHub + properties: { + labels: [ + 'VPNRoutes' + ] + routes: [ + { + name: 'DefaultVPNRoute' + destinations: [ + '10.1.100.0/24' + ] + destinationType: 'CIDR' + nextHop: azureFirewall.id + nextHopType: 'ResourceId' + } + ] + } +} + +resource hubRouteMap 'Microsoft.Network/virtualHubs/routeMaps@2024-01-01' = { + name: 'VPNRouteMap' + parent: virtualHub + dependsOn: [ + hubRouteTable + ] + properties: { + rules: [ + { + actions: [ + { + parameters: [ + { + asPath: [ + '65051' + ] + } + ] + type: 'Add' + } + ] + matchCriteria: [ + { + asPath: [ + '65050' + ] + matchCondition: 'Equals' + } + ] + name: 'TestVPNRouteMap' + nextStepIfMatched: 'Continue' + } + ] + } +} +resource azureFirewall 'Microsoft.Network/azureFirewalls@2024-01-01' = { + name: '${virtualWANName}-${location}-hub' + location: location + properties: { + sku: { + name: 'AZFW_Hub' + tier: 'Premium' + } + virtualHub: { + id: virtualHub.id + } + hubIPAddresses: { + publicIPs: { + count: 1 + } + } + } +} + +@description('The resource ID of the created Virtual WAN.') +output virtualWANResourceId string = virtualWan.id + +@description('The name of the created Virtual WAN.') +output virtualWANName string = virtualWan.name + +@description('The resource ID of the created Virtual Hub.') +output virtualHubResourceId string = virtualHub.id + +@description('The name of the created Virtual Hub.') +output virtualHubName string = virtualHub.name + +@description('The resource ID of the created VPN Server Configuration.') +output vpnServerConfigurationResourceId string = vpnServerConfiguration.id + +@description('The name of the created VPN Server Configuration.') +output vpnServerConfigurationName string = vpnServerConfiguration.name + +@description('The resource ID of the created hub Azure Firewall') +output azureFirewallResourceId string = azureFirewall.id + +@description('The name of the created hub Azure Firewall') +output azureFirewallName string = azureFirewall.name + +@description('The private IP address of the created hub Azure Firewall') +output azureFirewallPrivateIp string = azureFirewall.properties.hubIPAddresses.privateIPAddress + +@description('The resource ID of the created hub route table') +output hubRouteTableName string = hubRouteTable.name + +@description('The name of the created hub route table') +output hubRouteTableResourceId string = hubRouteTable.id + +@description('The labels for the created hub route table') +output hubRouteTableLabels string[] = hubRouteTable.properties.labels + +@description('The resource ID of the created hub route map') +output hubRouteMapResourceId string = hubRouteMap.id + +@description('The name of the created hub route map') +output hubRouteMapName string = hubRouteMap.name diff --git a/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..3395943aa --- /dev/null +++ b/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/max/main.test.bicep @@ -0,0 +1,79 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.p2svpngateway-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npvgmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}p2sVpnGw' + customDnsServers: [ + '10.50.10.50' + '10.50.50.50' + ] + isRoutingPreferenceInternet: false + enableInternetSecurity: false + associatedRouteTableName: 'noneRouteTable' + inboundRouteMapResourceId: nestedDependencies.outputs.hubRouteMapResourceId + outboundRouteMapResourceId: nestedDependencies.outputs.hubRouteMapResourceId + propagatedRouteTableNames: [ + nestedDependencies.outputs.hubRouteTableName + ] + propagatedLabelNames: nestedDependencies.outputs.hubRouteTableLabels + vpnClientAddressPoolAddressPrefixes: [ + '10.0.2.0/24' + '10.0.3.0/24' + ] + virtualHubResourceId: nestedDependencies.outputs.virtualHubResourceId + vpnGatewayScaleUnit: 5 + vpnServerConfigurationResourceId: nestedDependencies.outputs.vpnServerConfigurationResourceId + p2SConnectionConfigurationsName: 'p2sConnectionConfig' + } + } +] diff --git a/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..c28dbefb5 --- /dev/null +++ b/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,82 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource virtualWan 'Microsoft.Network/virtualWans@2024-01-01' = { + name: virtualWANName + location: location +} + +resource vpnServerConfiguration 'Microsoft.Network/vpnServerConfigurations@2024-01-01' = { + name: '${virtualWANName}-${location}-vpnServerConfiguration' + location: location + properties: { + aadAuthenticationParameters: { + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' + } + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnProtocols: [ + 'OpenVPN' + ] + } +} + +resource virtualHub 'Microsoft.Network/virtualHubs@2024-01-01' = { + name: '${virtualWANName}-${location}-hub' + location: location + properties: { + addressPrefix: '10.0.0.0/23' + virtualWan: { + id: virtualWan.id + } + } +} + +resource azureFirewall 'Microsoft.Network/azureFirewalls@2024-01-01' = { + name: '${virtualWANName}-${location}-hub' + location: location + properties: { + sku: { + name: 'AZFW_Hub' + tier: 'Premium' + } + virtualHub: { + id: virtualHub.id + } + hubIPAddresses: { + publicIPs: { + count: 1 + } + } + } +} + +@description('The resource ID of the created Virtual WAN.') +output virtualWANResourceId string = virtualWan.id + +@description('The name of the created Virtual WAN.') +output virtualWANName string = virtualWan.name + +@description('The resource ID of the created Virtual Hub.') +output virtualHubResourceId string = virtualHub.id + +@description('The name of the created Virtual Hub.') +output virtualHubName string = virtualHub.name + +@description('The resource ID of the created VPN Server Configuration.') +output vpnServerConfigurationResourceId string = vpnServerConfiguration.id + +@description('The name of the created VPN Server Configuration.') +output vpnServerConfigurationName string = vpnServerConfiguration.name + +@description('The resource ID of the created hub Azure Firewall') +output azureFirewallResourceId string = azureFirewall.id + +@description('The name of the created hub Azure Firewall') +output azureFirewallName string = azureFirewall.name diff --git a/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..f1f998422 --- /dev/null +++ b/avm/1.1.0/res/network/p2s-vpn-gateway/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,72 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.p2svpngateway-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npvgwaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + + + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}p2sVpnGw' + location: resourceLocation + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + p2SConnectionConfigurationsName: 'p2sConnectionConfig1' + isRoutingPreferenceInternet: false + enableInternetSecurity: true + associatedRouteTableName: 'defaultRouteTable' + vpnClientAddressPoolAddressPrefixes: [ + '10.0.2.0/24' + ] + virtualHubResourceId: nestedDependencies.outputs.virtualHubResourceId + vpnServerConfigurationResourceId: nestedDependencies.outputs.vpnServerConfigurationResourceId + } + } +] diff --git a/avm/1.1.0/res/network/p2s-vpn-gateway/version.json b/avm/1.1.0/res/network/p2s-vpn-gateway/version.json new file mode 100644 index 000000000..7245f1487 --- /dev/null +++ b/avm/1.1.0/res/network/p2s-vpn-gateway/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] + } \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-dns-zone/README.md b/avm/1.1.0/res/network/private-dns-zone/README.md new file mode 100644 index 000000000..d1db0f234 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/README.md @@ -0,0 +1,2740 @@ +# Private DNS Zones `[Microsoft.Network/privateDnsZones]` + +This module deploys a Private DNS zone. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/privateDnsZones` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones) | +| `Microsoft.Network/privateDnsZones/A` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/A) | +| `Microsoft.Network/privateDnsZones/AAAA` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/AAAA) | +| `Microsoft.Network/privateDnsZones/CNAME` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/CNAME) | +| `Microsoft.Network/privateDnsZones/MX` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/MX) | +| `Microsoft.Network/privateDnsZones/PTR` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/PTR) | +| `Microsoft.Network/privateDnsZones/SOA` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/SOA) | +| `Microsoft.Network/privateDnsZones/SRV` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/SRV) | +| `Microsoft.Network/privateDnsZones/TXT` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/TXT) | +| `Microsoft.Network/privateDnsZones/virtualNetworkLinks` | [2024-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-06-01/privateDnsZones/virtualNetworkLinks) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/private-dns-zone:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { + name: 'privateDnsZoneDeployment' + params: { + // Required parameters + name: 'npdzmin001.com' + // Non-required parameters + location: 'global' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npdzmin001.com" + }, + // Non-required parameters + "location": { + "value": "global" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-dns-zone:' + +// Required parameters +param name = 'npdzmin001.com' +// Non-required parameters +param location = 'global' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { + name: 'privateDnsZoneDeployment' + params: { + // Required parameters + name: 'npdzmax001.com' + // Non-required parameters + a: [ + { + aRecords: [ + { + ipv4Address: '10.240.4.4' + } + ] + name: 'A_10.240.4.4' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } + ] + aaaa: [ + { + aaaaRecords: [ + { + ipv6Address: '2001:0db8:85a3:0000:0000:8a2e:0370:7334' + } + ] + name: 'AAAA_2001_0db8_85a3_0000_0000_8a2e_0370_7334' + ttl: 3600 + } + ] + cname: [ + { + cnameRecord: { + cname: 'test' + } + name: 'CNAME_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } + ] + location: 'global' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + mx: [ + { + mxRecords: [ + { + exchange: 'contoso.com' + preference: 100 + } + ] + name: 'MX_contoso' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } + ] + ptr: [ + { + name: 'PTR_contoso' + ptrRecords: [ + { + ptrdname: 'contoso.com' + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } + ] + roleAssignments: [ + { + name: '8001f03c-2ca1-4dab-ab69-4dbaa3635af1' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + soa: [ + { + name: '@' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + soaRecord: { + email: 'azureprivatedns-host.microsoft.com' + expireTime: 2419200 + host: 'azureprivatedns.net' + minimumTtl: 10 + refreshTime: 3600 + retryTime: 300 + serialNumber: 1 + } + ttl: 3600 + } + ] + srv: [ + { + name: 'SRV_contoso' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + srvRecords: [ + { + port: 9332 + priority: 0 + target: 'test.contoso.com' + weight: 0 + } + ] + ttl: 3600 + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + txt: [ + { + name: 'TXT_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + txtRecords: [ + { + value: [ + 'test' + ] + } + ] + } + ] + virtualNetworkLinks: [ + { + registrationEnabled: true + virtualNetworkResourceId: '' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npdzmax001.com" + }, + // Non-required parameters + "a": { + "value": [ + { + "aRecords": [ + { + "ipv4Address": "10.240.4.4" + } + ], + "name": "A_10.240.4.4", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "ttl": 3600 + } + ] + }, + "aaaa": { + "value": [ + { + "aaaaRecords": [ + { + "ipv6Address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + ], + "name": "AAAA_2001_0db8_85a3_0000_0000_8a2e_0370_7334", + "ttl": 3600 + } + ] + }, + "cname": { + "value": [ + { + "cnameRecord": { + "cname": "test" + }, + "name": "CNAME_test", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "ttl": 3600 + } + ] + }, + "location": { + "value": "global" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "mx": { + "value": [ + { + "mxRecords": [ + { + "exchange": "contoso.com", + "preference": 100 + } + ], + "name": "MX_contoso", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "ttl": 3600 + } + ] + }, + "ptr": { + "value": [ + { + "name": "PTR_contoso", + "ptrRecords": [ + { + "ptrdname": "contoso.com" + } + ], + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "ttl": 3600 + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "8001f03c-2ca1-4dab-ab69-4dbaa3635af1", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "soa": { + "value": [ + { + "name": "@", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "soaRecord": { + "email": "azureprivatedns-host.microsoft.com", + "expireTime": 2419200, + "host": "azureprivatedns.net", + "minimumTtl": 10, + "refreshTime": 3600, + "retryTime": 300, + "serialNumber": 1 + }, + "ttl": 3600 + } + ] + }, + "srv": { + "value": [ + { + "name": "SRV_contoso", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "srvRecords": [ + { + "port": 9332, + "priority": 0, + "target": "test.contoso.com", + "weight": 0 + } + ], + "ttl": 3600 + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "txt": { + "value": [ + { + "name": "TXT_test", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "ttl": 3600, + "txtRecords": [ + { + "value": [ + "test" + ] + } + ] + } + ] + }, + "virtualNetworkLinks": { + "value": [ + { + "registrationEnabled": true, + "virtualNetworkResourceId": "" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-dns-zone:' + +// Required parameters +param name = 'npdzmax001.com' +// Non-required parameters +param a = [ + { + aRecords: [ + { + ipv4Address: '10.240.4.4' + } + ] + name: 'A_10.240.4.4' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param aaaa = [ + { + aaaaRecords: [ + { + ipv6Address: '2001:0db8:85a3:0000:0000:8a2e:0370:7334' + } + ] + name: 'AAAA_2001_0db8_85a3_0000_0000_8a2e_0370_7334' + ttl: 3600 + } +] +param cname = [ + { + cnameRecord: { + cname: 'test' + } + name: 'CNAME_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param mx = [ + { + mxRecords: [ + { + exchange: 'contoso.com' + preference: 100 + } + ] + name: 'MX_contoso' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param ptr = [ + { + name: 'PTR_contoso' + ptrRecords: [ + { + ptrdname: 'contoso.com' + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param roleAssignments = [ + { + name: '8001f03c-2ca1-4dab-ab69-4dbaa3635af1' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param soa = [ + { + name: '@' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + soaRecord: { + email: 'azureprivatedns-host.microsoft.com' + expireTime: 2419200 + host: 'azureprivatedns.net' + minimumTtl: 10 + refreshTime: 3600 + retryTime: 300 + serialNumber: 1 + } + ttl: 3600 + } +] +param srv = [ + { + name: 'SRV_contoso' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + srvRecords: [ + { + port: 9332 + priority: 0 + target: 'test.contoso.com' + weight: 0 + } + ] + ttl: 3600 + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param txt = [ + { + name: 'TXT_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + txtRecords: [ + { + value: [ + 'test' + ] + } + ] + } +] +param virtualNetworkLinks = [ + { + registrationEnabled: true + virtualNetworkResourceId: '' + } +] +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = { + name: 'privateDnsZoneDeployment' + params: { + // Required parameters + name: 'npdzwaf001.com' + // Non-required parameters + location: 'global' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npdzwaf001.com" + }, + // Non-required parameters + "location": { + "value": "global" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-dns-zone:' + +// Required parameters +param name = 'npdzwaf001.com' +// Non-required parameters +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Private DNS zone name. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`a`](#parameter-a) | array | Array of A records. | +| [`aaaa`](#parameter-aaaa) | array | Array of AAAA records. | +| [`cname`](#parameter-cname) | array | Array of CNAME records. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | The location of the PrivateDNSZone. Should be global. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`mx`](#parameter-mx) | array | Array of MX records. | +| [`ptr`](#parameter-ptr) | array | Array of PTR records. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`soa`](#parameter-soa) | array | Array of SOA records. | +| [`srv`](#parameter-srv) | array | Array of SRV records. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`txt`](#parameter-txt) | array | Array of TXT records. | +| [`virtualNetworkLinks`](#parameter-virtualnetworklinks) | array | Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet. | + +### Parameter: `name` + +Private DNS zone name. + +- Required: Yes +- Type: string + +### Parameter: `a` + +Array of A records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-aname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`aRecords`](#parameter-aarecords) | array | The list of A records in the record set. | +| [`metadata`](#parameter-ametadata) | object | The metadata of the record. | +| [`roleAssignments`](#parameter-aroleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-attl) | int | The TTL of the record. | + +### Parameter: `a.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `a.aRecords` + +The list of A records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipv4Address`](#parameter-aarecordsipv4address) | string | The IPv4 address of this A record. | + +### Parameter: `a.aRecords.ipv4Address` + +The IPv4 address of this A record. + +- Required: Yes +- Type: string + +### Parameter: `a.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `a.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-aroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-aroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-aroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-aroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-aroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-aroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-aroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-aroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `a.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `a.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `a.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `a.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `a.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `a.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `a.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `a.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `a.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `aaaa` + +Array of AAAA records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-aaaaname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`aaaaRecords`](#parameter-aaaaaaaarecords) | array | The list of AAAA records in the record set. | +| [`metadata`](#parameter-aaaametadata) | object | The metadata of the record. | +| [`roleAssignments`](#parameter-aaaaroleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-aaaattl) | int | The TTL of the record. | + +### Parameter: `aaaa.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `aaaa.aaaaRecords` + +The list of AAAA records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipv6Address`](#parameter-aaaaaaaarecordsipv6address) | string | The IPv6 address of this AAAA record. | + +### Parameter: `aaaa.aaaaRecords.ipv6Address` + +The IPv6 address of this AAAA record. + +- Required: Yes +- Type: string + +### Parameter: `aaaa.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `aaaa.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-aaaaroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-aaaaroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-aaaaroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-aaaaroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-aaaaroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-aaaaroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-aaaaroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-aaaaroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `aaaa.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `aaaa.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `aaaa.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `aaaa.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `aaaa.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `aaaa.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `aaaa.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `aaaa.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `aaaa.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `cname` + +Array of CNAME records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-cnamename) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`cnameRecord`](#parameter-cnamecnamerecord) | object | The CNAME record in the record set. | +| [`metadata`](#parameter-cnamemetadata) | object | The metadata of the record. | +| [`roleAssignments`](#parameter-cnameroleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-cnamettl) | int | The TTL of the record. | + +### Parameter: `cname.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `cname.cnameRecord` + +The CNAME record in the record set. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`cname`](#parameter-cnamecnamerecordcname) | string | The canonical name of the CNAME record. | + +### Parameter: `cname.cnameRecord.cname` + +The canonical name of the CNAME record. + +- Required: Yes +- Type: string + +### Parameter: `cname.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `cname.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-cnameroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-cnameroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-cnameroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-cnameroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-cnameroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-cnameroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-cnameroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-cnameroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `cname.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `cname.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `cname.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `cname.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `cname.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `cname.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `cname.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `cname.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `cname.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +The location of the PrivateDNSZone. Should be global. + +- Required: No +- Type: string +- Default: `'global'` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `mx` + +Array of MX records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-mxname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-mxmetadata) | object | The metadata of the record. | +| [`mxRecords`](#parameter-mxmxrecords) | array | The list of MX records in the record set. | +| [`roleAssignments`](#parameter-mxroleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-mxttl) | int | The TTL of the record. | + +### Parameter: `mx.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `mx.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `mx.mxRecords` + +The list of MX records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`exchange`](#parameter-mxmxrecordsexchange) | string | The domain name of the mail host for this MX record. | +| [`preference`](#parameter-mxmxrecordspreference) | int | The preference value for this MX record. | + +### Parameter: `mx.mxRecords.exchange` + +The domain name of the mail host for this MX record. + +- Required: Yes +- Type: string + +### Parameter: `mx.mxRecords.preference` + +The preference value for this MX record. + +- Required: Yes +- Type: int + +### Parameter: `mx.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-mxroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-mxroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-mxroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-mxroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-mxroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-mxroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-mxroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-mxroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `mx.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `mx.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `mx.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `mx.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `mx.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `mx.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `mx.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `mx.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `mx.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `ptr` + +Array of PTR records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-ptrname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-ptrmetadata) | object | The metadata of the record. | +| [`ptrRecords`](#parameter-ptrptrrecords) | array | The list of PTR records in the record set. | +| [`roleAssignments`](#parameter-ptrroleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-ptrttl) | int | The TTL of the record. | + +### Parameter: `ptr.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `ptr.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `ptr.ptrRecords` + +The list of PTR records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ptrdname`](#parameter-ptrptrrecordsptrdname) | string | The PTR target domain name for this PTR record. | + +### Parameter: `ptr.ptrRecords.ptrdname` + +The PTR target domain name for this PTR record. + +- Required: Yes +- Type: string + +### Parameter: `ptr.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-ptrroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-ptrroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-ptrroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-ptrroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-ptrroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-ptrroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-ptrroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-ptrroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `ptr.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `ptr.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `ptr.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `ptr.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `ptr.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `ptr.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `ptr.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `ptr.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ptr.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `soa` + +Array of SOA records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-soaname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-soametadata) | object | The metadata of the record. | +| [`roleAssignments`](#parameter-soaroleassignments) | array | Array of role assignments to create. | +| [`soaRecord`](#parameter-soasoarecord) | object | The SOA record in the record set. | +| [`ttl`](#parameter-soattl) | int | The TTL of the record. | + +### Parameter: `soa.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `soa.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `soa.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-soaroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-soaroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-soaroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-soaroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-soaroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-soaroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-soaroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-soaroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `soa.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `soa.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `soa.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `soa.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `soa.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `soa.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `soa.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `soa.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `soa.soaRecord` + +The SOA record in the record set. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`email`](#parameter-soasoarecordemail) | string | The email contact for this SOA record. | +| [`expireTime`](#parameter-soasoarecordexpiretime) | int | The expire time for this SOA record. | +| [`host`](#parameter-soasoarecordhost) | string | The domain name of the authoritative name server for this SOA record. | +| [`minimumTtl`](#parameter-soasoarecordminimumttl) | int | The minimum value for this SOA record. By convention this is used to determine the negative caching duration. | +| [`refreshTime`](#parameter-soasoarecordrefreshtime) | int | The refresh value for this SOA record. | +| [`retryTime`](#parameter-soasoarecordretrytime) | int | The retry time for this SOA record. | +| [`serialNumber`](#parameter-soasoarecordserialnumber) | int | The serial number for this SOA record. | + +### Parameter: `soa.soaRecord.email` + +The email contact for this SOA record. + +- Required: Yes +- Type: string + +### Parameter: `soa.soaRecord.expireTime` + +The expire time for this SOA record. + +- Required: Yes +- Type: int + +### Parameter: `soa.soaRecord.host` + +The domain name of the authoritative name server for this SOA record. + +- Required: Yes +- Type: string + +### Parameter: `soa.soaRecord.minimumTtl` + +The minimum value for this SOA record. By convention this is used to determine the negative caching duration. + +- Required: Yes +- Type: int + +### Parameter: `soa.soaRecord.refreshTime` + +The refresh value for this SOA record. + +- Required: Yes +- Type: int + +### Parameter: `soa.soaRecord.retryTime` + +The retry time for this SOA record. + +- Required: Yes +- Type: int + +### Parameter: `soa.soaRecord.serialNumber` + +The serial number for this SOA record. + +- Required: Yes +- Type: int + +### Parameter: `soa.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `srv` + +Array of SRV records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-srvname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-srvmetadata) | object | The metadata of the record. | +| [`roleAssignments`](#parameter-srvroleassignments) | array | Array of role assignments to create. | +| [`srvRecords`](#parameter-srvsrvrecords) | array | The list of SRV records in the record set. | +| [`ttl`](#parameter-srvttl) | int | The TTL of the record. | + +### Parameter: `srv.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `srv.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `srv.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-srvroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-srvroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-srvroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-srvroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-srvroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-srvroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-srvroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-srvroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `srv.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `srv.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `srv.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `srv.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `srv.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `srv.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `srv.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `srv.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `srv.srvRecords` + +The list of SRV records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`port`](#parameter-srvsrvrecordsport) | int | The port value for this SRV record. | +| [`priority`](#parameter-srvsrvrecordspriority) | int | The priority value for this SRV record. | +| [`target`](#parameter-srvsrvrecordstarget) | string | The target domain name for this SRV record. | +| [`weight`](#parameter-srvsrvrecordsweight) | int | The weight value for this SRV record. | + +### Parameter: `srv.srvRecords.port` + +The port value for this SRV record. + +- Required: Yes +- Type: int + +### Parameter: `srv.srvRecords.priority` + +The priority value for this SRV record. + +- Required: Yes +- Type: int + +### Parameter: `srv.srvRecords.target` + +The target domain name for this SRV record. + +- Required: Yes +- Type: string + +### Parameter: `srv.srvRecords.weight` + +The weight value for this SRV record. + +- Required: Yes +- Type: int + +### Parameter: `srv.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `txt` + +Array of TXT records. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-txtname) | string | The name of the record. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-txtmetadata) | object | The metadata of the record. | +| [`roleAssignments`](#parameter-txtroleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-txtttl) | int | The TTL of the record. | +| [`txtRecords`](#parameter-txttxtrecords) | array | The list of TXT records in the record set. | + +### Parameter: `txt.name` + +The name of the record. + +- Required: Yes +- Type: string + +### Parameter: `txt.metadata` + +The metadata of the record. + +- Required: No +- Type: object + +### Parameter: `txt.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-txtroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-txtroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-txtroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-txtroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-txtroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-txtroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-txtroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-txtroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `txt.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `txt.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `txt.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `txt.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `txt.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `txt.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `txt.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `txt.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `txt.ttl` + +The TTL of the record. + +- Required: No +- Type: int + +### Parameter: `txt.txtRecords` + +The list of TXT records in the record set. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`value`](#parameter-txttxtrecordsvalue) | array | The text value of this TXT record. | + +### Parameter: `txt.txtRecords.value` + +The text value of this TXT record. + +- Required: Yes +- Type: array + +### Parameter: `virtualNetworkLinks` + +Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`virtualNetworkResourceId`](#parameter-virtualnetworklinksvirtualnetworkresourceid) | string | The resource ID of the virtual network to link. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`location`](#parameter-virtualnetworklinkslocation) | string | The Azure Region where the resource lives. | +| [`name`](#parameter-virtualnetworklinksname) | string | The resource name. | +| [`registrationEnabled`](#parameter-virtualnetworklinksregistrationenabled) | bool | Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?. | +| [`resolutionPolicy`](#parameter-virtualnetworklinksresolutionpolicy) | string | The resolution type of the private-dns-zone fallback machanism. | +| [`tags`](#parameter-virtualnetworklinkstags) | object | Resource tags. | + +### Parameter: `virtualNetworkLinks.virtualNetworkResourceId` + +The resource ID of the virtual network to link. + +- Required: Yes +- Type: string + +### Parameter: `virtualNetworkLinks.location` + +The Azure Region where the resource lives. + +- Required: No +- Type: string + +### Parameter: `virtualNetworkLinks.name` + +The resource name. + +- Required: No +- Type: string + +### Parameter: `virtualNetworkLinks.registrationEnabled` + +Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?. + +- Required: No +- Type: bool + +### Parameter: `virtualNetworkLinks.resolutionPolicy` + +The resolution type of the private-dns-zone fallback machanism. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Default' + 'NxDomainRedirect' + ] + ``` + +### Parameter: `virtualNetworkLinks.tags` + +Resource tags. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the private DNS zone. | +| `resourceGroupName` | string | The resource group the private DNS zone was deployed into. | +| `resourceId` | string | The resource ID of the private DNS zone. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/private-dns-zone/a/README.md b/avm/1.1.0/res/network/private-dns-zone/a/README.md new file mode 100644 index 000000000..6584b4966 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/a/README.md @@ -0,0 +1,188 @@ +# Private DNS Zone A record `[Microsoft.Network/privateDnsZones/A]` + +This module deploys a Private DNS Zone A record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/privateDnsZones/A` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/A) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the A record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneName`](#parameter-privatednszonename) | string | The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`aRecords`](#parameter-arecords) | array | The list of A records in the record set. | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the A record. + +- Required: Yes +- Type: string + +### Parameter: `privateDnsZoneName` + +The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `aRecords` + +The list of A records in the record set. + +- Required: No +- Type: array + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed A record. | +| `resourceGroupName` | string | The resource group of the deployed A record. | +| `resourceId` | string | The resource ID of the deployed A record. | diff --git a/avm/1.1.0/res/network/private-dns-zone/a/main.bicep b/avm/1.1.0/res/network/private-dns-zone/a/main.bicep new file mode 100644 index 000000000..0f32527f4 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/a/main.bicep @@ -0,0 +1,122 @@ +metadata name = 'Private DNS Zone A record' +metadata description = 'This module deploys a Private DNS Zone A record.' + +@description('Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment.') +param privateDnsZoneName string + +@description('Required. The name of the A record.') +param name string + +@description('Optional. The list of A records in the record set.') +param aRecords array? + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = { + name: privateDnsZoneName +} + +resource A 'Microsoft.Network/privateDnsZones/A@2020-06-01' = { + name: name + parent: privateDnsZone + properties: { + aRecords: aRecords + metadata: metadata + ttl: ttl + } +} + +resource A_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(A.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: A + } +] + +@description('The name of the deployed A record.') +output name string = A.name + +@description('The resource ID of the deployed A record.') +output resourceId string = A.id + +@description('The resource group of the deployed A record.') +output resourceGroupName string = resourceGroup().name + +// ================ // +// Definitions // +// ================ // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/private-dns-zone/a/main.json b/avm/1.1.0/res/network/private-dns-zone/a/main.json new file mode 100644 index 000000000..40c36f937 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/a/main.json @@ -0,0 +1,211 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12329988072380606270" + }, + "name": "Private DNS Zone A record", + "description": "This module deploys a Private DNS Zone A record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the A record." + } + }, + "aRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of A records in the record set." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "A": { + "type": "Microsoft.Network/privateDnsZones/A", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "aRecords": "[parameters('aRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "A_roleAssignments": { + "copy": { + "name": "A_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/A/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "A" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed A record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed A record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed A record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-dns-zone/aaaa/README.md b/avm/1.1.0/res/network/private-dns-zone/aaaa/README.md new file mode 100644 index 000000000..01b9ca1fb --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/aaaa/README.md @@ -0,0 +1,188 @@ +# Private DNS Zone AAAA record `[Microsoft.Network/privateDnsZones/AAAA]` + +This module deploys a Private DNS Zone AAAA record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/privateDnsZones/AAAA` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/AAAA) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the AAAA record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneName`](#parameter-privatednszonename) | string | The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`aaaaRecords`](#parameter-aaaarecords) | array | The list of AAAA records in the record set. | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the AAAA record. + +- Required: Yes +- Type: string + +### Parameter: `privateDnsZoneName` + +The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `aaaaRecords` + +The list of AAAA records in the record set. + +- Required: No +- Type: array + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed AAAA record. | +| `resourceGroupName` | string | The resource group of the deployed AAAA record. | +| `resourceId` | string | The resource ID of the deployed AAAA record. | diff --git a/avm/1.1.0/res/network/private-dns-zone/aaaa/main.bicep b/avm/1.1.0/res/network/private-dns-zone/aaaa/main.bicep new file mode 100644 index 000000000..fae10b122 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/aaaa/main.bicep @@ -0,0 +1,122 @@ +metadata name = 'Private DNS Zone AAAA record' +metadata description = 'This module deploys a Private DNS Zone AAAA record.' + +@description('Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment.') +param privateDnsZoneName string + +@description('Required. The name of the AAAA record.') +param name string + +@description('Optional. The list of AAAA records in the record set.') +param aaaaRecords array? + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = { + name: privateDnsZoneName +} + +resource AAAA 'Microsoft.Network/privateDnsZones/AAAA@2020-06-01' = { + name: name + parent: privateDnsZone + properties: { + aaaaRecords: aaaaRecords + metadata: metadata + ttl: ttl + } +} + +resource AAAA_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(AAAA.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: AAAA + } +] + +@description('The name of the deployed AAAA record.') +output name string = AAAA.name + +@description('The resource ID of the deployed AAAA record.') +output resourceId string = AAAA.id + +@description('The resource group of the deployed AAAA record.') +output resourceGroupName string = resourceGroup().name + +// ================ // +// Definitions // +// ================ // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/private-dns-zone/aaaa/main.json b/avm/1.1.0/res/network/private-dns-zone/aaaa/main.json new file mode 100644 index 000000000..7191c8438 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/aaaa/main.json @@ -0,0 +1,211 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "18144761159622341175" + }, + "name": "Private DNS Zone AAAA record", + "description": "This module deploys a Private DNS Zone AAAA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the AAAA record." + } + }, + "aaaaRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of AAAA records in the record set." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "AAAA": { + "type": "Microsoft.Network/privateDnsZones/AAAA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "aaaaRecords": "[parameters('aaaaRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "AAAA_roleAssignments": { + "copy": { + "name": "AAAA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/AAAA/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "AAAA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed AAAA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed AAAA record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed AAAA record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-dns-zone/cname/README.md b/avm/1.1.0/res/network/private-dns-zone/cname/README.md new file mode 100644 index 000000000..bcabc2f0a --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/cname/README.md @@ -0,0 +1,188 @@ +# Private DNS Zone CNAME record `[Microsoft.Network/privateDnsZones/CNAME]` + +This module deploys a Private DNS Zone CNAME record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/privateDnsZones/CNAME` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/CNAME) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the CNAME record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneName`](#parameter-privatednszonename) | string | The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`cnameRecord`](#parameter-cnamerecord) | object | A CNAME record. | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the CNAME record. + +- Required: Yes +- Type: string + +### Parameter: `privateDnsZoneName` + +The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `cnameRecord` + +A CNAME record. + +- Required: No +- Type: object + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed CNAME record. | +| `resourceGroupName` | string | The resource group of the deployed CNAME record. | +| `resourceId` | string | The resource ID of the deployed CNAME record. | diff --git a/avm/1.1.0/res/network/private-dns-zone/cname/main.bicep b/avm/1.1.0/res/network/private-dns-zone/cname/main.bicep new file mode 100644 index 000000000..89fecb27b --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/cname/main.bicep @@ -0,0 +1,122 @@ +metadata name = 'Private DNS Zone CNAME record' +metadata description = 'This module deploys a Private DNS Zone CNAME record.' + +@description('Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment.') +param privateDnsZoneName string + +@description('Required. The name of the CNAME record.') +param name string + +@description('Optional. A CNAME record.') +param cnameRecord object? + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = { + name: privateDnsZoneName +} + +resource CNAME 'Microsoft.Network/privateDnsZones/CNAME@2020-06-01' = { + name: name + parent: privateDnsZone + properties: { + cnameRecord: cnameRecord + metadata: metadata + ttl: ttl + } +} + +resource CNAME_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(CNAME.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: CNAME + } +] + +@description('The name of the deployed CNAME record.') +output name string = CNAME.name + +@description('The resource ID of the deployed CNAME record.') +output resourceId string = CNAME.id + +@description('The resource group of the deployed CNAME record.') +output resourceGroupName string = resourceGroup().name + +// ================ // +// Definitions // +// ================ // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/private-dns-zone/cname/main.json b/avm/1.1.0/res/network/private-dns-zone/cname/main.json new file mode 100644 index 000000000..0512bb9a6 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/cname/main.json @@ -0,0 +1,211 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "8900024794567849685" + }, + "name": "Private DNS Zone CNAME record", + "description": "This module deploys a Private DNS Zone CNAME record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the CNAME record." + } + }, + "cnameRecord": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A CNAME record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "CNAME": { + "type": "Microsoft.Network/privateDnsZones/CNAME", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "cnameRecord": "[parameters('cnameRecord')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "CNAME_roleAssignments": { + "copy": { + "name": "CNAME_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/CNAME/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "CNAME" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed CNAME record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed CNAME record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed CNAME record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-dns-zone/main.bicep b/avm/1.1.0/res/network/private-dns-zone/main.bicep new file mode 100644 index 000000000..267165ce1 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/main.bicep @@ -0,0 +1,517 @@ +metadata name = 'Private DNS Zones' +metadata description = 'This module deploys a Private DNS zone.' + +@description('Required. Private DNS zone name.') +param name string + +@description('Optional. Array of A records.') +param a aType + +@description('Optional. Array of AAAA records.') +param aaaa aaaaType + +@description('Optional. Array of CNAME records.') +param cname cnameType + +@description('Optional. Array of MX records.') +param mx mxType + +@description('Optional. Array of PTR records.') +param ptr ptrType + +@description('Optional. Array of SOA records.') +param soa soaType + +@description('Optional. Array of SRV records.') +param srv srvType + +@description('Optional. Array of TXT records.') +param txt txtType + +@description('Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties \'virtualNetworkResourceId\' and \'registrationEnabled\'. The \'vnetResourceId\' is a resource ID of a vNet to link, \'registrationEnabled\' (bool) enables automatic DNS registration in the zone for the linked vNet.') +param virtualNetworkLinks virtualNetworkLinkType + +@description('Optional. The location of the PrivateDNSZone. Should be global.') +param location string = 'global' + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-privatednszone.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: name + location: location + tags: tags +} + +module privateDnsZone_A 'a/main.bicep' = [ + for (aRecord, index) in (a ?? []): { + name: '${uniqueString(deployment().name, location)}-PrivateDnsZone-ARecord-${index}' + params: { + privateDnsZoneName: privateDnsZone.name + name: aRecord.name + aRecords: aRecord.?aRecords + metadata: aRecord.?metadata + ttl: aRecord.?ttl ?? 3600 + roleAssignments: aRecord.?roleAssignments + } + } +] + +module privateDnsZone_AAAA 'aaaa/main.bicep' = [ + for (aaaaRecord, index) in (aaaa ?? []): { + name: '${uniqueString(deployment().name, location)}-PrivateDnsZone-AAAARecord-${index}' + params: { + privateDnsZoneName: privateDnsZone.name + name: aaaaRecord.name + aaaaRecords: aaaaRecord.?aaaaRecords + metadata: aaaaRecord.?metadata + ttl: aaaaRecord.?ttl ?? 3600 + roleAssignments: aaaaRecord.?roleAssignments + } + } +] + +module privateDnsZone_CNAME 'cname/main.bicep' = [ + for (cnameRecord, index) in (cname ?? []): { + name: '${uniqueString(deployment().name, location)}-PrivateDnsZone-CNAMERecord-${index}' + params: { + privateDnsZoneName: privateDnsZone.name + name: cnameRecord.name + cnameRecord: cnameRecord.?cnameRecord + metadata: cnameRecord.?metadata + ttl: cnameRecord.?ttl ?? 3600 + roleAssignments: cnameRecord.?roleAssignments + } + } +] + +module privateDnsZone_MX 'mx/main.bicep' = [ + for (mxRecord, index) in (mx ?? []): { + name: '${uniqueString(deployment().name, location)}-PrivateDnsZone-MXRecord-${index}' + params: { + privateDnsZoneName: privateDnsZone.name + name: mxRecord.name + metadata: mxRecord.?metadata + mxRecords: mxRecord.?mxRecords + ttl: mxRecord.?ttl ?? 3600 + roleAssignments: mxRecord.?roleAssignments + } + } +] + +module privateDnsZone_PTR 'ptr/main.bicep' = [ + for (ptrRecord, index) in (ptr ?? []): { + name: '${uniqueString(deployment().name, location)}-PrivateDnsZone-PTRRecord-${index}' + params: { + privateDnsZoneName: privateDnsZone.name + name: ptrRecord.name + metadata: ptrRecord.?metadata + ptrRecords: ptrRecord.?ptrRecords + ttl: ptrRecord.?ttl ?? 3600 + roleAssignments: ptrRecord.?roleAssignments + } + } +] + +module privateDnsZone_SOA 'soa/main.bicep' = [ + for (soaRecord, index) in (soa ?? []): { + name: '${uniqueString(deployment().name, location)}-PrivateDnsZone-SOARecord-${index}' + params: { + privateDnsZoneName: privateDnsZone.name + name: soaRecord.name + metadata: soaRecord.?metadata + soaRecord: soaRecord.?soaRecord + ttl: soaRecord.?ttl ?? 3600 + roleAssignments: soaRecord.?roleAssignments + } + } +] + +module privateDnsZone_SRV 'srv/main.bicep' = [ + for (srvRecord, index) in (srv ?? []): { + name: '${uniqueString(deployment().name, location)}-PrivateDnsZone-SRVRecord-${index}' + params: { + privateDnsZoneName: privateDnsZone.name + name: srvRecord.name + metadata: srvRecord.?metadata + srvRecords: srvRecord.?srvRecords + ttl: srvRecord.?ttl ?? 3600 + roleAssignments: srvRecord.?roleAssignments + } + } +] + +module privateDnsZone_TXT 'txt/main.bicep' = [ + for (txtRecord, index) in (txt ?? []): { + name: '${uniqueString(deployment().name, location)}-PrivateDnsZone-TXTRecord-${index}' + params: { + privateDnsZoneName: privateDnsZone.name + name: txtRecord.name + metadata: txtRecord.?metadata + txtRecords: txtRecord.?txtRecords + ttl: txtRecord.?ttl ?? 3600 + roleAssignments: txtRecord.?roleAssignments + } + } +] + +module privateDnsZone_virtualNetworkLinks 'virtual-network-link/main.bicep' = [ + for (virtualNetworkLink, index) in (virtualNetworkLinks ?? []): { + name: '${uniqueString(deployment().name, location)}-PrivateDnsZone-VirtualNetworkLink-${index}' + params: { + privateDnsZoneName: privateDnsZone.name + name: virtualNetworkLink.?name ?? '${last(split(virtualNetworkLink.virtualNetworkResourceId, '/'))}-vnetlink' + virtualNetworkResourceId: virtualNetworkLink.virtualNetworkResourceId + location: virtualNetworkLink.?location ?? 'global' + registrationEnabled: virtualNetworkLink.?registrationEnabled ?? false + tags: virtualNetworkLink.?tags ?? tags + resolutionPolicy: virtualNetworkLink.?resolutionPolicy + } + } +] + +resource privateDnsZone_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: privateDnsZone +} + +resource privateDnsZone_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(privateDnsZone.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: privateDnsZone + } +] + +@description('The resource group the private DNS zone was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the private DNS zone.') +output name string = privateDnsZone.name + +@description('The resource ID of the private DNS zone.') +output resourceId string = privateDnsZone.id + +@description('The location the resource was deployed into.') +output location string = privateDnsZone.location + +// ================ // +// Definitions // +// ================ // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type aType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The list of A records in the record set.') + aRecords: { + @description('Required. The IPv4 address of this A record.') + ipv4Address: string + }[]? +}[]? + +type aaaaType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The list of AAAA records in the record set.') + aaaaRecords: { + @description('Required. The IPv6 address of this AAAA record.') + ipv6Address: string + }[]? +}[]? + +type cnameType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The CNAME record in the record set.') + cnameRecord: { + @description('Required. The canonical name of the CNAME record.') + cname: string + }? +}[]? + +type mxType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The list of MX records in the record set.') + mxRecords: { + @description('Required. The domain name of the mail host for this MX record.') + exchange: string + + @description('Required. The preference value for this MX record.') + preference: int + }[]? +}[]? + +type ptrType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The list of PTR records in the record set.') + ptrRecords: { + @description('Required. The PTR target domain name for this PTR record.') + ptrdname: string + }[]? +}[]? + +type soaType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The SOA record in the record set.') + soaRecord: { + @description('Required. The email contact for this SOA record.') + email: string + + @description('Required. The expire time for this SOA record.') + expireTime: int + + @description('Required. The domain name of the authoritative name server for this SOA record.') + host: string + + @description('Required. The minimum value for this SOA record. By convention this is used to determine the negative caching duration.') + minimumTtl: int + + @description('Required. The refresh value for this SOA record.') + refreshTime: int + + @description('Required. The retry time for this SOA record.') + retryTime: int + + @description('Required. The serial number for this SOA record.') + serialNumber: int + }? +}[]? + +type srvType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The list of SRV records in the record set.') + srvRecords: { + @description('Required. The priority value for this SRV record.') + priority: int + + @description('Required. The weight value for this SRV record.') + weight: int + + @description('Required. The port value for this SRV record.') + port: int + + @description('Required. The target domain name for this SRV record.') + target: string + }[]? +}[]? + +type txtType = { + @description('Required. The name of the record.') + name: string + + @description('Optional. The metadata of the record.') + metadata: object? + + @description('Optional. The TTL of the record.') + ttl: int? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. The list of TXT records in the record set.') + txtRecords: { + @description('Required. The text value of this TXT record.') + value: string[] + }[]? +}[]? + +type virtualNetworkLinkType = { + @description('Optional. The resource name.') + @minLength(1) + @maxLength(80) + name: string? + + @description('Required. The resource ID of the virtual network to link.') + virtualNetworkResourceId: string + + @description('Optional. The Azure Region where the resource lives.') + location: string? + + @description('Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?.') + registrationEnabled: bool? + + @description('Optional. Resource tags.') + tags: object? + + @description('Optional. The resolution type of the private-dns-zone fallback machanism.') + resolutionPolicy: ('Default' | 'NxDomainRedirect')? +}[]? diff --git a/avm/1.1.0/res/network/private-dns-zone/main.json b/avm/1.1.0/res/network/private-dns-zone/main.json new file mode 100644 index 000000000..e6e100397 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/main.json @@ -0,0 +1,3006 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "2710025845349133598" + }, + "name": "Private DNS Zones", + "description": "This module deploys a Private DNS zone." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "aType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "aRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipv4Address": { + "type": "string", + "metadata": { + "description": "Required. The IPv4 address of this A record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of A records in the record set." + } + } + } + }, + "nullable": true + }, + "aaaaType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "aaaaRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ipv6Address": { + "type": "string", + "metadata": { + "description": "Required. The IPv6 address of this AAAA record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of AAAA records in the record set." + } + } + } + }, + "nullable": true + }, + "cnameType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "cnameRecord": { + "type": "object", + "properties": { + "cname": { + "type": "string", + "metadata": { + "description": "Required. The canonical name of the CNAME record." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The CNAME record in the record set." + } + } + } + }, + "nullable": true + }, + "mxType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "mxRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "exchange": { + "type": "string", + "metadata": { + "description": "Required. The domain name of the mail host for this MX record." + } + }, + "preference": { + "type": "int", + "metadata": { + "description": "Required. The preference value for this MX record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of MX records in the record set." + } + } + } + }, + "nullable": true + }, + "ptrType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "ptrRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ptrdname": { + "type": "string", + "metadata": { + "description": "Required. The PTR target domain name for this PTR record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of PTR records in the record set." + } + } + } + }, + "nullable": true + }, + "soaType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "soaRecord": { + "type": "object", + "properties": { + "email": { + "type": "string", + "metadata": { + "description": "Required. The email contact for this SOA record." + } + }, + "expireTime": { + "type": "int", + "metadata": { + "description": "Required. The expire time for this SOA record." + } + }, + "host": { + "type": "string", + "metadata": { + "description": "Required. The domain name of the authoritative name server for this SOA record." + } + }, + "minimumTtl": { + "type": "int", + "metadata": { + "description": "Required. The minimum value for this SOA record. By convention this is used to determine the negative caching duration." + } + }, + "refreshTime": { + "type": "int", + "metadata": { + "description": "Required. The refresh value for this SOA record." + } + }, + "retryTime": { + "type": "int", + "metadata": { + "description": "Required. The retry time for this SOA record." + } + }, + "serialNumber": { + "type": "int", + "metadata": { + "description": "Required. The serial number for this SOA record." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The SOA record in the record set." + } + } + } + }, + "nullable": true + }, + "srvType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "srvRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "priority": { + "type": "int", + "metadata": { + "description": "Required. The priority value for this SRV record." + } + }, + "weight": { + "type": "int", + "metadata": { + "description": "Required. The weight value for this SRV record." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. The port value for this SRV record." + } + }, + "target": { + "type": "string", + "metadata": { + "description": "Required. The target domain name for this SRV record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of SRV records in the record set." + } + } + } + }, + "nullable": true + }, + "txtType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata of the record." + } + }, + "ttl": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The TTL of the record." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "txtRecords": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The text value of this TXT record." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of TXT records in the record set." + } + } + } + }, + "nullable": true + }, + "virtualNetworkLinkType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 80, + "metadata": { + "description": "Optional. The resource name." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the virtual network to link." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Region where the resource lives." + } + }, + "registrationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "resolutionPolicy": { + "type": "string", + "allowedValues": [ + "Default", + "NxDomainRedirect" + ], + "nullable": true, + "metadata": { + "description": "Optional. The resolution type of the private-dns-zone fallback machanism." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Private DNS zone name." + } + }, + "a": { + "$ref": "#/definitions/aType", + "metadata": { + "description": "Optional. Array of A records." + } + }, + "aaaa": { + "$ref": "#/definitions/aaaaType", + "metadata": { + "description": "Optional. Array of AAAA records." + } + }, + "cname": { + "$ref": "#/definitions/cnameType", + "metadata": { + "description": "Optional. Array of CNAME records." + } + }, + "mx": { + "$ref": "#/definitions/mxType", + "metadata": { + "description": "Optional. Array of MX records." + } + }, + "ptr": { + "$ref": "#/definitions/ptrType", + "metadata": { + "description": "Optional. Array of PTR records." + } + }, + "soa": { + "$ref": "#/definitions/soaType", + "metadata": { + "description": "Optional. Array of SOA records." + } + }, + "srv": { + "$ref": "#/definitions/srvType", + "metadata": { + "description": "Optional. Array of SRV records." + } + }, + "txt": { + "$ref": "#/definitions/txtType", + "metadata": { + "description": "Optional. Array of TXT records." + } + }, + "virtualNetworkLinks": { + "$ref": "#/definitions/virtualNetworkLinkType", + "metadata": { + "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "privateDnsZone_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_roleAssignments": { + "copy": { + "name": "privateDnsZone_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_A": { + "copy": { + "name": "privateDnsZone_A", + "count": "[length(coalesce(parameters('a'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" + }, + "aRecords": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12329988072380606270" + }, + "name": "Private DNS Zone A record", + "description": "This module deploys a Private DNS Zone A record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the A record." + } + }, + "aRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of A records in the record set." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "A": { + "type": "Microsoft.Network/privateDnsZones/A", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "aRecords": "[parameters('aRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "A_roleAssignments": { + "copy": { + "name": "A_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/A/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "A" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed A record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed A record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed A record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_AAAA": { + "copy": { + "name": "privateDnsZone_AAAA", + "count": "[length(coalesce(parameters('aaaa'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" + }, + "aaaaRecords": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "18144761159622341175" + }, + "name": "Private DNS Zone AAAA record", + "description": "This module deploys a Private DNS Zone AAAA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the AAAA record." + } + }, + "aaaaRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of AAAA records in the record set." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "AAAA": { + "type": "Microsoft.Network/privateDnsZones/AAAA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "aaaaRecords": "[parameters('aaaaRecords')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "AAAA_roleAssignments": { + "copy": { + "name": "AAAA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/AAAA/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "AAAA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed AAAA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed AAAA record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed AAAA record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_CNAME": { + "copy": { + "name": "privateDnsZone_CNAME", + "count": "[length(coalesce(parameters('cname'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" + }, + "cnameRecord": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "8900024794567849685" + }, + "name": "Private DNS Zone CNAME record", + "description": "This module deploys a Private DNS Zone CNAME record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the CNAME record." + } + }, + "cnameRecord": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A CNAME record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "CNAME": { + "type": "Microsoft.Network/privateDnsZones/CNAME", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "cnameRecord": "[parameters('cnameRecord')]", + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]" + } + }, + "CNAME_roleAssignments": { + "copy": { + "name": "CNAME_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/CNAME/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "CNAME" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed CNAME record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed CNAME record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed CNAME record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_MX": { + "copy": { + "name": "privateDnsZone_MX", + "count": "[length(coalesce(parameters('mx'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" + }, + "mxRecords": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10186845181379684291" + }, + "name": "Private DNS Zone MX record", + "description": "This module deploys a Private DNS Zone MX record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the MX record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "mxRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of MX records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "MX": { + "type": "Microsoft.Network/privateDnsZones/MX", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "mxRecords": "[parameters('mxRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "MX_roleAssignments": { + "copy": { + "name": "MX_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/MX/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "MX" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed MX record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed MX record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed MX record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_PTR": { + "copy": { + "name": "privateDnsZone_PTR", + "count": "[length(coalesce(parameters('ptr'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" + }, + "ptrRecords": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12397116547796665355" + }, + "name": "Private DNS Zone PTR record", + "description": "This module deploys a Private DNS Zone PTR record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the PTR record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ptrRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of PTR records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "PTR": { + "type": "Microsoft.Network/privateDnsZones/PTR", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "ptrRecords": "[parameters('ptrRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "PTR_roleAssignments": { + "copy": { + "name": "PTR_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/PTR/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "PTR" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed PTR record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed PTR record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed PTR record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_SOA": { + "copy": { + "name": "privateDnsZone_SOA", + "count": "[length(coalesce(parameters('soa'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" + }, + "soaRecord": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9828503900264294678" + }, + "name": "Private DNS Zone SOA record", + "description": "This module deploys a Private DNS Zone SOA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SOA record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "soaRecord": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A SOA record." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SOA": { + "type": "Microsoft.Network/privateDnsZones/SOA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "soaRecord": "[parameters('soaRecord')]", + "ttl": "[parameters('ttl')]" + } + }, + "SOA_roleAssignments": { + "copy": { + "name": "SOA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/SOA/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SOA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SOA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SOA record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SOA record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_SRV": { + "copy": { + "name": "privateDnsZone_SRV", + "count": "[length(coalesce(parameters('srv'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" + }, + "srvRecords": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9015292509771221683" + }, + "name": "Private DNS Zone SRV record", + "description": "This module deploys a Private DNS Zone SRV record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SRV record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "srvRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of SRV records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SRV": { + "type": "Microsoft.Network/privateDnsZones/SRV", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "srvRecords": "[parameters('srvRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "SRV_roleAssignments": { + "copy": { + "name": "SRV_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/SRV/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SRV" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SRV record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SRV record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SRV record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_TXT": { + "copy": { + "name": "privateDnsZone_TXT", + "count": "[length(coalesce(parameters('txt'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" + }, + "txtRecords": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" + }, + "ttl": { + "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "816236401965037598" + }, + "name": "Private DNS Zone TXT record", + "description": "This module deploys a Private DNS Zone TXT record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the TXT record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "txtRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of TXT records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "TXT": { + "type": "Microsoft.Network/privateDnsZones/TXT", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]", + "txtRecords": "[parameters('txtRecords')]" + } + }, + "TXT_roleAssignments": { + "copy": { + "name": "TXT_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/TXT/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "TXT" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed TXT record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed TXT record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed TXT record." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + }, + "privateDnsZone_virtualNetworkLinks": { + "copy": { + "name": "privateDnsZone_virtualNetworkLinks", + "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-VirtualNetworkLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" + }, + "virtualNetworkResourceId": { + "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" + }, + "registrationEnabled": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "resolutionPolicy": { + "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15937807282215500764" + }, + "name": "Private DNS Zone Virtual Network Link", + "description": "This module deploys a Private DNS Zone Virtual Network Link." + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "registrationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + }, + "resolutionPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." + } + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "registrationEnabled": "[parameters('registrationEnabled')]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + }, + "resolutionPolicy": "[parameters('resolutionPolicy')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private DNS zone." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private DNS zone." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-dns-zone/mx/README.md b/avm/1.1.0/res/network/private-dns-zone/mx/README.md new file mode 100644 index 000000000..721b698cc --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/mx/README.md @@ -0,0 +1,188 @@ +# Private DNS Zone MX record `[Microsoft.Network/privateDnsZones/MX]` + +This module deploys a Private DNS Zone MX record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/privateDnsZones/MX` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/MX) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the MX record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneName`](#parameter-privatednszonename) | string | The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`mxRecords`](#parameter-mxrecords) | array | The list of MX records in the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the MX record. + +- Required: Yes +- Type: string + +### Parameter: `privateDnsZoneName` + +The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `mxRecords` + +The list of MX records in the record set. + +- Required: No +- Type: array + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed MX record. | +| `resourceGroupName` | string | The resource group of the deployed MX record. | +| `resourceId` | string | The resource ID of the deployed MX record. | diff --git a/avm/1.1.0/res/network/private-dns-zone/mx/main.bicep b/avm/1.1.0/res/network/private-dns-zone/mx/main.bicep new file mode 100644 index 000000000..911e0daf2 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/mx/main.bicep @@ -0,0 +1,122 @@ +metadata name = 'Private DNS Zone MX record' +metadata description = 'This module deploys a Private DNS Zone MX record.' + +@description('Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment.') +param privateDnsZoneName string + +@description('Required. The name of the MX record.') +param name string + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The list of MX records in the record set.') +param mxRecords array? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = { + name: privateDnsZoneName +} + +resource MX 'Microsoft.Network/privateDnsZones/MX@2020-06-01' = { + name: name + parent: privateDnsZone + properties: { + metadata: metadata + mxRecords: mxRecords + ttl: ttl + } +} + +resource MX_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(MX.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: MX + } +] + +@description('The name of the deployed MX record.') +output name string = MX.name + +@description('The resource ID of the deployed MX record.') +output resourceId string = MX.id + +@description('The resource group of the deployed MX record.') +output resourceGroupName string = resourceGroup().name + +// ================ // +// Definitions // +// ================ // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/private-dns-zone/mx/main.json b/avm/1.1.0/res/network/private-dns-zone/mx/main.json new file mode 100644 index 000000000..b5cdc2b7e --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/mx/main.json @@ -0,0 +1,211 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "10186845181379684291" + }, + "name": "Private DNS Zone MX record", + "description": "This module deploys a Private DNS Zone MX record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the MX record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "mxRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of MX records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "MX": { + "type": "Microsoft.Network/privateDnsZones/MX", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "mxRecords": "[parameters('mxRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "MX_roleAssignments": { + "copy": { + "name": "MX_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/MX/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "MX" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed MX record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed MX record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed MX record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-dns-zone/ptr/README.md b/avm/1.1.0/res/network/private-dns-zone/ptr/README.md new file mode 100644 index 000000000..0c8d412a5 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/ptr/README.md @@ -0,0 +1,188 @@ +# Private DNS Zone PTR record `[Microsoft.Network/privateDnsZones/PTR]` + +This module deploys a Private DNS Zone PTR record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/privateDnsZones/PTR` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/PTR) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the PTR record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneName`](#parameter-privatednszonename) | string | The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`ptrRecords`](#parameter-ptrrecords) | array | The list of PTR records in the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the PTR record. + +- Required: Yes +- Type: string + +### Parameter: `privateDnsZoneName` + +The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `ptrRecords` + +The list of PTR records in the record set. + +- Required: No +- Type: array + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed PTR record. | +| `resourceGroupName` | string | The resource group of the deployed PTR record. | +| `resourceId` | string | The resource ID of the deployed PTR record. | diff --git a/avm/1.1.0/res/network/private-dns-zone/ptr/main.bicep b/avm/1.1.0/res/network/private-dns-zone/ptr/main.bicep new file mode 100644 index 000000000..7c2c622cc --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/ptr/main.bicep @@ -0,0 +1,122 @@ +metadata name = 'Private DNS Zone PTR record' +metadata description = 'This module deploys a Private DNS Zone PTR record.' + +@description('Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment.') +param privateDnsZoneName string + +@description('Required. The name of the PTR record.') +param name string + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The list of PTR records in the record set.') +param ptrRecords array? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = { + name: privateDnsZoneName +} + +resource PTR 'Microsoft.Network/privateDnsZones/PTR@2020-06-01' = { + name: name + parent: privateDnsZone + properties: { + metadata: metadata + ptrRecords: ptrRecords + ttl: ttl + } +} + +resource PTR_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(PTR.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: PTR + } +] + +@description('The name of the deployed PTR record.') +output name string = PTR.name + +@description('The resource ID of the deployed PTR record.') +output resourceId string = PTR.id + +@description('The resource group of the deployed PTR record.') +output resourceGroupName string = resourceGroup().name + +// ================ // +// Definitions // +// ================ // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/private-dns-zone/ptr/main.json b/avm/1.1.0/res/network/private-dns-zone/ptr/main.json new file mode 100644 index 000000000..3e22f46ba --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/ptr/main.json @@ -0,0 +1,211 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "12397116547796665355" + }, + "name": "Private DNS Zone PTR record", + "description": "This module deploys a Private DNS Zone PTR record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the PTR record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ptrRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of PTR records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "PTR": { + "type": "Microsoft.Network/privateDnsZones/PTR", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "ptrRecords": "[parameters('ptrRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "PTR_roleAssignments": { + "copy": { + "name": "PTR_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/PTR/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "PTR" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed PTR record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed PTR record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed PTR record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-dns-zone/soa/README.md b/avm/1.1.0/res/network/private-dns-zone/soa/README.md new file mode 100644 index 000000000..fd6c40a7f --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/soa/README.md @@ -0,0 +1,188 @@ +# Private DNS Zone SOA record `[Microsoft.Network/privateDnsZones/SOA]` + +This module deploys a Private DNS Zone SOA record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/privateDnsZones/SOA` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/SOA) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the SOA record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneName`](#parameter-privatednszonename) | string | The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`soaRecord`](#parameter-soarecord) | object | A SOA record. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the SOA record. + +- Required: Yes +- Type: string + +### Parameter: `privateDnsZoneName` + +The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `soaRecord` + +A SOA record. + +- Required: No +- Type: object + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed SOA record. | +| `resourceGroupName` | string | The resource group of the deployed SOA record. | +| `resourceId` | string | The resource ID of the deployed SOA record. | diff --git a/avm/1.1.0/res/network/private-dns-zone/soa/main.bicep b/avm/1.1.0/res/network/private-dns-zone/soa/main.bicep new file mode 100644 index 000000000..33abf4493 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/soa/main.bicep @@ -0,0 +1,122 @@ +metadata name = 'Private DNS Zone SOA record' +metadata description = 'This module deploys a Private DNS Zone SOA record.' + +@description('Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment.') +param privateDnsZoneName string + +@description('Required. The name of the SOA record.') +param name string + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. A SOA record.') +param soaRecord object? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = { + name: privateDnsZoneName +} + +resource SOA 'Microsoft.Network/privateDnsZones/SOA@2020-06-01' = { + name: name + parent: privateDnsZone + properties: { + metadata: metadata + soaRecord: soaRecord + ttl: ttl + } +} + +resource SOA_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(SOA.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: SOA + } +] + +@description('The name of the deployed SOA record.') +output name string = SOA.name + +@description('The resource ID of the deployed SOA record.') +output resourceId string = SOA.id + +@description('The resource group of the deployed SOA record.') +output resourceGroupName string = resourceGroup().name + +// ================ // +// Definitions // +// ================ // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/private-dns-zone/soa/main.json b/avm/1.1.0/res/network/private-dns-zone/soa/main.json new file mode 100644 index 000000000..00cda9bde --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/soa/main.json @@ -0,0 +1,211 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9828503900264294678" + }, + "name": "Private DNS Zone SOA record", + "description": "This module deploys a Private DNS Zone SOA record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SOA record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "soaRecord": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A SOA record." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SOA": { + "type": "Microsoft.Network/privateDnsZones/SOA", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "soaRecord": "[parameters('soaRecord')]", + "ttl": "[parameters('ttl')]" + } + }, + "SOA_roleAssignments": { + "copy": { + "name": "SOA_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/SOA/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SOA" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SOA record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SOA record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SOA record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-dns-zone/srv/README.md b/avm/1.1.0/res/network/private-dns-zone/srv/README.md new file mode 100644 index 000000000..a6047c6bd --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/srv/README.md @@ -0,0 +1,188 @@ +# Private DNS Zone SRV record `[Microsoft.Network/privateDnsZones/SRV]` + +This module deploys a Private DNS Zone SRV record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/privateDnsZones/SRV` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/SRV) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the SRV record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneName`](#parameter-privatednszonename) | string | The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`srvRecords`](#parameter-srvrecords) | array | The list of SRV records in the record set. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | + +### Parameter: `name` + +The name of the SRV record. + +- Required: Yes +- Type: string + +### Parameter: `privateDnsZoneName` + +The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `srvRecords` + +The list of SRV records in the record set. + +- Required: No +- Type: array + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed SRV record. | +| `resourceGroupName` | string | The resource group of the deployed SRV record. | +| `resourceId` | string | The resource ID of the deployed SRV record. | diff --git a/avm/1.1.0/res/network/private-dns-zone/srv/main.bicep b/avm/1.1.0/res/network/private-dns-zone/srv/main.bicep new file mode 100644 index 000000000..f6e5acdb5 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/srv/main.bicep @@ -0,0 +1,122 @@ +metadata name = 'Private DNS Zone SRV record' +metadata description = 'This module deploys a Private DNS Zone SRV record.' + +@description('Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment.') +param privateDnsZoneName string + +@description('Required. The name of the SRV record.') +param name string + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The list of SRV records in the record set.') +param srvRecords array? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = { + name: privateDnsZoneName +} + +resource SRV 'Microsoft.Network/privateDnsZones/SRV@2020-06-01' = { + name: name + parent: privateDnsZone + properties: { + metadata: metadata + srvRecords: srvRecords + ttl: ttl + } +} + +resource SRV_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(SRV.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: SRV + } +] + +@description('The name of the deployed SRV record.') +output name string = SRV.name + +@description('The resource ID of the deployed SRV record.') +output resourceId string = SRV.id + +@description('The resource group of the deployed SRV record.') +output resourceGroupName string = resourceGroup().name + +// ================ // +// Definitions // +// ================ // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/private-dns-zone/srv/main.json b/avm/1.1.0/res/network/private-dns-zone/srv/main.json new file mode 100644 index 000000000..584f1d5a8 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/srv/main.json @@ -0,0 +1,211 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9015292509771221683" + }, + "name": "Private DNS Zone SRV record", + "description": "This module deploys a Private DNS Zone SRV record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the SRV record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "srvRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of SRV records in the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "SRV": { + "type": "Microsoft.Network/privateDnsZones/SRV", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "srvRecords": "[parameters('srvRecords')]", + "ttl": "[parameters('ttl')]" + } + }, + "SRV_roleAssignments": { + "copy": { + "name": "SRV_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/SRV/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "SRV" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed SRV record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed SRV record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed SRV record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-dns-zone/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/private-dns-zone/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..81053892b --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.privatednszones-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npdzmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001.com' + location: 'global' + } + } +] diff --git a/avm/1.1.0/res/network/private-dns-zone/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/private-dns-zone/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..f4ff1fbf5 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/tests/e2e/max/dependencies.bicep @@ -0,0 +1,41 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/private-dns-zone/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/private-dns-zone/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..006a3842b --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/tests/e2e/max/main.test.bicep @@ -0,0 +1,332 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.privatednszones-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npdzmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001.com' + location: 'global' + a: [ + { + name: 'A_10.240.4.4' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + + aRecords: [ + { + ipv4Address: '10.240.4.4' + } + ] + } + ] + aaaa: [ + { + name: 'AAAA_2001_0db8_85a3_0000_0000_8a2e_0370_7334' + ttl: 3600 + aaaaRecords: [ + { + ipv6Address: '2001:0db8:85a3:0000:0000:8a2e:0370:7334' + } + ] + } + ] + cname: [ + { + name: 'CNAME_test' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + cnameRecord: { + cname: 'test' + } + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + mx: [ + { + name: 'MX_contoso' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + mxRecords: [ + { + exchange: 'contoso.com' + preference: 100 + } + ] + } + ] + ptr: [ + { + name: 'PTR_contoso' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + ptrRecords: [ + { + ptrdname: 'contoso.com' + } + ] + } + ] + roleAssignments: [ + { + name: '8001f03c-2ca1-4dab-ab69-4dbaa3635af1' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + soa: [ + { + name: '@' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + soaRecord: { + email: 'azureprivatedns-host.microsoft.com' + expireTime: 2419200 + host: 'azureprivatedns.net' + minimumTtl: 10 + refreshTime: 3600 + retryTime: 300 + serialNumber: 1 + } + } + ] + srv: [ + { + name: 'SRV_contoso' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + srvRecords: [ + { + port: 9332 + priority: 0 + target: 'test.contoso.com' + weight: 0 + } + ] + } + ] + txt: [ + { + name: 'TXT_test' + ttl: 3600 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + txtRecords: [ + { + value: [ + 'test' + ] + } + ] + } + ] + virtualNetworkLinks: [ + { + registrationEnabled: true + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/private-dns-zone/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/private-dns-zone/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..f4ff1fbf5 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,41 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/private-dns-zone/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/private-dns-zone/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..465cc291d --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,67 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.privatednszones-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npdzwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001.com' + location: 'global' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + } + } +] diff --git a/avm/1.1.0/res/network/private-dns-zone/txt/README.md b/avm/1.1.0/res/network/private-dns-zone/txt/README.md new file mode 100644 index 000000000..2121b15b1 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/txt/README.md @@ -0,0 +1,188 @@ +# Private DNS Zone TXT record `[Microsoft.Network/privateDnsZones/TXT]` + +This module deploys a Private DNS Zone TXT record. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/privateDnsZones/TXT` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/TXT) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the TXT record. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneName`](#parameter-privatednszonename) | string | The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-metadata) | object | The metadata attached to the record set. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`ttl`](#parameter-ttl) | int | The TTL (time-to-live) of the records in the record set. | +| [`txtRecords`](#parameter-txtrecords) | array | The list of TXT records in the record set. | + +### Parameter: `name` + +The name of the TXT record. + +- Required: Yes +- Type: string + +### Parameter: `privateDnsZoneName` + +The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `metadata` + +The metadata attached to the record set. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `ttl` + +The TTL (time-to-live) of the records in the record set. + +- Required: No +- Type: int +- Default: `3600` + +### Parameter: `txtRecords` + +The list of TXT records in the record set. + +- Required: No +- Type: array + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed TXT record. | +| `resourceGroupName` | string | The resource group of the deployed TXT record. | +| `resourceId` | string | The resource ID of the deployed TXT record. | diff --git a/avm/1.1.0/res/network/private-dns-zone/txt/main.bicep b/avm/1.1.0/res/network/private-dns-zone/txt/main.bicep new file mode 100644 index 000000000..0f4f971b4 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/txt/main.bicep @@ -0,0 +1,122 @@ +metadata name = 'Private DNS Zone TXT record' +metadata description = 'This module deploys a Private DNS Zone TXT record.' + +@description('Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment.') +param privateDnsZoneName string + +@description('Required. The name of the TXT record.') +param name string + +@description('Optional. The metadata attached to the record set.') +param metadata object? + +@description('Optional. The TTL (time-to-live) of the records in the record set.') +param ttl int = 3600 + +@description('Optional. The list of TXT records in the record set.') +param txtRecords array? + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = { + name: privateDnsZoneName +} + +resource TXT 'Microsoft.Network/privateDnsZones/TXT@2020-06-01' = { + name: name + parent: privateDnsZone + properties: { + metadata: metadata + ttl: ttl + txtRecords: txtRecords + } +} + +resource TXT_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(TXT.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: TXT + } +] + +@description('The name of the deployed TXT record.') +output name string = TXT.name + +@description('The resource ID of the deployed TXT record.') +output resourceId string = TXT.id + +@description('The resource group of the deployed TXT record.') +output resourceGroupName string = resourceGroup().name + +// ================ // +// Definitions // +// ================ // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/private-dns-zone/txt/main.json b/avm/1.1.0/res/network/private-dns-zone/txt/main.json new file mode 100644 index 000000000..ff2fa9de4 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/txt/main.json @@ -0,0 +1,211 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "816236401965037598" + }, + "name": "Private DNS Zone TXT record", + "description": "This module deploys a Private DNS Zone TXT record." + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the TXT record." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The metadata attached to the record set." + } + }, + "ttl": { + "type": "int", + "defaultValue": 3600, + "metadata": { + "description": "Optional. The TTL (time-to-live) of the records in the record set." + } + }, + "txtRecords": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of TXT records in the record set." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "TXT": { + "type": "Microsoft.Network/privateDnsZones/TXT", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]", + "ttl": "[parameters('ttl')]", + "txtRecords": "[parameters('txtRecords')]" + } + }, + "TXT_roleAssignments": { + "copy": { + "name": "TXT_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateDnsZones/{0}/TXT/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "TXT" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed TXT record." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed TXT record." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed TXT record." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-dns-zone/version.json b/avm/1.1.0/res/network/private-dns-zone/version.json new file mode 100644 index 000000000..09c3664ce --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.7", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-dns-zone/virtual-network-link/README.md b/avm/1.1.0/res/network/private-dns-zone/virtual-network-link/README.md new file mode 100644 index 000000000..ef310045a --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/virtual-network-link/README.md @@ -0,0 +1,100 @@ +# Private DNS Zone Virtual Network Link `[Microsoft.Network/privateDnsZones/virtualNetworkLinks]` + +This module deploys a Private DNS Zone Virtual Network Link. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/privateDnsZones/virtualNetworkLinks` | [2024-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-06-01/privateDnsZones/virtualNetworkLinks) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`virtualNetworkResourceId`](#parameter-virtualnetworkresourceid) | string | Link to another virtual network resource ID. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneName`](#parameter-privatednszonename) | string | The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`location`](#parameter-location) | string | The location of the PrivateDNSZone. Should be global. | +| [`name`](#parameter-name) | string | The name of the virtual network link. | +| [`registrationEnabled`](#parameter-registrationenabled) | bool | Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?. | +| [`resolutionPolicy`](#parameter-resolutionpolicy) | string | The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `virtualNetworkResourceId` + +Link to another virtual network resource ID. + +- Required: Yes +- Type: string + +### Parameter: `privateDnsZoneName` + +The name of the parent Private DNS zone. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `location` + +The location of the PrivateDNSZone. Should be global. + +- Required: No +- Type: string +- Default: `'global'` + +### Parameter: `name` + +The name of the virtual network link. + +- Required: No +- Type: string +- Default: `[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]` + +### Parameter: `registrationEnabled` + +Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `resolutionPolicy` + +The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option. + +- Required: No +- Type: string + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed virtual network link. | +| `resourceGroupName` | string | The resource group of the deployed virtual network link. | +| `resourceId` | string | The resource ID of the deployed virtual network link. | diff --git a/avm/1.1.0/res/network/private-dns-zone/virtual-network-link/main.bicep b/avm/1.1.0/res/network/private-dns-zone/virtual-network-link/main.bicep new file mode 100644 index 000000000..e977e8d78 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/virtual-network-link/main.bicep @@ -0,0 +1,53 @@ +metadata name = 'Private DNS Zone Virtual Network Link' +metadata description = 'This module deploys a Private DNS Zone Virtual Network Link.' + +@description('Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment.') +param privateDnsZoneName string + +@description('Optional. The name of the virtual network link.') +param name string = '${last(split(virtualNetworkResourceId, '/'))}-vnetlink' + +@description('Optional. The location of the PrivateDNSZone. Should be global.') +param location string = 'global' + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?.') +param registrationEnabled bool = false + +@description('Required. Link to another virtual network resource ID.') +param virtualNetworkResourceId string + +@description('Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option.') +param resolutionPolicy string? + +resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = { + name: privateDnsZoneName +} + +resource virtualNetworkLink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01' = { + name: name + parent: privateDnsZone + location: location + tags: tags + properties: { + registrationEnabled: registrationEnabled + virtualNetwork: { + id: virtualNetworkResourceId + } + resolutionPolicy: resolutionPolicy + } +} + +@description('The name of the deployed virtual network link.') +output name string = virtualNetworkLink.name + +@description('The resource ID of the deployed virtual network link.') +output resourceId string = virtualNetworkLink.id + +@description('The resource group of the deployed virtual network link.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = virtualNetworkLink.location diff --git a/avm/1.1.0/res/network/private-dns-zone/virtual-network-link/main.json b/avm/1.1.0/res/network/private-dns-zone/virtual-network-link/main.json new file mode 100644 index 000000000..377d08542 --- /dev/null +++ b/avm/1.1.0/res/network/private-dns-zone/virtual-network-link/main.json @@ -0,0 +1,115 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15937807282215500764" + }, + "name": "Private DNS Zone Virtual Network Link", + "description": "This module deploys a Private DNS Zone Virtual Network Link." + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "registrationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + }, + "resolutionPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." + } + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "registrationEnabled": "[parameters('registrationEnabled')]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + }, + "resolutionPolicy": "[parameters('resolutionPolicy')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-endpoint/README.md b/avm/1.1.0/res/network/private-endpoint/README.md new file mode 100644 index 000000000..fe08c08b7 --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/README.md @@ -0,0 +1,1268 @@ +# Private Endpoints `[Microsoft.Network/privateEndpoints]` + +This module deploys a Private Endpoint. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/private-endpoint:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [Using private link service](#example-3-using-private-link-service) +- [WAF-aligned](#example-4-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = { + name: 'privateEndpointDeployment' + params: { + // Required parameters + name: 'npemin001' + subnetResourceId: '' + // Non-required parameters + privateLinkServiceConnections: [ + { + name: 'npemin001' + properties: { + groupIds: [ + 'vault' + ] + privateLinkServiceId: '' + } + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npemin001" + }, + "subnetResourceId": { + "value": "" + }, + // Non-required parameters + "privateLinkServiceConnections": { + "value": [ + { + "name": "npemin001", + "properties": { + "groupIds": [ + "vault" + ], + "privateLinkServiceId": "" + } + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-endpoint:' + +// Required parameters +param name = 'npemin001' +param subnetResourceId = '' +// Non-required parameters +param privateLinkServiceConnections = [ + { + name: 'npemin001' + properties: { + groupIds: [ + 'vault' + ] + privateLinkServiceId: '' + } + } +] +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = { + name: 'privateEndpointDeployment' + params: { + // Required parameters + name: 'npemax001' + subnetResourceId: '' + // Non-required parameters + applicationSecurityGroupResourceIds: [ + '' + ] + customDnsConfigs: [ + { + fqdn: 'abc.keyvault.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + customNetworkInterfaceName: 'npemax001nic' + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + privateDnsZoneGroup: { + name: 'default' + privateDnsZoneGroupConfigs: [ + { + name: 'config' + privateDnsZoneResourceId: '' + } + ] + } + privateLinkServiceConnections: [ + { + name: 'npemax001' + properties: { + groupIds: [ + 'vault' + ] + privateLinkServiceId: '' + requestMessage: 'Hey there' + } + } + ] + roleAssignments: [ + { + name: '6804f270-b4e9-455f-a11b-7f2a64e38f7c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npemax001" + }, + "subnetResourceId": { + "value": "" + }, + // Non-required parameters + "applicationSecurityGroupResourceIds": { + "value": [ + "" + ] + }, + "customDnsConfigs": { + "value": [ + { + "fqdn": "abc.keyvault.com", + "ipAddresses": [ + "10.0.0.10" + ] + } + ] + }, + "customNetworkInterfaceName": { + "value": "npemax001nic" + }, + "ipConfigurations": { + "value": [ + { + "name": "myIPconfig", + "properties": { + "groupId": "vault", + "memberName": "default", + "privateIPAddress": "10.0.0.10" + } + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "privateDnsZoneGroup": { + "value": { + "name": "default", + "privateDnsZoneGroupConfigs": [ + { + "name": "config", + "privateDnsZoneResourceId": "" + } + ] + } + }, + "privateLinkServiceConnections": { + "value": [ + { + "name": "npemax001", + "properties": { + "groupIds": [ + "vault" + ], + "privateLinkServiceId": "", + "requestMessage": "Hey there" + } + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "6804f270-b4e9-455f-a11b-7f2a64e38f7c", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-endpoint:' + +// Required parameters +param name = 'npemax001' +param subnetResourceId = '' +// Non-required parameters +param applicationSecurityGroupResourceIds = [ + '' +] +param customDnsConfigs = [ + { + fqdn: 'abc.keyvault.com' + ipAddresses: [ + '10.0.0.10' + ] + } +] +param customNetworkInterfaceName = 'npemax001nic' +param ipConfigurations = [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateDnsZoneGroup = { + name: 'default' + privateDnsZoneGroupConfigs: [ + { + name: 'config' + privateDnsZoneResourceId: '' + } + ] +} +param privateLinkServiceConnections = [ + { + name: 'npemax001' + properties: { + groupIds: [ + 'vault' + ] + privateLinkServiceId: '' + requestMessage: 'Hey there' + } + } +] +param roleAssignments = [ + { + name: '6804f270-b4e9-455f-a11b-7f2a64e38f7c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _Using private link service_ + +This instance deploys the module with a private link service to test the application of an empty list of string for `groupIds`. + + +

+ +via Bicep module + +```bicep +module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = { + name: 'privateEndpointDeployment' + params: { + // Required parameters + name: 'npepls001' + subnetResourceId: '' + // Non-required parameters + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: '' + memberName: '' + privateIPAddress: '10.0.0.10' + } + } + ] + privateLinkServiceConnections: [ + { + name: 'npepls001' + properties: { + groupIds: [] + privateLinkServiceId: '' + } + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npepls001" + }, + "subnetResourceId": { + "value": "" + }, + // Non-required parameters + "ipConfigurations": { + "value": [ + { + "name": "myIPconfig", + "properties": { + "groupId": "", + "memberName": "", + "privateIPAddress": "10.0.0.10" + } + } + ] + }, + "privateLinkServiceConnections": { + "value": [ + { + "name": "npepls001", + "properties": { + "groupIds": [], + "privateLinkServiceId": "" + } + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-endpoint:' + +// Required parameters +param name = 'npepls001' +param subnetResourceId = '' +// Non-required parameters +param ipConfigurations = [ + { + name: 'myIPconfig' + properties: { + groupId: '' + memberName: '' + privateIPAddress: '10.0.0.10' + } + } +] +param privateLinkServiceConnections = [ + { + name: 'npepls001' + properties: { + groupIds: [] + privateLinkServiceId: '' + } + } +] +``` + +
+

+ +### Example 4: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module privateEndpoint 'br/public:avm/res/network/private-endpoint:' = { + name: 'privateEndpointDeployment' + params: { + // Required parameters + name: 'npewaf001' + subnetResourceId: '' + // Non-required parameters + applicationSecurityGroupResourceIds: [ + '' + ] + customNetworkInterfaceName: 'npewaf001nic' + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + privateLinkServiceConnections: [ + { + name: 'npewaf001' + properties: { + groupIds: [ + 'vault' + ] + privateLinkServiceId: '' + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npewaf001" + }, + "subnetResourceId": { + "value": "" + }, + // Non-required parameters + "applicationSecurityGroupResourceIds": { + "value": [ + "" + ] + }, + "customNetworkInterfaceName": { + "value": "npewaf001nic" + }, + "ipConfigurations": { + "value": [ + { + "name": "myIPconfig", + "properties": { + "groupId": "vault", + "memberName": "default", + "privateIPAddress": "10.0.0.10" + } + } + ] + }, + "privateDnsZoneGroup": { + "value": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + } + }, + "privateLinkServiceConnections": { + "value": [ + { + "name": "npewaf001", + "properties": { + "groupIds": [ + "vault" + ], + "privateLinkServiceId": "" + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-endpoint:' + +// Required parameters +param name = 'npewaf001' +param subnetResourceId = '' +// Non-required parameters +param applicationSecurityGroupResourceIds = [ + '' +] +param customNetworkInterfaceName = 'npewaf001nic' +param ipConfigurations = [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } +] +param privateDnsZoneGroup = { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] +} +param privateLinkServiceConnections = [ + { + name: 'npewaf001' + properties: { + groupIds: [ + 'vault' + ] + privateLinkServiceId: '' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the private endpoint resource to create. | +| [`subnetResourceId`](#parameter-subnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`manualPrivateLinkServiceConnections`](#parameter-manualprivatelinkserviceconnections) | array | A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty. | +| [`privateLinkServiceConnections`](#parameter-privatelinkserviceconnections) | array | A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationSecurityGroupResourceIds`](#parameter-applicationsecuritygroupresourceids) | array | Application security groups in which the private endpoint IP configuration is included. | +| [`customDnsConfigs`](#parameter-customdnsconfigs) | array | Custom DNS configurations. | +| [`customNetworkInterfaceName`](#parameter-customnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`ipConfigurations`](#parameter-ipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`privateDnsZoneGroup`](#parameter-privatednszonegroup) | object | The private DNS zone group to configure for the private endpoint. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags to be applied on all resources/resource groups in this deployment. | + +### Parameter: `name` + +Name of the private endpoint resource to create. + +- Required: Yes +- Type: string + +### Parameter: `subnetResourceId` + +Resource ID of the subnet where the endpoint needs to be created. + +- Required: Yes +- Type: string + +### Parameter: `manualPrivateLinkServiceConnections` + +A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-manualprivatelinkserviceconnectionsname) | string | The name of the private link service connection. | +| [`properties`](#parameter-manualprivatelinkserviceconnectionsproperties) | object | Properties of private link service connection. | + +### Parameter: `manualPrivateLinkServiceConnections.name` + +The name of the private link service connection. + +- Required: Yes +- Type: string + +### Parameter: `manualPrivateLinkServiceConnections.properties` + +Properties of private link service connection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupIds`](#parameter-manualprivatelinkserviceconnectionspropertiesgroupids) | array | The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`. | +| [`privateLinkServiceId`](#parameter-manualprivatelinkserviceconnectionspropertiesprivatelinkserviceid) | string | The resource id of private link service. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`requestMessage`](#parameter-manualprivatelinkserviceconnectionspropertiesrequestmessage) | string | A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. | + +### Parameter: `manualPrivateLinkServiceConnections.properties.groupIds` + +The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`. + +- Required: Yes +- Type: array + +### Parameter: `manualPrivateLinkServiceConnections.properties.privateLinkServiceId` + +The resource id of private link service. + +- Required: Yes +- Type: string + +### Parameter: `manualPrivateLinkServiceConnections.properties.requestMessage` + +A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. + +- Required: No +- Type: string + +### Parameter: `privateLinkServiceConnections` + +A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privatelinkserviceconnectionsname) | string | The name of the private link service connection. | +| [`properties`](#parameter-privatelinkserviceconnectionsproperties) | object | Properties of private link service connection. | + +### Parameter: `privateLinkServiceConnections.name` + +The name of the private link service connection. + +- Required: Yes +- Type: string + +### Parameter: `privateLinkServiceConnections.properties` + +Properties of private link service connection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupIds`](#parameter-privatelinkserviceconnectionspropertiesgroupids) | array | The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`. | +| [`privateLinkServiceId`](#parameter-privatelinkserviceconnectionspropertiesprivatelinkserviceid) | string | The resource id of private link service. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`requestMessage`](#parameter-privatelinkserviceconnectionspropertiesrequestmessage) | string | A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. | + +### Parameter: `privateLinkServiceConnections.properties.groupIds` + +The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`. + +- Required: Yes +- Type: array + +### Parameter: `privateLinkServiceConnections.properties.privateLinkServiceId` + +The resource id of private link service. + +- Required: Yes +- Type: string + +### Parameter: `privateLinkServiceConnections.properties.requestMessage` + +A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. + +- Required: No +- Type: string + +### Parameter: `applicationSecurityGroupResourceIds` + +Application security groups in which the private endpoint IP configuration is included. + +- Required: No +- Type: array + +### Parameter: `customDnsConfigs` + +Custom DNS configurations. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipAddresses`](#parameter-customdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`fqdn`](#parameter-customdnsconfigsfqdn) | string | FQDN that resolves to private endpoint IP address. | + +### Parameter: `customDnsConfigs.ipAddresses` + +A list of private IP addresses of the private endpoint. + +- Required: Yes +- Type: array + +### Parameter: `customDnsConfigs.fqdn` + +FQDN that resolves to private endpoint IP address. + +- Required: No +- Type: string + +### Parameter: `customNetworkInterfaceName` + +The custom name of the network interface attached to the private endpoint. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `ipConfigurations` + +A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-ipconfigurationsname) | string | The name of the resource that is unique within a resource group. | +| [`properties`](#parameter-ipconfigurationsproperties) | object | Properties of private endpoint IP configurations. | + +### Parameter: `ipConfigurations.name` + +The name of the resource that is unique within a resource group. + +- Required: Yes +- Type: string + +### Parameter: `ipConfigurations.properties` + +Properties of private endpoint IP configurations. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupId`](#parameter-ipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string. | +| [`memberName`](#parameter-ipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string. | +| [`privateIPAddress`](#parameter-ipconfigurationspropertiesprivateipaddress) | string | A private IP address obtained from the private endpoint's subnet. | + +### Parameter: `ipConfigurations.properties.groupId` + +The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string. + +- Required: Yes +- Type: string + +### Parameter: `ipConfigurations.properties.memberName` + +The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string. + +- Required: Yes +- Type: string + +### Parameter: `ipConfigurations.properties.privateIPAddress` + +A private IP address obtained from the private endpoint's subnet. + +- Required: Yes +- Type: string + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `privateDnsZoneGroup` + +The private DNS zone group to configure for the private endpoint. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneGroupConfigs`](#parameter-privatednszonegroupprivatednszonegroupconfigs) | array | The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privatednszonegroupname) | string | The name of the Private DNS Zone Group. | + +### Parameter: `privateDnsZoneGroup.privateDnsZoneGroupConfigs` + +The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneResourceId`](#parameter-privatednszonegroupprivatednszonegroupconfigsprivatednszoneresourceid) | string | The resource id of the private DNS zone. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privatednszonegroupprivatednszonegroupconfigsname) | string | The name of the private DNS zone group config. | + +### Parameter: `privateDnsZoneGroup.privateDnsZoneGroupConfigs.privateDnsZoneResourceId` + +The resource id of the private DNS zone. + +- Required: Yes +- Type: string + +### Parameter: `privateDnsZoneGroup.privateDnsZoneGroupConfigs.name` + +The name of the private DNS zone group config. + +- Required: No +- Type: string + +### Parameter: `privateDnsZoneGroup.name` + +The name of the Private DNS Zone Group. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags to be applied on all resources/resource groups in this deployment. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `customDnsConfigs` | array | The custom DNS configurations of the private endpoint. | +| `groupId` | string | The group Id for the private endpoint Group. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the private endpoint. | +| `networkInterfaceResourceIds` | array | The resource IDs of the network interfaces associated with the private endpoint. | +| `resourceGroupName` | string | The resource group the private endpoint was deployed into. | +| `resourceId` | string | The resource ID of the private endpoint. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/private-endpoint/main.bicep b/avm/1.1.0/res/network/private-endpoint/main.bicep new file mode 100644 index 000000000..a70108971 --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/main.bicep @@ -0,0 +1,248 @@ +metadata name = 'Private Endpoints' +metadata description = 'This module deploys a Private Endpoint.' + +@description('Required. Name of the private endpoint resource to create.') +param name string + +@description('Required. Resource ID of the subnet where the endpoint needs to be created.') +param subnetResourceId string + +@description('Optional. Application security groups in which the private endpoint IP configuration is included.') +param applicationSecurityGroupResourceIds string[]? + +@description('Optional. The custom name of the network interface attached to the private endpoint.') +param customNetworkInterfaceName string? + +@description('Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints.') +param ipConfigurations ipConfigurationType[]? + +@description('Optional. The private DNS zone group to configure for the private endpoint.') +param privateDnsZoneGroup privateDnsZoneGroupType? + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags to be applied on all resources/resource groups in this deployment.') +param tags object? + +@description('Optional. Custom DNS configurations.') +param customDnsConfigs customDnsConfigType[]? + +@description('Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty.') +param manualPrivateLinkServiceConnections privateLinkServiceConnectionType[]? + +@description('Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty.') +param privateLinkServiceConnections privateLinkServiceConnectionType[]? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-privateendpoint.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-11-01' = { + name: name + location: location + tags: tags + properties: { + applicationSecurityGroups: [ + for applicationSecurityGroupResourceId in (applicationSecurityGroupResourceIds ?? []): { + id: applicationSecurityGroupResourceId + } + ] + customDnsConfigs: customDnsConfigs ?? [] + customNetworkInterfaceName: customNetworkInterfaceName ?? '' + ipConfigurations: ipConfigurations ?? [] + manualPrivateLinkServiceConnections: manualPrivateLinkServiceConnections ?? [] + privateLinkServiceConnections: privateLinkServiceConnections ?? [] + subnet: { + id: subnetResourceId + } + } +} + +module privateEndpoint_privateDnsZoneGroup 'private-dns-zone-group/main.bicep' = if (!empty(privateDnsZoneGroup)) { + name: '${uniqueString(deployment().name)}-PrivateEndpoint-PrivateDnsZoneGroup' + params: { + name: privateDnsZoneGroup.?name + privateEndpointName: privateEndpoint.name + privateDnsZoneConfigs: privateDnsZoneGroup!.privateDnsZoneGroupConfigs + } +} + +resource privateEndpoint_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: privateEndpoint +} + +resource privateEndpoint_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(privateEndpoint.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: privateEndpoint + } +] + +@description('The resource group the private endpoint was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the private endpoint.') +output resourceId string = privateEndpoint.id + +@description('The name of the private endpoint.') +output name string = privateEndpoint.name + +@description('The location the resource was deployed into.') +output location string = privateEndpoint.location + +@description('The custom DNS configurations of the private endpoint.') +output customDnsConfigs customDnsConfigType[] = privateEndpoint.properties.customDnsConfigs + +@description('The resource IDs of the network interfaces associated with the private endpoint.') +output networkInterfaceResourceIds string[] = map(privateEndpoint.properties.networkInterfaces, nic => nic.id) + +@description('The group Id for the private endpoint Group.') +output groupId string? = privateEndpoint.properties.?manualPrivateLinkServiceConnections[?0].properties.?groupIds[?0] ?? privateEndpoint.properties.?privateLinkServiceConnections[?0].properties.?groupIds[?0] + +// ================ // +// Definitions // +// ================ // + +import { privateDnsZoneGroupConfigType } from 'private-dns-zone-group/main.bicep' + +@export() +type privateDnsZoneGroupType = { + @description('Optional. The name of the Private DNS Zone Group.') + name: string? + + @description('Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones.') + privateDnsZoneGroupConfigs: privateDnsZoneGroupConfigType[] +} + +@export() +type ipConfigurationType = { + @description('Required. The name of the resource that is unique within a resource group.') + name: string + + @description('Required. Properties of private endpoint IP configurations.') + properties: { + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string.') + groupId: string + + @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string.') + memberName: string + + @description('Required. A private IP address obtained from the private endpoint\'s subnet.') + privateIPAddress: string + } +} + +@export() +type privateLinkServiceConnectionType = { + @description('Required. The name of the private link service connection.') + name: string + + @description('Required. Properties of private link service connection.') + properties: { + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`.') + groupIds: string[] + + @description('Required. The resource id of private link service.') + privateLinkServiceId: string + + @description('Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars.') + requestMessage: string? + } +} + +@export() +type customDnsConfigType = { + @description('Optional. FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @description('Required. A list of private IP addresses of the private endpoint.') + ipAddresses: string[] +} diff --git a/avm/1.1.0/res/network/private-endpoint/main.json b/avm/1.1.0/res/network/private-endpoint/main.json new file mode 100644 index 000000000..09882a699 --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/main.json @@ -0,0 +1,697 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "7551972959536498344" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15534698908285836761" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-endpoint/private-dns-zone-group/README.md b/avm/1.1.0/res/network/private-endpoint/private-dns-zone-group/README.md new file mode 100644 index 000000000..898c0a1f9 --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/private-dns-zone-group/README.md @@ -0,0 +1,91 @@ +# Private Endpoint Private DNS Zone Groups `[Microsoft.Network/privateEndpoints/privateDnsZoneGroups]` + +This module deploys a Private Endpoint Private DNS Zone Group. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneConfigs`](#parameter-privatednszoneconfigs) | array | Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateEndpointName`](#parameter-privateendpointname) | string | The name of the parent private endpoint. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the private DNS zone group. | + +### Parameter: `privateDnsZoneConfigs` + +Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneResourceId`](#parameter-privatednszoneconfigsprivatednszoneresourceid) | string | The resource id of the private DNS zone. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privatednszoneconfigsname) | string | The name of the private DNS zone group config. | + +### Parameter: `privateDnsZoneConfigs.privateDnsZoneResourceId` + +The resource id of the private DNS zone. + +- Required: Yes +- Type: string + +### Parameter: `privateDnsZoneConfigs.name` + +The name of the private DNS zone group config. + +- Required: No +- Type: string + +### Parameter: `privateEndpointName` + +The name of the parent private endpoint. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the private DNS zone group. + +- Required: No +- Type: string +- Default: `'default'` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the private endpoint DNS zone group. | +| `resourceGroupName` | string | The resource group the private endpoint DNS zone group was deployed into. | +| `resourceId` | string | The resource ID of the private endpoint DNS zone group. | diff --git a/avm/1.1.0/res/network/private-endpoint/private-dns-zone-group/main.bicep b/avm/1.1.0/res/network/private-endpoint/private-dns-zone-group/main.bicep new file mode 100644 index 000000000..52ec654c9 --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/private-dns-zone-group/main.bicep @@ -0,0 +1,56 @@ +metadata name = 'Private Endpoint Private DNS Zone Groups' +metadata description = 'This module deploys a Private Endpoint Private DNS Zone Group.' + +@description('Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment.') +param privateEndpointName string + +@description('Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones.') +@minLength(1) +@maxLength(5) +param privateDnsZoneConfigs privateDnsZoneGroupConfigType[] + +@description('Optional. The name of the private DNS zone group.') +param name string = 'default' + +var privateDnsZoneConfigsVar = [ + for privateDnsZoneConfig in privateDnsZoneConfigs: { + name: privateDnsZoneConfig.?name ?? last(split(privateDnsZoneConfig.privateDnsZoneResourceId, '/')) + properties: { + privateDnsZoneId: privateDnsZoneConfig.privateDnsZoneResourceId + } + } +] + +resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-11-01' existing = { + name: privateEndpointName +} + +resource privateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2023-11-01' = { + name: name + parent: privateEndpoint + properties: { + privateDnsZoneConfigs: privateDnsZoneConfigsVar + } +} + +@description('The name of the private endpoint DNS zone group.') +output name string = privateDnsZoneGroup.name + +@description('The resource ID of the private endpoint DNS zone group.') +output resourceId string = privateDnsZoneGroup.id + +@description('The resource group the private endpoint DNS zone group was deployed into.') +output resourceGroupName string = resourceGroup().name + +// ================ // +// Definitions // +// ================ // + +@export() +type privateDnsZoneGroupConfigType = { + @description('Optional. The name of the private DNS zone group config.') + name: string? + + @description('Required. The resource id of the private DNS zone.') + privateDnsZoneResourceId: string +} diff --git a/avm/1.1.0/res/network/private-endpoint/private-dns-zone-group/main.json b/avm/1.1.0/res/network/private-endpoint/private-dns-zone-group/main.json new file mode 100644 index 000000000..6aa3dfdda --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/private-dns-zone-group/main.json @@ -0,0 +1,116 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15534698908285836761" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-endpoint/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/private-endpoint/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..a2a1d93da --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,54 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id diff --git a/avm/1.1.0/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..0cd5fc0b8 --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,69 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.privateendpoints-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npemin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + privateLinkServiceConnections: [ + { + name: '${namePrefix}${serviceShort}001' + properties: { + privateLinkServiceId: nestedDependencies.outputs.keyVaultResourceId + groupIds: [ + 'vault' + ] + } + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/private-endpoint/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/private-endpoint/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..a4bc9dabc --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/tests/e2e/max/dependencies.bicep @@ -0,0 +1,95 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Application Security Group to create.') +param applicationSecurityGroupName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } +} + +resource applicationSecurityGroup 'Microsoft.Network/applicationSecurityGroups@2023-04-01' = { + name: applicationSecurityGroupName + location: location +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.vaultcore.azure.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The resource ID of the created Application Security Group.') +output applicationSecurityGroupResourceId string = applicationSecurityGroup.id diff --git a/avm/1.1.0/res/network/private-endpoint/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/private-endpoint/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..71b57d3d1 --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/tests/e2e/max/main.test.bicep @@ -0,0 +1,135 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.privateendpoints-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npemax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + applicationSecurityGroupName: 'dep-${namePrefix}-asg-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + subnetResourceId: nestedDependencies.outputs.subnetResourceId + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + privateDnsZoneGroup: { + name: 'default' + privateDnsZoneGroupConfigs: [ + { + name: 'config' + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + roleAssignments: [ + { + name: '6804f270-b4e9-455f-a11b-7f2a64e38f7c' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] + customDnsConfigs: [ + { + fqdn: 'abc.keyvault.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + customNetworkInterfaceName: '${namePrefix}${serviceShort}001nic' + applicationSecurityGroupResourceIds: [ + nestedDependencies.outputs.applicationSecurityGroupResourceId + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + privateLinkServiceConnections: [ + { + name: '${namePrefix}${serviceShort}001' + properties: { + privateLinkServiceId: nestedDependencies.outputs.keyVaultResourceId + groupIds: [ + 'vault' + ] + requestMessage: 'Hey there' + } + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/private-endpoint/tests/e2e/private-link/dependencies.bicep b/avm/1.1.0/res/network/private-endpoint/tests/e2e/private-link/dependencies.bicep new file mode 100644 index 000000000..5014b766b --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/tests/e2e/private-link/dependencies.bicep @@ -0,0 +1,147 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Key Vault to create.') +param privateLinkServiceName string + +@description('Required. The name of the Load Balancer to create.') +param loadbalancerName string + +var addressPrefix = '10.0.0.0/16' +var backendPoolName = 'backEndPool' +var loadBalancerFrontEndIpConfigurationName = 'myFrontEnd' +var healthProbeName = 'healthProbe' + + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'frontendSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + privateLinkServiceNetworkPolicies: 'Disabled' + } + } + { + name: 'backendSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 1) + } + } + ] + } +} + +resource loadbalancer 'Microsoft.Network/loadBalancers@2023-11-01' = { + name: loadbalancerName + location: location + sku: { + name: 'Standard' + } + properties: { + frontendIPConfigurations: [ + { + name: loadBalancerFrontEndIpConfigurationName + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: virtualNetwork.properties.subnets[0].id // frontendSubnet + } + } + } + ] + backendAddressPools: [ + { + name: backendPoolName + } + ] + inboundNatRules: [ + { + name: 'RDP' + properties: { + frontendIPConfiguration: { + id: resourceId('Microsoft.Network/loadBalancers/frontendIpConfigurations', loadbalancerName, loadBalancerFrontEndIpConfigurationName) + } + protocol: 'Tcp' + frontendPort: 3389 + backendPort: 3389 + enableFloatingIP: false + } + } + ] + loadBalancingRules: [ + { + name: 'myHTTPRule' + properties: { + frontendIPConfiguration: { + id: resourceId('Microsoft.Network/loadBalancers/frontendIpConfigurations', loadbalancerName, loadBalancerFrontEndIpConfigurationName) + } + backendAddressPool: { + id: resourceId('Microsoft.Network/loadBalancers/backendAddressPools', loadbalancerName, backendPoolName) + } + probe: { + id: resourceId('Microsoft.Network/loadBalancers/probes', loadbalancerName, healthProbeName) + } + protocol: 'Tcp' + frontendPort: 80 + backendPort: 80 + idleTimeoutInMinutes: 15 + } + } + ] + probes: [ + { + properties: { + protocol: 'Tcp' + port: 80 + intervalInSeconds: 15 + numberOfProbes: 2 + } + name: healthProbeName + } + ] + } +} + +resource privateLinkService 'Microsoft.Network/privateLinkServices@2023-11-01' = { + name: privateLinkServiceName + location: location + properties: { + enableProxyProtocol: false + loadBalancerFrontendIpConfigurations: [ + { + id: loadbalancer.properties.frontendIPConfigurations[0].id + } + ] + ipConfigurations: [ + { + name: 'snet-provider-default-1' + properties: { + privateIPAllocationMethod: 'Dynamic' + privateIPAddressVersion: 'IPv4' + subnet: { + id: loadbalancer.properties.frontendIPConfigurations[0].properties.subnet.id + } + primary: false + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Private Link Service.') +output privateLinkServiceResourceId string = privateLinkService.id diff --git a/avm/1.1.0/res/network/private-endpoint/tests/e2e/private-link/main.test.bicep b/avm/1.1.0/res/network/private-endpoint/tests/e2e/private-link/main.test.bicep new file mode 100644 index 000000000..4a4e0452c --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/tests/e2e/private-link/main.test.bicep @@ -0,0 +1,78 @@ +targetScope = 'subscription' + +metadata name = 'Using private link service' +metadata description = 'This instance deploys the module with a private link service to test the application of an empty list of string for `groupIds`.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.privateendpoints-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npepls' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + privateLinkServiceName: 'dep-${namePrefix}-pls-${serviceShort}' + loadbalancerName: 'dep-${namePrefix}-lb-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: '' + memberName: '' + privateIPAddress: '10.0.0.10' + } + } + ] + privateLinkServiceConnections: [ + { + name: '${namePrefix}${serviceShort}001' + properties: { + privateLinkServiceId: nestedDependencies.outputs.privateLinkServiceResourceId + groupIds: [] + } + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/private-endpoint/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/private-endpoint/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..a4bc9dabc --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,95 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Application Security Group to create.') +param applicationSecurityGroupName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } +} + +resource applicationSecurityGroup 'Microsoft.Network/applicationSecurityGroups@2023-04-01' = { + name: applicationSecurityGroupName + location: location +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.vaultcore.azure.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The resource ID of the created Application Security Group.') +output applicationSecurityGroupResourceId string = applicationSecurityGroup.id diff --git a/avm/1.1.0/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..2727009b1 --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,97 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.privateendpoints-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npewaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + applicationSecurityGroupName: 'dep-${namePrefix}-asg-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] + customNetworkInterfaceName: '${namePrefix}${serviceShort}001nic' + applicationSecurityGroupResourceIds: [ + nestedDependencies.outputs.applicationSecurityGroupResourceId + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + privateLinkServiceConnections: [ + { + name: '${namePrefix}${serviceShort}001' + properties: { + privateLinkServiceId: nestedDependencies.outputs.keyVaultResourceId + groupIds: [ + 'vault' + ] + } + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/private-endpoint/tests/unit/custom.tests.ps1 b/avm/1.1.0/res/network/private-endpoint/tests/unit/custom.tests.ps1 new file mode 100644 index 000000000..36b53af9c --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/tests/unit/custom.tests.ps1 @@ -0,0 +1,7 @@ +########################### +## Additional unit tests ## +########################### +## +## You can add any custom static validation tests you want here, or add them spread accross multiple test files in the unit folder. +## +########################### diff --git a/avm/1.1.0/res/network/private-endpoint/version.json b/avm/1.1.0/res/network/private-endpoint/version.json new file mode 100644 index 000000000..9c08aae21 --- /dev/null +++ b/avm/1.1.0/res/network/private-endpoint/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.10", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-link-service/README.md b/avm/1.1.0/res/network/private-link-service/README.md new file mode 100644 index 000000000..53aea9646 --- /dev/null +++ b/avm/1.1.0/res/network/private-link-service/README.md @@ -0,0 +1,858 @@ +# Private Link Services `[Microsoft.Network/privateLinkServices]` + +This module deploys a Private Link Service. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/privateLinkServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateLinkServices) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/private-link-service:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module privateLinkService 'br/public:avm/res/network/private-link-service:' = { + name: 'privateLinkServiceDeployment' + params: { + // Required parameters + ipConfigurations: [ + { + name: 'nplsmin01' + properties: { + subnet: { + id: '' + } + } + } + ] + loadBalancerFrontendIpConfigurations: [ + { + id: '' + } + ] + name: 'nplsmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "ipConfigurations": { + "value": [ + { + "name": "nplsmin01", + "properties": { + "subnet": { + "id": "" + } + } + } + ] + }, + "loadBalancerFrontendIpConfigurations": { + "value": [ + { + "id": "" + } + ] + }, + "name": { + "value": "nplsmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-link-service:' + +// Required parameters +param ipConfigurations = [ + { + name: 'nplsmin01' + properties: { + subnet: { + id: '' + } + } + } +] +param loadBalancerFrontendIpConfigurations = [ + { + id: '' + } +] +param name = 'nplsmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module privateLinkService 'br/public:avm/res/network/private-link-service:' = { + name: 'privateLinkServiceDeployment' + params: { + // Required parameters + ipConfigurations: [ + { + name: 'nplsmax01' + properties: { + primary: true + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '' + } + } + } + ] + loadBalancerFrontendIpConfigurations: [ + { + id: '' + } + ] + name: 'nplsmax001' + // Non-required parameters + autoApproval: { + subscriptions: [ + '*' + ] + } + enableProxyProtocol: true + fqdns: [ + 'nplsmax.plsfqdn01.azure.privatelinkservice' + 'nplsmax.plsfqdn02.azure.privatelinkservice' + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'fec82bb5-8552-4c4b-a3f6-65bdae54d7f4' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + visibility: { + subscriptions: [ + '' + ] + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "ipConfigurations": { + "value": [ + { + "name": "nplsmax01", + "properties": { + "primary": true, + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "" + } + } + } + ] + }, + "loadBalancerFrontendIpConfigurations": { + "value": [ + { + "id": "" + } + ] + }, + "name": { + "value": "nplsmax001" + }, + // Non-required parameters + "autoApproval": { + "value": { + "subscriptions": [ + "*" + ] + } + }, + "enableProxyProtocol": { + "value": true + }, + "fqdns": { + "value": [ + "nplsmax.plsfqdn01.azure.privatelinkservice", + "nplsmax.plsfqdn02.azure.privatelinkservice" + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "fec82bb5-8552-4c4b-a3f6-65bdae54d7f4", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "visibility": { + "value": { + "subscriptions": [ + "" + ] + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-link-service:' + +// Required parameters +param ipConfigurations = [ + { + name: 'nplsmax01' + properties: { + primary: true + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '' + } + } + } +] +param loadBalancerFrontendIpConfigurations = [ + { + id: '' + } +] +param name = 'nplsmax001' +// Non-required parameters +param autoApproval = { + subscriptions: [ + '*' + ] +} +param enableProxyProtocol = true +param fqdns = [ + 'nplsmax.plsfqdn01.azure.privatelinkservice' + 'nplsmax.plsfqdn02.azure.privatelinkservice' +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'fec82bb5-8552-4c4b-a3f6-65bdae54d7f4' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param visibility = { + subscriptions: [ + '' + ] +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module privateLinkService 'br/public:avm/res/network/private-link-service:' = { + name: 'privateLinkServiceDeployment' + params: { + // Required parameters + ipConfigurations: [ + { + name: 'nplswaf01' + properties: { + primary: true + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '' + } + } + } + ] + loadBalancerFrontendIpConfigurations: [ + { + id: '' + } + ] + name: 'nplswaf001' + // Non-required parameters + autoApproval: { + subscriptions: [ + '*' + ] + } + enableProxyProtocol: true + fqdns: [ + 'nplswaf.plsfqdn01.azure.privatelinkservice' + 'nplswaf.plsfqdn02.azure.privatelinkservice' + ] + location: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + visibility: { + subscriptions: [ + '' + ] + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "ipConfigurations": { + "value": [ + { + "name": "nplswaf01", + "properties": { + "primary": true, + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "" + } + } + } + ] + }, + "loadBalancerFrontendIpConfigurations": { + "value": [ + { + "id": "" + } + ] + }, + "name": { + "value": "nplswaf001" + }, + // Non-required parameters + "autoApproval": { + "value": { + "subscriptions": [ + "*" + ] + } + }, + "enableProxyProtocol": { + "value": true + }, + "fqdns": { + "value": [ + "nplswaf.plsfqdn01.azure.privatelinkservice", + "nplswaf.plsfqdn02.azure.privatelinkservice" + ] + }, + "location": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "visibility": { + "value": { + "subscriptions": [ + "" + ] + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-link-service:' + +// Required parameters +param ipConfigurations = [ + { + name: 'nplswaf01' + properties: { + primary: true + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '' + } + } + } +] +param loadBalancerFrontendIpConfigurations = [ + { + id: '' + } +] +param name = 'nplswaf001' +// Non-required parameters +param autoApproval = { + subscriptions: [ + '*' + ] +} +param enableProxyProtocol = true +param fqdns = [ + 'nplswaf.plsfqdn01.azure.privatelinkservice' + 'nplswaf.plsfqdn02.azure.privatelinkservice' +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param visibility = { + subscriptions: [ + '' + ] +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipConfigurations`](#parameter-ipconfigurations) | array | An array of private link service IP configurations. At least one IP configuration is required on the private link service. | +| [`loadBalancerFrontendIpConfigurations`](#parameter-loadbalancerfrontendipconfigurations) | array | An array of references to the load balancer IP configurations. The Private Link service is tied to the frontend IP address of a Standard Load Balancer. All traffic destined for the service will reach the frontend of the SLB. You can configure SLB rules to direct this traffic to appropriate backend pools where your applications are running. Load balancer frontend IP configurations are different than NAT IP configurations. At least one load balancer frontend IP configuration is required on the private link service. | +| [`name`](#parameter-name) | string | The name of the private link service to create. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`autoApproval`](#parameter-autoapproval) | object | The auto-approval list of the private link service. | +| [`enableProxyProtocol`](#parameter-enableproxyprotocol) | bool | Lets the service provider use tcp proxy v2 to retrieve connection information about the service consumer. Service Provider is responsible for setting up receiver configs to be able to parse the proxy protocol v2 header. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`extendedLocation`](#parameter-extendedlocation) | object | The extended location of the load balancer. | +| [`fqdns`](#parameter-fqdns) | array | The list of Fqdn. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags to be applied on all resources/resource groups in this deployment. | +| [`visibility`](#parameter-visibility) | object | Controls the exposure settings for your Private Link service. Service providers can choose to limit the exposure to their service to subscriptions with Azure role-based access control (Azure RBAC) permissions, a restricted set of subscriptions, or all Azure subscriptions. | + +### Parameter: `ipConfigurations` + +An array of private link service IP configurations. At least one IP configuration is required on the private link service. + +- Required: Yes +- Type: array + +### Parameter: `loadBalancerFrontendIpConfigurations` + +An array of references to the load balancer IP configurations. The Private Link service is tied to the frontend IP address of a Standard Load Balancer. All traffic destined for the service will reach the frontend of the SLB. You can configure SLB rules to direct this traffic to appropriate backend pools where your applications are running. Load balancer frontend IP configurations are different than NAT IP configurations. At least one load balancer frontend IP configuration is required on the private link service. + +- Required: Yes +- Type: array + +### Parameter: `name` + +The name of the private link service to create. + +- Required: Yes +- Type: string + +### Parameter: `autoApproval` + +The auto-approval list of the private link service. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `enableProxyProtocol` + +Lets the service provider use tcp proxy v2 to retrieve connection information about the service consumer. Service Provider is responsible for setting up receiver configs to be able to parse the proxy protocol v2 header. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `extendedLocation` + +The extended location of the load balancer. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `fqdns` + +The list of Fqdn. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags to be applied on all resources/resource groups in this deployment. + +- Required: No +- Type: object + +### Parameter: `visibility` + +Controls the exposure settings for your Private Link service. Service providers can choose to limit the exposure to their service to subscriptions with Azure role-based access control (Azure RBAC) permissions, a restricted set of subscriptions, or all Azure subscriptions. + +- Required: No +- Type: object +- Default: `{}` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the private link service. | +| `resourceGroupName` | string | The resource group the private link service was deployed into. | +| `resourceId` | string | The resource ID of the private link service. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/private-link-service/main.bicep b/avm/1.1.0/res/network/private-link-service/main.bicep new file mode 100644 index 000000000..c05f603a3 --- /dev/null +++ b/avm/1.1.0/res/network/private-link-service/main.bicep @@ -0,0 +1,189 @@ +metadata name = 'Private Link Services' +metadata description = 'This module deploys a Private Link Service.' + +@description('Required. The name of the private link service to create.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Tags to be applied on all resources/resource groups in this deployment.') +param tags object? + +@description('Required. An array of private link service IP configurations. At least one IP configuration is required on the private link service.') +param ipConfigurations array + +@description('Required. An array of references to the load balancer IP configurations. The Private Link service is tied to the frontend IP address of a Standard Load Balancer. All traffic destined for the service will reach the frontend of the SLB. You can configure SLB rules to direct this traffic to appropriate backend pools where your applications are running. Load balancer frontend IP configurations are different than NAT IP configurations. At least one load balancer frontend IP configuration is required on the private link service.') +param loadBalancerFrontendIpConfigurations array + +@description('Optional. The extended location of the load balancer.') +param extendedLocation object = {} + +@description('Optional. The auto-approval list of the private link service.') +param autoApproval object = {} + +@description('Optional. Lets the service provider use tcp proxy v2 to retrieve connection information about the service consumer. Service Provider is responsible for setting up receiver configs to be able to parse the proxy protocol v2 header.') +param enableProxyProtocol bool = false + +@description('Optional. The list of Fqdn.') +param fqdns array = [] + +@description('Optional. Controls the exposure settings for your Private Link service. Service providers can choose to limit the exposure to their service to subscriptions with Azure role-based access control (Azure RBAC) permissions, a restricted set of subscriptions, or all Azure subscriptions.') +param visibility object = {} + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-privatelinkservice.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource privateLinkService 'Microsoft.Network/privateLinkServices@2023-04-01' = { + name: name + location: location + tags: tags + extendedLocation: !empty(extendedLocation) ? extendedLocation : null + properties: { + autoApproval: autoApproval + enableProxyProtocol: enableProxyProtocol + fqdns: fqdns + ipConfigurations: ipConfigurations + loadBalancerFrontendIpConfigurations: loadBalancerFrontendIpConfigurations + visibility: visibility + } +} + +resource privateLinkService_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: privateLinkService +} + +resource privateLinkService_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + privateLinkService.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: privateLinkService + } +] + +@description('The resource group the private link service was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the private link service.') +output resourceId string = privateLinkService.id + +@description('The name of the private link service.') +output name string = privateLinkService.name + +@description('The location the resource was deployed into.') +output location string = privateLinkService.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/private-link-service/main.json b/avm/1.1.0/res/network/private-link-service/main.json new file mode 100644 index 000000000..bea31eb39 --- /dev/null +++ b/avm/1.1.0/res/network/private-link-service/main.json @@ -0,0 +1,324 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "2768080787285261323" + }, + "name": "Private Link Services", + "description": "This module deploys a Private Link Service." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "description": "Required. An array of private link service IP configurations. At least one IP configuration is required on the private link service." + } + }, + "loadBalancerFrontendIpConfigurations": { + "type": "array", + "metadata": { + "description": "Required. An array of references to the load balancer IP configurations. The Private Link service is tied to the frontend IP address of a Standard Load Balancer. All traffic destined for the service will reach the frontend of the SLB. You can configure SLB rules to direct this traffic to appropriate backend pools where your applications are running. Load balancer frontend IP configurations are different than NAT IP configurations. At least one load balancer frontend IP configuration is required on the private link service." + } + }, + "extendedLocation": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The extended location of the load balancer." + } + }, + "autoApproval": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The auto-approval list of the private link service." + } + }, + "enableProxyProtocol": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Lets the service provider use tcp proxy v2 to retrieve connection information about the service consumer. Service Provider is responsible for setting up receiver configs to be able to parse the proxy protocol v2 header." + } + }, + "fqdns": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The list of Fqdn." + } + }, + "visibility": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Controls the exposure settings for your Private Link service. Service providers can choose to limit the exposure to their service to subscriptions with Azure role-based access control (Azure RBAC) permissions, a restricted set of subscriptions, or all Azure subscriptions." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privatelinkservice.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateLinkService": { + "type": "Microsoft.Network/privateLinkServices", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "extendedLocation": "[if(not(empty(parameters('extendedLocation'))), parameters('extendedLocation'), null())]", + "properties": { + "autoApproval": "[parameters('autoApproval')]", + "enableProxyProtocol": "[parameters('enableProxyProtocol')]", + "fqdns": "[parameters('fqdns')]", + "ipConfigurations": "[parameters('ipConfigurations')]", + "loadBalancerFrontendIpConfigurations": "[parameters('loadBalancerFrontendIpConfigurations')]", + "visibility": "[parameters('visibility')]" + } + }, + "privateLinkService_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateLinkServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateLinkService" + ] + }, + "privateLinkService_roleAssignments": { + "copy": { + "name": "privateLinkService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateLinkServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateLinkServices', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateLinkService" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private link service was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private link service." + }, + "value": "[resourceId('Microsoft.Network/privateLinkServices', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private link service." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateLinkService', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/private-link-service/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/private-link-service/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..cecd1df76 --- /dev/null +++ b/avm/1.1.0/res/network/private-link-service/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,57 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Load Balancer to create.') +param loadBalancerName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + privateLinkServiceNetworkPolicies: 'Disabled' + } + } + ] + } +} + +resource loadBalancer 'Microsoft.Network/loadBalancers@2023-04-01' = { + name: loadBalancerName + location: location + sku: { + name: 'Standard' + } + properties: { + frontendIPConfigurations: [ + { + name: 'frontendIPConfiguration' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Load Balancer Frontend IP Configuration.') +output loadBalancerFrontendIpConfigurationResourceId string = loadBalancer.properties.frontendIPConfigurations[0].id diff --git a/avm/1.1.0/res/network/private-link-service/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/private-link-service/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..133ed317d --- /dev/null +++ b/avm/1.1.0/res/network/private-link-service/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,73 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.privatelinkservices-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nplsmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + loadBalancerName: 'dep-${namePrefix}-lb-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + ipConfigurations: [ + { + name: '${serviceShort}01' + properties: { + subnet: { + id: nestedDependencies.outputs.subnetResourceId + } + } + } + ] + loadBalancerFrontendIpConfigurations: [ + { + id: nestedDependencies.outputs.loadBalancerFrontendIpConfigurationResourceId + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/private-link-service/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/private-link-service/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..1031dd483 --- /dev/null +++ b/avm/1.1.0/res/network/private-link-service/tests/e2e/max/dependencies.bicep @@ -0,0 +1,68 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Load Balancer to create.') +param loadBalancerName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + privateLinkServiceNetworkPolicies: 'Disabled' + } + } + ] + } +} + +resource loadBalancer 'Microsoft.Network/loadBalancers@2023-04-01' = { + name: loadBalancerName + location: location + sku: { + name: 'Standard' + } + properties: { + frontendIPConfigurations: [ + { + name: 'frontendIPConfiguration' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Load Balancer Frontend IP Configuration.') +output loadBalancerFrontendIpConfigurationResourceId string = loadBalancer.properties.frontendIPConfigurations[0].id diff --git a/avm/1.1.0/res/network/private-link-service/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/private-link-service/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..390a50d21 --- /dev/null +++ b/avm/1.1.0/res/network/private-link-service/tests/e2e/max/main.test.bicep @@ -0,0 +1,122 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.privatelinkservices-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nplsmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + loadBalancerName: 'dep-${namePrefix}-lb-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + ipConfigurations: [ + { + name: '${serviceShort}01' + properties: { + primary: true + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: nestedDependencies.outputs.subnetResourceId + } + } + } + ] + loadBalancerFrontendIpConfigurations: [ + { + id: nestedDependencies.outputs.loadBalancerFrontendIpConfigurationResourceId + } + ] + autoApproval: { + subscriptions: [ + '*' + ] + } + visibility: { + subscriptions: [ + subscription().subscriptionId + ] + } + enableProxyProtocol: true + fqdns: [ + '${serviceShort}.plsfqdn01.azure.privatelinkservice' + '${serviceShort}.plsfqdn02.azure.privatelinkservice' + ] + roleAssignments: [ + { + name: 'fec82bb5-8552-4c4b-a3f6-65bdae54d7f4' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/private-link-service/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/private-link-service/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..cecd1df76 --- /dev/null +++ b/avm/1.1.0/res/network/private-link-service/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,57 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Load Balancer to create.') +param loadBalancerName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + privateLinkServiceNetworkPolicies: 'Disabled' + } + } + ] + } +} + +resource loadBalancer 'Microsoft.Network/loadBalancers@2023-04-01' = { + name: loadBalancerName + location: location + sku: { + name: 'Standard' + } + properties: { + frontendIPConfigurations: [ + { + name: 'frontendIPConfiguration' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Load Balancer Frontend IP Configuration.') +output loadBalancerFrontendIpConfigurationResourceId string = loadBalancer.properties.frontendIPConfigurations[0].id diff --git a/avm/1.1.0/res/network/private-link-service/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/private-link-service/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..48b68e42b --- /dev/null +++ b/avm/1.1.0/res/network/private-link-service/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,95 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.privatelinkservices-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nplswaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + loadBalancerName: 'dep-${namePrefix}-lb-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + ipConfigurations: [ + { + name: '${serviceShort}01' + properties: { + primary: true + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: nestedDependencies.outputs.subnetResourceId + } + } + } + ] + loadBalancerFrontendIpConfigurations: [ + { + id: nestedDependencies.outputs.loadBalancerFrontendIpConfigurationResourceId + } + ] + autoApproval: { + subscriptions: [ + '*' + ] + } + visibility: { + subscriptions: [ + subscription().subscriptionId + ] + } + enableProxyProtocol: true + fqdns: [ + '${serviceShort}.plsfqdn01.azure.privatelinkservice' + '${serviceShort}.plsfqdn02.azure.privatelinkservice' + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/private-link-service/version.json b/avm/1.1.0/res/network/private-link-service/version.json new file mode 100644 index 000000000..1c035df49 --- /dev/null +++ b/avm/1.1.0/res/network/private-link-service/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.2", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/public-ip-address/README.md b/avm/1.1.0/res/network/public-ip-address/README.md new file mode 100644 index 000000000..1674ff5af --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-address/README.md @@ -0,0 +1,1188 @@ +# Public IP Addresses `[Microsoft.Network/publicIPAddresses]` + +This module deploys a Public IP Address. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/publicIPAddresses` | [2024-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-05-01/publicIPAddresses) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/public-ip-address:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module publicIpAddress 'br/public:avm/res/network/public-ip-address:' = { + name: 'publicIpAddressDeployment' + params: { + // Required parameters + name: 'npiamin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npiamin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/public-ip-address:' + +// Required parameters +param name = 'npiamin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module publicIpAddress 'br/public:avm/res/network/public-ip-address:' = { + name: 'publicIpAddressDeployment' + params: { + // Required parameters + name: 'npiamax001' + // Non-required parameters + ddosSettings: '' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsSettings: '' + ipTags: [ + { + ipTagType: 'RoutingPreference' + tag: 'Internet' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + publicIPAddressVersion: 'IPv4' + publicIPAllocationMethod: 'Static' + publicIpPrefixResourceId: '' + roleAssignments: [ + { + name: '902f366b-ba61-4eb6-aa3a-786d317f2dbc' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + skuName: 'Standard' + skuTier: 'Regional' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + zones: [ + 1 + 2 + 3 + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npiamax001" + }, + // Non-required parameters + "ddosSettings": { + "value": "" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "dnsSettings": { + "value": "" + }, + "ipTags": { + "value": [ + { + "ipTagType": "RoutingPreference", + "tag": "Internet" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "publicIPAddressVersion": { + "value": "IPv4" + }, + "publicIPAllocationMethod": { + "value": "Static" + }, + "publicIpPrefixResourceId": { + "value": "" + }, + "roleAssignments": { + "value": [ + { + "name": "902f366b-ba61-4eb6-aa3a-786d317f2dbc", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "skuName": { + "value": "Standard" + }, + "skuTier": { + "value": "Regional" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "zones": { + "value": [ + 1, + 2, + 3 + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/public-ip-address:' + +// Required parameters +param name = 'npiamax001' +// Non-required parameters +param ddosSettings = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param dnsSettings = '' +param ipTags = [ + { + ipTagType: 'RoutingPreference' + tag: 'Internet' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param publicIPAddressVersion = 'IPv4' +param publicIPAllocationMethod = 'Static' +param publicIpPrefixResourceId = '' +param roleAssignments = [ + { + name: '902f366b-ba61-4eb6-aa3a-786d317f2dbc' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuName = 'Standard' +param skuTier = 'Regional' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zones = [ + 1 + 2 + 3 +] +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module publicIpAddress 'br/public:avm/res/network/public-ip-address:' = { + name: 'publicIpAddressDeployment' + params: { + // Required parameters + name: 'npiawaf001' + // Non-required parameters + ddosSettings: '' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsSettings: '' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + publicIPAddressVersion: 'IPv4' + publicIPAllocationMethod: 'Static' + publicIpPrefixResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + skuName: 'Standard' + skuTier: 'Regional' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + zones: [ + 1 + 2 + 3 + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npiawaf001" + }, + // Non-required parameters + "ddosSettings": { + "value": "" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "dnsSettings": { + "value": "" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "publicIPAddressVersion": { + "value": "IPv4" + }, + "publicIPAllocationMethod": { + "value": "Static" + }, + "publicIpPrefixResourceId": { + "value": "" + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "skuName": { + "value": "Standard" + }, + "skuTier": { + "value": "Regional" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "zones": { + "value": [ + 1, + 2, + 3 + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/public-ip-address:' + +// Required parameters +param name = 'npiawaf001' +// Non-required parameters +param ddosSettings = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param dnsSettings = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param publicIPAddressVersion = 'IPv4' +param publicIPAllocationMethod = 'Static' +param publicIpPrefixResourceId = '' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuName = 'Standard' +param skuTier = 'Regional' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zones = [ + 1 + 2 + 3 +] +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the Public IP Address. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ddosSettings`](#parameter-ddossettings) | object | The DDoS protection plan configuration associated with the public IP address. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`dnsSettings`](#parameter-dnssettings) | object | The DNS settings of the public IP address. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`idleTimeoutInMinutes`](#parameter-idletimeoutinminutes) | int | The idle timeout of the public IP address. | +| [`ipTags`](#parameter-iptags) | array | The list of tags associated with the public IP address. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`publicIPAddressVersion`](#parameter-publicipaddressversion) | string | IP address version. | +| [`publicIPAllocationMethod`](#parameter-publicipallocationmethod) | string | The public IP address allocation method. | +| [`publicIpPrefixResourceId`](#parameter-publicipprefixresourceid) | string | Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`skuName`](#parameter-skuname) | string | Name of a public IP address SKU. | +| [`skuTier`](#parameter-skutier) | string | Tier of a public IP address SKU. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`zones`](#parameter-zones) | array | A list of availability zones denoting the IP allocated for the resource needs to come from. | + +### Parameter: `name` + +The name of the Public IP Address. + +- Required: Yes +- Type: string + +### Parameter: `ddosSettings` + +The DDoS protection plan configuration associated with the public IP address. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`protectionMode`](#parameter-ddossettingsprotectionmode) | string | The DDoS protection policy customizations. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ddosProtectionPlan`](#parameter-ddossettingsddosprotectionplan) | object | The DDoS protection plan associated with the public IP address. | + +### Parameter: `ddosSettings.protectionMode` + +The DDoS protection policy customizations. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Enabled' + ] + ``` + +### Parameter: `ddosSettings.ddosProtectionPlan` + +The DDoS protection plan associated with the public IP address. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`id`](#parameter-ddossettingsddosprotectionplanid) | string | The resource ID of the DDOS protection plan associated with the public IP address. | + +### Parameter: `ddosSettings.ddosProtectionPlan.id` + +The resource ID of the DDOS protection plan associated with the public IP address. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of the diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of the diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `dnsSettings` + +The DNS settings of the public IP address. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`domainNameLabel`](#parameter-dnssettingsdomainnamelabel) | string | The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`domainNameLabelScope`](#parameter-dnssettingsdomainnamelabelscope) | string | The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN. | +| [`fqdn`](#parameter-dnssettingsfqdn) | string | The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone. | +| [`reverseFqdn`](#parameter-dnssettingsreversefqdn) | string | The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN. | + +### Parameter: `dnsSettings.domainNameLabel` + +The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system. + +- Required: Yes +- Type: string + +### Parameter: `dnsSettings.domainNameLabelScope` + +The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'NoReuse' + 'ResourceGroupReuse' + 'SubscriptionReuse' + 'TenantReuse' + ] + ``` + +### Parameter: `dnsSettings.fqdn` + +The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone. + +- Required: No +- Type: string + +### Parameter: `dnsSettings.reverseFqdn` + +The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `idleTimeoutInMinutes` + +The idle timeout of the public IP address. + +- Required: No +- Type: int +- Default: `4` + +### Parameter: `ipTags` + +The list of tags associated with the public IP address. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipTagType`](#parameter-iptagsiptagtype) | string | The IP tag type. | +| [`tag`](#parameter-iptagstag) | string | The IP tag. | + +### Parameter: `ipTags.ipTagType` + +The IP tag type. + +- Required: Yes +- Type: string + +### Parameter: `ipTags.tag` + +The IP tag. + +- Required: Yes +- Type: string + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `publicIPAddressVersion` + +IP address version. + +- Required: No +- Type: string +- Default: `'IPv4'` +- Allowed: + ```Bicep + [ + 'IPv4' + 'IPv6' + ] + ``` + +### Parameter: `publicIPAllocationMethod` + +The public IP address allocation method. + +- Required: No +- Type: string +- Default: `'Static'` +- Allowed: + ```Bicep + [ + 'Dynamic' + 'Static' + ] + ``` + +### Parameter: `publicIpPrefixResourceId` + +Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `skuName` + +Name of a public IP address SKU. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Standard' + ] + ``` + +### Parameter: `skuTier` + +Tier of a public IP address SKU. + +- Required: No +- Type: string +- Default: `'Regional'` +- Allowed: + ```Bicep + [ + 'Global' + 'Regional' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `zones` + +A list of availability zones denoting the IP allocated for the resource needs to come from. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` +- Allowed: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `ipAddress` | string | The public IP address of the public IP address resource. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the public IP address. | +| `resourceGroupName` | string | The resource group the public IP address was deployed into. | +| `resourceId` | string | The resource ID of the public IP address. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.2.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/public-ip-address/main.bicep b/avm/1.1.0/res/network/public-ip-address/main.bicep new file mode 100644 index 000000000..7294fe5e4 --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-address/main.bicep @@ -0,0 +1,279 @@ +metadata name = 'Public IP Addresses' +metadata description = 'This module deploys a Public IP Address.' + +@description('Required. The name of the Public IP Address.') +param name string + +@description('Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix.') +param publicIpPrefixResourceId string? + +@description('Optional. The public IP address allocation method.') +@allowed([ + 'Dynamic' + 'Static' +]) +param publicIPAllocationMethod string = 'Static' + +@description('Optional. A list of availability zones denoting the IP allocated for the resource needs to come from.') +@allowed([ + 1 + 2 + 3 +]) +param zones int[] = [ + 1 + 2 + 3 +] + +@description('Optional. IP address version.') +@allowed([ + 'IPv4' + 'IPv6' +]) +param publicIPAddressVersion string = 'IPv4' + +@description('Optional. The DNS settings of the public IP address.') +param dnsSettings dnsSettingsType? + +@description('Optional. The list of tags associated with the public IP address.') +param ipTags ipTagType[]? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +@description('Optional. Name of a public IP address SKU.') +@allowed([ + 'Basic' + 'Standard' +]) +param skuName string = 'Standard' + +@description('Optional. Tier of a public IP address SKU.') +@allowed([ + 'Global' + 'Regional' +]) +param skuTier string = 'Regional' + +@description('Optional. The DDoS protection plan configuration associated with the public IP address.') +param ddosSettings ddosSettingsType? + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. The idle timeout of the public IP address.') +param idleTimeoutInMinutes int = 4 + +@description('Optional. Tags of the resource.') +param tags object? + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'DNS Resolver Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d' + ) + 'DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'befefa01-2a29-4197-83a8-272ff33ce314' + ) + 'Domain Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'eeaeda52-9324-47f6-8069-5d5bade478b2' + ) + 'Domain Services Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '361898ef-9ed1-48c2-849c-a832951106bb' + ) + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Private DNS Zone Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b12aa53e-6015-4669-85d0-8515ebb3ae7f' + ) + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-publicipaddress.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource publicIpAddress 'Microsoft.Network/publicIPAddresses@2024-05-01' = { + name: name + location: location + tags: tags + sku: { + name: skuName + tier: skuTier + } + zones: map(zones, zone => string(zone)) + properties: { + ddosSettings: ddosSettings + dnsSettings: dnsSettings + publicIPAddressVersion: publicIPAddressVersion + publicIPAllocationMethod: publicIPAllocationMethod + publicIPPrefix: !empty(publicIpPrefixResourceId) + ? { + id: publicIpPrefixResourceId + } + : null + idleTimeoutInMinutes: idleTimeoutInMinutes + ipTags: ipTags + } +} + +resource publicIpAddress_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: publicIpAddress +} + +resource publicIpAddress_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(publicIpAddress.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: publicIpAddress + } +] + +resource publicIpAddress_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: publicIpAddress + } +] + +@description('The resource group the public IP address was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the public IP address.') +output name string = publicIpAddress.name + +@description('The resource ID of the public IP address.') +output resourceId string = publicIpAddress.id + +@description('The public IP address of the public IP address resource.') +output ipAddress string = publicIpAddress.properties.?ipAddress ?? '' + +@description('The location the resource was deployed into.') +output location string = publicIpAddress.location + +// ================ // +// Definitions // +// ================ // + +@export() +type dnsSettingsType = { + @description('Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system.') + domainNameLabel: string + + @description('Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN.') + domainNameLabelScope: ('NoReuse' | 'ResourceGroupReuse' | 'SubscriptionReuse' | 'TenantReuse')? + + @description('Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone.') + fqdn: string? + + @description('Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN.') + reverseFqdn: string? +} + +@export() +type ddosSettingsType = { + @description('Optional. The DDoS protection plan associated with the public IP address.') + ddosProtectionPlan: { + @description('Required. The resource ID of the DDOS protection plan associated with the public IP address.') + id: string + }? + @description('Required. The DDoS protection policy customizations.') + protectionMode: 'Enabled' +} + +@export() +type ipTagType = { + @description('Required. The IP tag type.') + ipTagType: string + + @description('Required. The IP tag.') + tag: string +} diff --git a/avm/1.1.0/res/network/public-ip-address/main.json b/avm/1.1.0/res/network/public-ip-address/main.json new file mode 100644 index 000000000..8d53c2edb --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-address/main.json @@ -0,0 +1,671 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "11118459859179868367" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address." + }, + "definitions": { + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "nullable": true, + "metadata": { + "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2024-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": "[parameters('ipTags')]" + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2024-05-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/public-ip-address/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/public-ip-address/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..1fd4157d2 --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-address/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,47 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.publicipaddresses-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npiamin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-11-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/network/public-ip-address/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/public-ip-address/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7b3d4e8fb --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-address/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/public-ip-address/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/public-ip-address/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..85db1a32c --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-address/tests/e2e/max/main.test.bicep @@ -0,0 +1,128 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.publicipaddresses-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npiamax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-11-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + name: 'myCustomLockName' + kind: 'CanNotDelete' + } + dnsSettings: null + ddosSettings: null + ipTags: [ + { + ipTagType: 'RoutingPreference' + tag: 'Internet' + } + ] + publicIpPrefixResourceId: null + publicIPAllocationMethod: 'Static' + roleAssignments: [ + { + name: '902f366b-ba61-4eb6-aa3a-786d317f2dbc' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + skuName: 'Standard' + skuTier: 'Regional' + publicIPAddressVersion: 'IPv4' + zones: [ + 1 + 2 + 3 + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + diagnosticSettings: [ + { + name: 'customSetting' + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/public-ip-address/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/public-ip-address/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..7b3d4e8fb --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-address/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/public-ip-address/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/public-ip-address/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..bcab1fc98 --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-address/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,120 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.publicipaddresses-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npiawaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-11-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + name: 'myCustomLockName' + kind: 'CanNotDelete' + } + dnsSettings: null + ddosSettings: null + publicIPAllocationMethod: 'Static' + publicIpPrefixResourceId: null + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + skuName: 'Standard' + skuTier: 'Regional' + publicIPAddressVersion: 'IPv4' + zones: [ + 1 + 2 + 3 + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + diagnosticSettings: [ + { + name: 'customSetting' + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/public-ip-address/tests/unit/custom.tests.ps1 b/avm/1.1.0/res/network/public-ip-address/tests/unit/custom.tests.ps1 new file mode 100644 index 000000000..36b53af9c --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-address/tests/unit/custom.tests.ps1 @@ -0,0 +1,7 @@ +########################### +## Additional unit tests ## +########################### +## +## You can add any custom static validation tests you want here, or add them spread accross multiple test files in the unit folder. +## +########################### diff --git a/avm/1.1.0/res/network/public-ip-address/version.json b/avm/1.1.0/res/network/public-ip-address/version.json new file mode 100644 index 000000000..9a9a06e89 --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-address/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.8", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/public-ip-prefix/README.md b/avm/1.1.0/res/network/public-ip-prefix/README.md new file mode 100644 index 000000000..91fb9f684 --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-prefix/README.md @@ -0,0 +1,812 @@ +# Public IP Prefixes `[Microsoft.Network/publicIPPrefixes]` + +This module deploys a Public IP Prefix. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/publicIPPrefixes` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-01-01/publicIPPrefixes) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/public-ip-prefix:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [IPv6 Public IP Prefix](#example-2-ipv6-public-ip-prefix) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [WAF-aligned](#example-4-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = { + name: 'publicIpPrefixDeployment' + params: { + // Required parameters + name: 'npipmin001' + prefixLength: 28 + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npipmin001" + }, + "prefixLength": { + "value": 28 + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/public-ip-prefix:' + +// Required parameters +param name = 'npipmin001' +param prefixLength = 28 +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _IPv6 Public IP Prefix_ + +This instance deploys the module using the IPv6 version of the Public IP Prefix. + + +

+ +via Bicep module + +```bicep +module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = { + name: 'publicIpPrefixDeployment' + params: { + // Required parameters + name: 'npipip6001' + prefixLength: 127 + // Non-required parameters + location: '' + publicIPAddressVersion: 'IPv6' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npipip6001" + }, + "prefixLength": { + "value": 127 + }, + // Non-required parameters + "location": { + "value": "" + }, + "publicIPAddressVersion": { + "value": "IPv6" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/public-ip-prefix:' + +// Required parameters +param name = 'npipip6001' +param prefixLength = 127 +// Non-required parameters +param location = '' +param publicIPAddressVersion = 'IPv6' +``` + +
+

+ +### Example 3: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = { + name: 'publicIpPrefixDeployment' + params: { + // Required parameters + name: 'npipmax001' + prefixLength: 28 + // Non-required parameters + ipTags: [ + { + ipTagType: 'RoutingPreference' + tag: 'Internet' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'bf62ed65-07be-48e8-b760-2d59795cd282' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + zones: [ + 1 + 2 + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npipmax001" + }, + "prefixLength": { + "value": 28 + }, + // Non-required parameters + "ipTags": { + "value": [ + { + "ipTagType": "RoutingPreference", + "tag": "Internet" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "bf62ed65-07be-48e8-b760-2d59795cd282", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "zones": { + "value": [ + 1, + 2 + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/public-ip-prefix:' + +// Required parameters +param name = 'npipmax001' +param prefixLength = 28 +// Non-required parameters +param ipTags = [ + { + ipTagType: 'RoutingPreference' + tag: 'Internet' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'bf62ed65-07be-48e8-b760-2d59795cd282' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zones = [ + 1 + 2 +] +``` + +
+

+ +### Example 4: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = { + name: 'publicIpPrefixDeployment' + params: { + // Required parameters + name: 'npipwaf001' + prefixLength: 28 + // Non-required parameters + location: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "npipwaf001" + }, + "prefixLength": { + "value": 28 + }, + // Non-required parameters + "location": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/public-ip-prefix:' + +// Required parameters +param name = 'npipwaf001' +param prefixLength = 28 +// Non-required parameters +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the Public IP Prefix. | +| [`prefixLength`](#parameter-prefixlength) | int | Length of the Public IP Prefix. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`customIPPrefix`](#parameter-customipprefix) | object | The custom IP address prefix that this prefix is associated with. A custom IP address prefix is a contiguous range of IP addresses owned by an external customer and provisioned into a subscription. When a custom IP prefix is in Provisioned, Commissioning, or Commissioned state, a linked public IP prefix can be created. Either as a subset of the custom IP prefix range or the entire range. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`ipTags`](#parameter-iptags) | array | The list of tags associated with the public IP prefix. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`publicIPAddressVersion`](#parameter-publicipaddressversion) | string | The public IP address version. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`tier`](#parameter-tier) | string | Tier of a public IP prefix SKU. If set to `Global`, the `zones` property must be empty. | +| [`zones`](#parameter-zones) | array | A list of availability zones denoting the IP allocated for the resource needs to come from. This is only applicable for regional public IP prefixes and must be empty for global public IP prefixes. | + +### Parameter: `name` + +The name of the Public IP Prefix. + +- Required: Yes +- Type: string + +### Parameter: `prefixLength` + +Length of the Public IP Prefix. + +- Required: Yes +- Type: int +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `customIPPrefix` + +The custom IP address prefix that this prefix is associated with. A custom IP address prefix is a contiguous range of IP addresses owned by an external customer and provisioned into a subscription. When a custom IP prefix is in Provisioned, Commissioning, or Commissioned state, a linked public IP prefix can be created. Either as a subset of the custom IP prefix range or the entire range. + +- Required: No +- Type: object +- Default: `{}` +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `ipTags` + +The list of tags associated with the public IP prefix. + +- Required: No +- Type: array +- MinValue: 21 +- MaxValue: 127 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipTagType`](#parameter-iptagsiptagtype) | string | The IP tag type. | +| [`tag`](#parameter-iptagstag) | string | The IP tag. | + +### Parameter: `ipTags.ipTagType` + +The IP tag type. + +- Required: Yes +- Type: string +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `ipTags.tag` + +The IP tag. + +- Required: Yes +- Type: string +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object +- MinValue: 21 +- MaxValue: 127 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `publicIPAddressVersion` + +The public IP address version. + +- Required: No +- Type: string +- Default: `'IPv4'` +- Allowed: + ```Bicep + [ + 'IPv4' + 'IPv6' + ] + ``` +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- MinValue: 21 +- MaxValue: 127 +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `tier` + +Tier of a public IP prefix SKU. If set to `Global`, the `zones` property must be empty. + +- Required: No +- Type: string +- Default: `'Regional'` +- Allowed: + ```Bicep + [ + 'Global' + 'Regional' + ] + ``` +- MinValue: 21 +- MaxValue: 127 + +### Parameter: `zones` + +A list of availability zones denoting the IP allocated for the resource needs to come from. This is only applicable for regional public IP prefixes and must be empty for global public IP prefixes. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` +- Allowed: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` +- MinValue: 21 +- MaxValue: 127 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the public IP prefix. | +| `resourceGroupName` | string | The resource group the public IP prefix was deployed into. | +| `resourceId` | string | The resource ID of the public IP prefix. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.2.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/public-ip-prefix/main.bicep b/avm/1.1.0/res/network/public-ip-prefix/main.bicep new file mode 100644 index 000000000..0c34ca0a7 --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-prefix/main.bicep @@ -0,0 +1,177 @@ +metadata name = 'Public IP Prefixes' +metadata description = 'This module deploys a Public IP Prefix.' + +@description('Required. The name of the Public IP Prefix.') +@minLength(1) +param name string + +@description('Optional. Tier of a public IP prefix SKU. If set to `Global`, the `zones` property must be empty.') +@allowed([ + 'Global' + 'Regional' +]) +param tier string = 'Regional' + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Required. Length of the Public IP Prefix.') +@minValue(21) +@maxValue(127) +param prefixLength int + +@description('Optional. The public IP address version.') +@allowed([ + 'IPv4' + 'IPv6' +]) +param publicIPAddressVersion string = 'IPv4' + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. The custom IP address prefix that this prefix is associated with. A custom IP address prefix is a contiguous range of IP addresses owned by an external customer and provisioned into a subscription. When a custom IP prefix is in Provisioned, Commissioning, or Commissioned state, a linked public IP prefix can be created. Either as a subset of the custom IP prefix range or the entire range.') +param customIPPrefix object = {} + +@description('Optional. The list of tags associated with the public IP prefix.') +param ipTags ipTagType[]? + +@description('Optional. A list of availability zones denoting the IP allocated for the resource needs to come from. This is only applicable for regional public IP prefixes and must be empty for global public IP prefixes.') +@allowed([ + 1 + 2 + 3 +]) +param zones int[] = [ + 1 + 2 + 3 +] + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-publicipprefix.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource publicIpPrefix 'Microsoft.Network/publicIPPrefixes@2024-01-01' = { + name: name + location: location + tags: tags + sku: { + name: 'Standard' + tier: tier + } + zones: map(zones, zone => string(zone)) + properties: { + customIPPrefix: !empty(customIPPrefix) ? customIPPrefix : null + publicIPAddressVersion: publicIPAddressVersion + prefixLength: prefixLength + ipTags: ipTags + } +} + +resource publicIpPrefix_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: publicIpPrefix +} + +resource publicIpPrefix_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(publicIpPrefix.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: publicIpPrefix + } +] + +@description('The resource ID of the public IP prefix.') +output resourceId string = publicIpPrefix.id + +@description('The resource group the public IP prefix was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the public IP prefix.') +output name string = publicIpPrefix.name + +@description('The location the resource was deployed into.') +output location string = publicIpPrefix.location + +// =============== // +// Definitions // +// =============== // + +@export() +type ipTagType = { + @description('Required. The IP tag type.') + ipTagType: string + + @description('Required. The IP tag.') + tag: string +} diff --git a/avm/1.1.0/res/network/public-ip-prefix/main.json b/avm/1.1.0/res/network/public-ip-prefix/main.json new file mode 100644 index 000000000..24942c7c3 --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-prefix/main.json @@ -0,0 +1,377 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "1837206327927302660" + }, + "name": "Public IP Prefixes", + "description": "This module deploys a Public IP Prefix." + }, + "definitions": { + "ipTagType": { + "type": "object", + "properties": { + "ipTagType": { + "type": "string", + "metadata": { + "description": "Required. The IP tag type." + } + }, + "tag": { + "type": "string", + "metadata": { + "description": "Required. The IP tag." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. The name of the Public IP Prefix." + } + }, + "tier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP prefix SKU. If set to `Global`, the `zones` property must be empty." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "prefixLength": { + "type": "int", + "minValue": 21, + "maxValue": 127, + "metadata": { + "description": "Required. Length of the Public IP Prefix." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. The public IP address version." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "customIPPrefix": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The custom IP address prefix that this prefix is associated with. A custom IP address prefix is a contiguous range of IP addresses owned by an external customer and provisioned into a subscription. When a custom IP prefix is in Provisioned, Commissioning, or Commissioned state, a linked public IP prefix can be created. Either as a subset of the custom IP prefix range or the entire range." + } + }, + "ipTags": { + "type": "array", + "items": { + "$ref": "#/definitions/ipTagType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of tags associated with the public IP prefix." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from. This is only applicable for regional public IP prefixes and must be empty for global public IP prefixes." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipprefix.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpPrefix": { + "type": "Microsoft.Network/publicIPPrefixes", + "apiVersion": "2024-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "Standard", + "tier": "[parameters('tier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "customIPPrefix": "[if(not(empty(parameters('customIPPrefix'))), parameters('customIPPrefix'), null())]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "prefixLength": "[parameters('prefixLength')]", + "ipTags": "[parameters('ipTags')]" + } + }, + "publicIpPrefix_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPPrefixes/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "publicIpPrefix" + ] + }, + "publicIpPrefix_roleAssignments": { + "copy": { + "name": "publicIpPrefix_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPPrefixes/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPPrefixes', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpPrefix" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP prefix." + }, + "value": "[resourceId('Microsoft.Network/publicIPPrefixes', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP prefix was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP prefix." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpPrefix', '2024-01-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..1c5839fb3 --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.publicipprefixes-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npipmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + prefixLength: 28 + } + } +] diff --git a/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/ipv6/main.test.bicep b/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/ipv6/main.test.bicep new file mode 100644 index 000000000..701807e26 --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/ipv6/main.test.bicep @@ -0,0 +1,50 @@ +targetScope = 'subscription' + +metadata name = 'IPv6 Public IP Prefix' +metadata description = 'This instance deploys the module using the IPv6 version of the Public IP Prefix.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.publicipprefixes-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npipip6' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + prefixLength: 127 + publicIPAddressVersion: 'IPv6' + } + } +] diff --git a/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7b3d4e8fb --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..c9148cc77 --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/max/main.test.bicep @@ -0,0 +1,99 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.publicipprefixes-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npipmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + prefixLength: 28 + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'bf62ed65-07be-48e8-b760-2d59795cd282' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + zones: [ + 1 + 2 + ] + ipTags: [ + { + ipTagType: 'RoutingPreference' + tag: 'Internet' + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..7b3d4e8fb --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..ce435763a --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-prefix/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,54 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.publicipprefixes-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'npipwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + prefixLength: 28 + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/public-ip-prefix/version.json b/avm/1.1.0/res/network/public-ip-prefix/version.json new file mode 100644 index 000000000..21226dd43 --- /dev/null +++ b/avm/1.1.0/res/network/public-ip-prefix/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.6", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/route-table/README.md b/avm/1.1.0/res/network/route-table/README.md new file mode 100644 index 000000000..8e00dd425 --- /dev/null +++ b/avm/1.1.0/res/network/route-table/README.md @@ -0,0 +1,699 @@ +# Route Tables `[Microsoft.Network/routeTables]` + +This module deploys a User Defined Route Table (UDR). + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/routeTables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/routeTables) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/route-table:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module routeTable 'br/public:avm/res/network/route-table:' = { + name: 'routeTableDeployment' + params: { + // Required parameters + name: 'nrtmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nrtmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/route-table:' + +// Required parameters +param name = 'nrtmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module routeTable 'br/public:avm/res/network/route-table:' = { + name: 'routeTableDeployment' + params: { + // Required parameters + name: 'nrtmax001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'de4b134c-7087-480d-892f-ce6629720d29' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + routes: [ + { + name: 'default' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopIpAddress: '172.16.0.20' + nextHopType: 'VirtualAppliance' + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nrtmax001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "de4b134c-7087-480d-892f-ce6629720d29", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "routes": { + "value": [ + { + "name": "default", + "properties": { + "addressPrefix": "0.0.0.0/0", + "nextHopIpAddress": "172.16.0.20", + "nextHopType": "VirtualAppliance" + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/route-table:' + +// Required parameters +param name = 'nrtmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'de4b134c-7087-480d-892f-ce6629720d29' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param routes = [ + { + name: 'default' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopIpAddress: '172.16.0.20' + nextHopType: 'VirtualAppliance' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module routeTable 'br/public:avm/res/network/route-table:' = { + name: 'routeTableDeployment' + params: { + // Required parameters + name: 'nrtwaf001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + routes: [ + { + name: 'default' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopIpAddress: '172.16.0.20' + nextHopType: 'VirtualAppliance' + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nrtwaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "routes": { + "value": [ + { + "name": "default", + "properties": { + "addressPrefix": "0.0.0.0/0", + "nextHopIpAddress": "172.16.0.20", + "nextHopType": "VirtualAppliance" + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/route-table:' + +// Required parameters +param name = 'nrtwaf001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param routes = [ + { + name: 'default' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopIpAddress: '172.16.0.20' + nextHopType: 'VirtualAppliance' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name given for the hub route table. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`disableBgpRoutePropagation`](#parameter-disablebgproutepropagation) | bool | Switch to disable BGP route propagation. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`routes`](#parameter-routes) | array | An array of routes to be established within the hub route table. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `name` + +Name given for the hub route table. + +- Required: Yes +- Type: string + +### Parameter: `disableBgpRoutePropagation` + +Switch to disable BGP route propagation. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `routes` + +An array of routes to be established within the hub route table. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-routesname) | string | Name of the route. | +| [`properties`](#parameter-routesproperties) | object | Properties of the route. | + +### Parameter: `routes.name` + +Name of the route. + +- Required: Yes +- Type: string + +### Parameter: `routes.properties` + +Properties of the route. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`nextHopType`](#parameter-routespropertiesnexthoptype) | string | The type of Azure hop the packet should be sent to. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefix`](#parameter-routespropertiesaddressprefix) | string | The destination CIDR to which the route applies. | +| [`hasBgpOverride`](#parameter-routespropertieshasbgpoverride) | bool | A value indicating whether this route overrides overlapping BGP routes regardless of LPM. | +| [`nextHopIpAddress`](#parameter-routespropertiesnexthopipaddress) | string | The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance. | + +### Parameter: `routes.properties.nextHopType` + +The type of Azure hop the packet should be sent to. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Internet' + 'None' + 'VirtualAppliance' + 'VirtualNetworkGateway' + 'VnetLocal' + ] + ``` + +### Parameter: `routes.properties.addressPrefix` + +The destination CIDR to which the route applies. + +- Required: No +- Type: string + +### Parameter: `routes.properties.hasBgpOverride` + +A value indicating whether this route overrides overlapping BGP routes regardless of LPM. + +- Required: No +- Type: bool + +### Parameter: `routes.properties.nextHopIpAddress` + +The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance. + +- Required: No +- Type: string + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the route table. | +| `resourceGroupName` | string | The resource group the route table was deployed into. | +| `resourceId` | string | The resource ID of the route table. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/route-table/main.bicep b/avm/1.1.0/res/network/route-table/main.bicep new file mode 100644 index 000000000..90cfae6f7 --- /dev/null +++ b/avm/1.1.0/res/network/route-table/main.bicep @@ -0,0 +1,184 @@ +metadata name = 'Route Tables' +metadata description = 'This module deploys a User Defined Route Table (UDR).' + +@description('Required. Name given for the hub route table.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. An array of routes to be established within the hub route table.') +param routes routeType + +@description('Optional. Switch to disable BGP route propagation.') +param disableBgpRoutePropagation bool = false + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.res.network-routetable.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource routeTable 'Microsoft.Network/routeTables@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + routes: routes + disableBgpRoutePropagation: disableBgpRoutePropagation + } +} + +resource routeTable_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: routeTable +} + +resource routeTable_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(routeTable.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: routeTable + } +] + +@description('The resource group the route table was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the route table.') +output name string = routeTable.name + +@description('The resource ID of the route table.') +output resourceId string = routeTable.id + +@description('The location the resource was deployed into.') +output location string = routeTable.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type routeType = { + @description('Required. Name of the route.') + name: string + + @description('Required. Properties of the route.') + properties: { + @description('Required. The type of Azure hop the packet should be sent to.') + nextHopType: ('VirtualAppliance' | 'VnetLocal' | 'Internet' | 'VirtualNetworkGateway' | 'None') + + @description('Optional. The destination CIDR to which the route applies.') + addressPrefix: string? + + @description('Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM.') + hasBgpOverride: bool? + + @description('Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance.') + nextHopIpAddress: string? + } +}[]? diff --git a/avm/1.1.0/res/network/route-table/main.json b/avm/1.1.0/res/network/route-table/main.json new file mode 100644 index 000000000..1c64b6221 --- /dev/null +++ b/avm/1.1.0/res/network/route-table/main.json @@ -0,0 +1,341 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "142872509148371547" + }, + "name": "Route Tables", + "description": "This module deploys a User Defined Route Table (UDR)." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "routeType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the route." + } + }, + "properties": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "None", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The type of Azure hop the packet should be sent to." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination CIDR to which the route applies." + } + }, + "hasBgpOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." + } + }, + "nextHopIpAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "description": "Required. Properties of the route." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name given for the hub route table." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "routes": { + "$ref": "#/definitions/routeType", + "metadata": { + "description": "Optional. An array of routes to be established within the hub route table." + } + }, + "disableBgpRoutePropagation": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Switch to disable BGP route propagation." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "routeTable": { + "type": "Microsoft.Network/routeTables", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "routes": "[parameters('routes')]", + "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" + } + }, + "routeTable_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/routeTables/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "routeTable" + ] + }, + "routeTable_roleAssignments": { + "copy": { + "name": "routeTable_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/routeTables/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/routeTables', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "routeTable" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the route table was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the route table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the route table." + }, + "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('routeTable', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/route-table/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/route-table/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..63c29b775 --- /dev/null +++ b/avm/1.1.0/res/network/route-table/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,45 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.routetables-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nrtmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } +} diff --git a/avm/1.1.0/res/network/route-table/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/route-table/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/network/route-table/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/route-table/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/route-table/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..b10d8ee6a --- /dev/null +++ b/avm/1.1.0/res/network/route-table/tests/e2e/max/main.test.bicep @@ -0,0 +1,95 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.routetables-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nrtmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'de4b134c-7087-480d-892f-ce6629720d29' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + routes: [ + { + name: 'default' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopIpAddress: '172.16.0.20' + nextHopType: 'VirtualAppliance' + } + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} diff --git a/avm/1.1.0/res/network/route-table/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/route-table/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..c0f75ab89 --- /dev/null +++ b/avm/1.1.0/res/network/route-table/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,64 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.routetables-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nrtwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + routes: [ + { + name: 'default' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopIpAddress: '172.16.0.20' + nextHopType: 'VirtualAppliance' + } + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} diff --git a/avm/1.1.0/res/network/route-table/version.json b/avm/1.1.0/res/network/route-table/version.json new file mode 100644 index 000000000..3f863a2be --- /dev/null +++ b/avm/1.1.0/res/network/route-table/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.4", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/service-endpoint-policy/README.md b/avm/1.1.0/res/network/service-endpoint-policy/README.md new file mode 100644 index 000000000..7bfd1efde --- /dev/null +++ b/avm/1.1.0/res/network/service-endpoint-policy/README.md @@ -0,0 +1,555 @@ +# Service-Endpoint-Policy `[Microsoft.Network/serviceEndpointPolicies]` + +This module deploys a Service Endpoint Policy. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/serviceEndpointPolicies` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/serviceEndpointPolicies) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/service-endpoint-policy:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:' = { + name: 'serviceEndpointPolicyDeployment' + params: { + // Required parameters + name: 'nsepmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nsepmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/service-endpoint-policy:' + +// Required parameters +param name = 'nsepmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:' = { + name: 'serviceEndpointPolicyDeployment' + params: { + // Required parameters + name: 'nsepmax001' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '36fbc5db-13e9-4bda-9594-1b1cc9db2d6d' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nsepmax001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "36fbc5db-13e9-4bda-9594-1b1cc9db2d6d", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/service-endpoint-policy:' + +// Required parameters +param name = 'nsepmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '36fbc5db-13e9-4bda-9594-1b1cc9db2d6d' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:' = { + name: 'serviceEndpointPolicyDeployment' + params: { + // Required parameters + name: 'nsepwaf001' + // Non-required parameters + location: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nsepwaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/service-endpoint-policy:' + +// Required parameters +param name = 'nsepwaf001' +// Non-required parameters +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Service Endpoint Policy to create. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`contextualServiceEndpointPolicies`](#parameter-contextualserviceendpointpolicies) | array | An Array of contextual service endpoint policy. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`serviceAlias`](#parameter-servicealias) | string | The alias indicating if the policy belongs to a service. | +| [`serviceEndpointPolicyDefinitions`](#parameter-serviceendpointpolicydefinitions) | array | An Array of service endpoint policy definitions. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `name` + +Name of the Service Endpoint Policy to create. + +- Required: Yes +- Type: string + +### Parameter: `contextualServiceEndpointPolicies` + +An Array of contextual service endpoint policy. + +- Required: No +- Type: array + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `serviceAlias` + +The alias indicating if the policy belongs to a service. + +- Required: No +- Type: string + +### Parameter: `serviceEndpointPolicyDefinitions` + +An Array of service endpoint policy definitions. + +- Required: No +- Type: array + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the Service Endpoint Policy. | +| `resourceGroupName` | string | The resource group the Service Endpoint Policy was deployed into. | +| `resourceId` | string | The resource ID of the Service Endpoint Policy. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/service-endpoint-policy/main.bicep b/avm/1.1.0/res/network/service-endpoint-policy/main.bicep new file mode 100644 index 000000000..9b6ebe432 --- /dev/null +++ b/avm/1.1.0/res/network/service-endpoint-policy/main.bicep @@ -0,0 +1,179 @@ +metadata name = 'Service-Endpoint-Policy' +metadata description = 'This module deploys a Service Endpoint Policy.' + +@description('Required. Name of the Service Endpoint Policy to create.') +@minLength(1) +@maxLength(60) +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. An Array of service endpoint policy definitions.') +param serviceEndpointPolicyDefinitions array? + +@description('Optional. An Array of contextual service endpoint policy.') +param contextualServiceEndpointPolicies array? + +@description('Optional. The alias indicating if the policy belongs to a service.') +param serviceAlias string? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-serviceendpointpolicy.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource serviceEndpointPolicy 'Microsoft.Network/serviceEndpointPolicies@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + serviceAlias: serviceAlias + contextualServiceEndpointPolicies: contextualServiceEndpointPolicies + serviceEndpointPolicyDefinitions: serviceEndpointPolicyDefinitions + } +} + +resource serviceEndpointPolicy_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: serviceEndpointPolicy +} + +resource serviceEndpointPolicy_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + serviceEndpointPolicy.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: serviceEndpointPolicy + } +] + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +// ================ // +// Definitions // +// ================ // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +@description('The resource group the Service Endpoint Policy was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the Service Endpoint Policy.') +output name string = serviceEndpointPolicy.name + +@description('The resource ID of the Service Endpoint Policy.') +output resourceId string = serviceEndpointPolicy.id + +@description('The location the resource was deployed into.') +output location string = serviceEndpointPolicy.location diff --git a/avm/1.1.0/res/network/service-endpoint-policy/main.json b/avm/1.1.0/res/network/service-endpoint-policy/main.json new file mode 100644 index 000000000..eea6a2113 --- /dev/null +++ b/avm/1.1.0/res/network/service-endpoint-policy/main.json @@ -0,0 +1,295 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "2116868468266307630" + }, + "name": "Service-Endpoint-Policy", + "description": "This module deploys a Service Endpoint Policy." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 60, + "metadata": { + "description": "Required. Name of the Service Endpoint Policy to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "serviceEndpointPolicyDefinitions": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. An Array of service endpoint policy definitions." + } + }, + "contextualServiceEndpointPolicies": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. An Array of contextual service endpoint policy." + } + }, + "serviceAlias": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The alias indicating if the policy belongs to a service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-serviceendpointpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "serviceEndpointPolicy": { + "type": "Microsoft.Network/serviceEndpointPolicies", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "serviceAlias": "[parameters('serviceAlias')]", + "contextualServiceEndpointPolicies": "[parameters('contextualServiceEndpointPolicies')]", + "serviceEndpointPolicyDefinitions": "[parameters('serviceEndpointPolicyDefinitions')]" + } + }, + "serviceEndpointPolicy_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/serviceEndpointPolicies/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "serviceEndpointPolicy" + ] + }, + "serviceEndpointPolicy_roleAssignments": { + "copy": { + "name": "serviceEndpointPolicy_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/serviceEndpointPolicies/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/serviceEndpointPolicies', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "serviceEndpointPolicy" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Service Endpoint Policy was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Service Endpoint Policy." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Service Endpoint Policy." + }, + "value": "[resourceId('Microsoft.Network/serviceEndpointPolicies', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('serviceEndpointPolicy', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..6a594af1c --- /dev/null +++ b/avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,47 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.serviceendpointpolicy-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nsepmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7b3d4e8fb --- /dev/null +++ b/avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..43504b459 --- /dev/null +++ b/avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/max/main.test.bicep @@ -0,0 +1,87 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.serviceendpointpolicy-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nsepmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '36fbc5db-13e9-4bda-9594-1b1cc9db2d6d' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..b2c6f1928 --- /dev/null +++ b/avm/1.1.0/res/network/service-endpoint-policy/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,52 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.serviceendpointpolicy-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nsepwaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/service-endpoint-policy/version.json b/avm/1.1.0/res/network/service-endpoint-policy/version.json new file mode 100644 index 000000000..76049e1c4 --- /dev/null +++ b/avm/1.1.0/res/network/service-endpoint-policy/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/trafficmanagerprofile/README.md b/avm/1.1.0/res/network/trafficmanagerprofile/README.md new file mode 100644 index 000000000..707111d93 --- /dev/null +++ b/avm/1.1.0/res/network/trafficmanagerprofile/README.md @@ -0,0 +1,979 @@ +# Traffic Manager Profiles `[Microsoft.Network/trafficmanagerprofiles]` + +This module deploys a Traffic Manager Profile. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/trafficmanagerprofiles` | [2018-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2018-08-01/trafficmanagerprofiles) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/trafficmanagerprofile:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:' = { + name: 'trafficmanagerprofileDeployment' + params: { + // Required parameters + name: 'ntmpmin001' + // Non-required parameters + location: 'global' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ntmpmin001" + }, + // Non-required parameters + "location": { + "value": "global" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/trafficmanagerprofile:' + +// Required parameters +param name = 'ntmpmin001' +// Non-required parameters +param location = 'global' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:' = { + name: 'trafficmanagerprofileDeployment' + params: { + // Required parameters + name: 'ntmpmax001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: 'global' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + relativeName: 'ntmpmax001-rn' + roleAssignments: [ + { + name: '76e7bd82-b689-4072-87be-519bfabf733e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ntmpmax001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "global" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "relativeName": { + "value": "ntmpmax001-rn" + }, + "roleAssignments": { + "value": [ + { + "name": "76e7bd82-b689-4072-87be-519bfabf733e", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/trafficmanagerprofile:' + +// Required parameters +param name = 'ntmpmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param relativeName = 'ntmpmax001-rn' +param roleAssignments = [ + { + name: '76e7bd82-b689-4072-87be-519bfabf733e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:' = { + name: 'trafficmanagerprofileDeployment' + params: { + // Required parameters + name: 'ntmpwaf001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + endpoints: [ + { + name: 'webApp01Endpoint' + properties: { + endpointLocation: '' + endpointStatus: 'Enabled' + priority: 1 + targetResourceId: '' + weight: 1 + } + type: 'Microsoft.Network/trafficManagerProfiles/azureEndpoints' + } + { + name: 'webApp02Endpoint' + properties: { + endpointLocation: '' + endpointStatus: 'Enabled' + priority: 2 + targetResourceId: '' + weight: 1 + } + type: 'Microsoft.Network/trafficManagerProfiles/azureEndpoints' + } + ] + location: 'global' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + monitorConfig: { + path: '/' + port: '443' + protocol: 'https' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ntmpwaf001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "endpoints": { + "value": [ + { + "name": "webApp01Endpoint", + "properties": { + "endpointLocation": "", + "endpointStatus": "Enabled", + "priority": 1, + "targetResourceId": "", + "weight": 1 + }, + "type": "Microsoft.Network/trafficManagerProfiles/azureEndpoints" + }, + { + "name": "webApp02Endpoint", + "properties": { + "endpointLocation": "", + "endpointStatus": "Enabled", + "priority": 2, + "targetResourceId": "", + "weight": 1 + }, + "type": "Microsoft.Network/trafficManagerProfiles/azureEndpoints" + } + ] + }, + "location": { + "value": "global" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "monitorConfig": { + "value": { + "path": "/", + "port": "443", + "protocol": "https" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/trafficmanagerprofile:' + +// Required parameters +param name = 'ntmpwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param endpoints = [ + { + name: 'webApp01Endpoint' + properties: { + endpointLocation: '' + endpointStatus: 'Enabled' + priority: 1 + targetResourceId: '' + weight: 1 + } + type: 'Microsoft.Network/trafficManagerProfiles/azureEndpoints' + } + { + name: 'webApp02Endpoint' + properties: { + endpointLocation: '' + endpointStatus: 'Enabled' + priority: 2 + targetResourceId: '' + weight: 1 + } + type: 'Microsoft.Network/trafficManagerProfiles/azureEndpoints' + } +] +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param monitorConfig = { + path: '/' + port: '443' + protocol: 'https' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Traffic Manager. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`endpoints`](#parameter-endpoints) | array | The list of endpoints in the Traffic Manager profile. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`maxReturn`](#parameter-maxreturn) | int | Maximum number of endpoints to be returned for MultiValue routing type. | +| [`monitorConfig`](#parameter-monitorconfig) | object | The endpoint monitoring settings of the Traffic Manager profile. | +| [`profileStatus`](#parameter-profilestatus) | string | The status of the Traffic Manager profile. | +| [`relativeName`](#parameter-relativename) | string | The relative DNS name provided by this Traffic Manager profile. This value is combined with the DNS domain name used by Azure Traffic Manager to form the fully-qualified domain name (FQDN) of the profile. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Resource tags. | +| [`trafficRoutingMethod`](#parameter-trafficroutingmethod) | string | The traffic routing method of the Traffic Manager profile. | +| [`trafficViewEnrollmentStatus`](#parameter-trafficviewenrollmentstatus) | string | Indicates whether Traffic View is 'Enabled' or 'Disabled' for the Traffic Manager profile. Null, indicates 'Disabled'. Enabling this feature will increase the cost of the Traffic Manage profile. | +| [`ttl`](#parameter-ttl) | int | The DNS Time-To-Live (TTL), in seconds. This informs the local DNS resolvers and DNS clients how long to cache DNS responses provided by this Traffic Manager profile. | + +### Parameter: `name` + +Name of the Traffic Manager. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `endpoints` + +The list of endpoints in the Traffic Manager profile. + +- Required: No +- Type: array + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `'global'` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `maxReturn` + +Maximum number of endpoints to be returned for MultiValue routing type. + +- Required: No +- Type: int +- Default: `1` + +### Parameter: `monitorConfig` + +The endpoint monitoring settings of the Traffic Manager profile. + +- Required: No +- Type: object +- Default: + ```Bicep + { + path: '/' + port: '80' + protocol: 'http' + } + ``` + +### Parameter: `profileStatus` + +The status of the Traffic Manager profile. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `relativeName` + +The relative DNS name provided by this Traffic Manager profile. This value is combined with the DNS domain name used by Azure Traffic Manager to form the fully-qualified domain name (FQDN) of the profile. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'Traffic Manager Contributor'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object + +### Parameter: `trafficRoutingMethod` + +The traffic routing method of the Traffic Manager profile. + +- Required: No +- Type: string +- Default: `'Performance'` +- Allowed: + ```Bicep + [ + 'Geographic' + 'MultiValue' + 'Performance' + 'Priority' + 'Subnet' + 'Weighted' + ] + ``` + +### Parameter: `trafficViewEnrollmentStatus` + +Indicates whether Traffic View is 'Enabled' or 'Disabled' for the Traffic Manager profile. Null, indicates 'Disabled'. Enabling this feature will increase the cost of the Traffic Manage profile. + +- Required: No +- Type: string +- Default: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `ttl` + +The DNS Time-To-Live (TTL), in seconds. This informs the local DNS resolvers and DNS clients how long to cache DNS responses provided by this Traffic Manager profile. + +- Required: No +- Type: int +- Default: `60` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the traffic manager was deployed into. | +| `resourceGroupName` | string | The resource group the traffic manager was deployed into. | +| `resourceId` | string | The resource ID of the traffic manager. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/trafficmanagerprofile/main.bicep b/avm/1.1.0/res/network/trafficmanagerprofile/main.bicep new file mode 100644 index 000000000..56c3e4af5 --- /dev/null +++ b/avm/1.1.0/res/network/trafficmanagerprofile/main.bicep @@ -0,0 +1,289 @@ +metadata name = 'Traffic Manager Profiles' +metadata description = 'This module deploys a Traffic Manager Profile.' + +@description('Required. Name of the Traffic Manager.') +@minLength(1) +param name string + +@description('Optional. The status of the Traffic Manager profile.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param profileStatus string = 'Enabled' + +@description('Optional. The traffic routing method of the Traffic Manager profile.') +@allowed([ + 'Performance' + 'Priority' + 'Weighted' + 'Geographic' + 'MultiValue' + 'Subnet' +]) +param trafficRoutingMethod string = 'Performance' + +@description('Optional. The relative DNS name provided by this Traffic Manager profile. This value is combined with the DNS domain name used by Azure Traffic Manager to form the fully-qualified domain name (FQDN) of the profile.') +param relativeName string? + +@description('Optional. The DNS Time-To-Live (TTL), in seconds. This informs the local DNS resolvers and DNS clients how long to cache DNS responses provided by this Traffic Manager profile.') +param ttl int = 60 + +@description('Optional. The endpoint monitoring settings of the Traffic Manager profile.') +param monitorConfig object = { + protocol: 'http' + port: '80' + path: '/' +} + +@description('Optional. The list of endpoints in the Traffic Manager profile.') +param endpoints array? + +@description('Optional. Indicates whether Traffic View is \'Enabled\' or \'Disabled\' for the Traffic Manager profile. Null, indicates \'Disabled\'. Enabling this feature will increase the cost of the Traffic Manage profile.') +@allowed([ + 'Disabled' + 'Enabled' +]) +param trafficViewEnrollmentStatus string = 'Disabled' + +@description('Optional. Maximum number of endpoints to be returned for MultiValue routing type.') +param maxReturn int = 1 + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Resource tags.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Location for all resources.') +param location string = 'global' + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator (Preview)': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'Traffic Manager Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a4b10055-b0c7-44c2-b00f-c7b5b3550cf7' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-trafficmanagerprofile.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource trafficManagerProfile 'Microsoft.Network/trafficmanagerprofiles@2018-08-01' = { + name: name + tags: tags + location: location + properties: { + profileStatus: profileStatus + trafficRoutingMethod: trafficRoutingMethod + dnsConfig: { + relativeName: relativeName ?? name + ttl: ttl + } + monitorConfig: monitorConfig + endpoints: endpoints + trafficViewEnrollmentStatus: trafficViewEnrollmentStatus + maxReturn: maxReturn + } +} + +resource trafficManagerProfile_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: trafficManagerProfile +} + +resource trafficManagerProfile_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: trafficManagerProfile + } +] + +resource trafficManagerProfile_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + trafficManagerProfile.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: trafficManagerProfile + } +] + +@description('The resource ID of the traffic manager.') +output resourceId string = trafficManagerProfile.id + +@description('The resource group the traffic manager was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the traffic manager was deployed into.') +output name string = trafficManagerProfile.name + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? diff --git a/avm/1.1.0/res/network/trafficmanagerprofile/main.json b/avm/1.1.0/res/network/trafficmanagerprofile/main.json new file mode 100644 index 000000000..c1930560f --- /dev/null +++ b/avm/1.1.0/res/network/trafficmanagerprofile/main.json @@ -0,0 +1,517 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "11605312251380139630" + }, + "name": "Traffic Manager Profiles", + "description": "This module deploys a Traffic Manager Profile." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the Traffic Manager." + } + }, + "profileStatus": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The status of the Traffic Manager profile." + } + }, + "trafficRoutingMethod": { + "type": "string", + "defaultValue": "Performance", + "allowedValues": [ + "Performance", + "Priority", + "Weighted", + "Geographic", + "MultiValue", + "Subnet" + ], + "metadata": { + "description": "Optional. The traffic routing method of the Traffic Manager profile." + } + }, + "relativeName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The relative DNS name provided by this Traffic Manager profile. This value is combined with the DNS domain name used by Azure Traffic Manager to form the fully-qualified domain name (FQDN) of the profile." + } + }, + "ttl": { + "type": "int", + "defaultValue": 60, + "metadata": { + "description": "Optional. The DNS Time-To-Live (TTL), in seconds. This informs the local DNS resolvers and DNS clients how long to cache DNS responses provided by this Traffic Manager profile." + } + }, + "monitorConfig": { + "type": "object", + "defaultValue": { + "protocol": "http", + "port": "80", + "path": "/" + }, + "metadata": { + "description": "Optional. The endpoint monitoring settings of the Traffic Manager profile." + } + }, + "endpoints": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of endpoints in the Traffic Manager profile." + } + }, + "trafficViewEnrollmentStatus": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Indicates whether Traffic View is 'Enabled' or 'Disabled' for the Traffic Manager profile. Null, indicates 'Disabled'. Enabling this feature will increase the cost of the Traffic Manage profile." + } + }, + "maxReturn": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Optional. Maximum number of endpoints to be returned for MultiValue routing type." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. Location for all resources." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Traffic Manager Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a4b10055-b0c7-44c2-b00f-c7b5b3550cf7')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-trafficmanagerprofile.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "trafficManagerProfile": { + "type": "Microsoft.Network/trafficmanagerprofiles", + "apiVersion": "2018-08-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "profileStatus": "[parameters('profileStatus')]", + "trafficRoutingMethod": "[parameters('trafficRoutingMethod')]", + "dnsConfig": { + "relativeName": "[coalesce(parameters('relativeName'), parameters('name'))]", + "ttl": "[parameters('ttl')]" + }, + "monitorConfig": "[parameters('monitorConfig')]", + "endpoints": "[parameters('endpoints')]", + "trafficViewEnrollmentStatus": "[parameters('trafficViewEnrollmentStatus')]", + "maxReturn": "[parameters('maxReturn')]" + } + }, + "trafficManagerProfile_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/trafficmanagerprofiles/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "trafficManagerProfile" + ] + }, + "trafficManagerProfile_diagnosticSettings": { + "copy": { + "name": "trafficManagerProfile_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/trafficmanagerprofiles/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "trafficManagerProfile" + ] + }, + "trafficManagerProfile_roleAssignments": { + "copy": { + "name": "trafficManagerProfile_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/trafficmanagerprofiles/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/trafficmanagerprofiles', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "trafficManagerProfile" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the traffic manager." + }, + "value": "[resourceId('Microsoft.Network/trafficmanagerprofiles', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the traffic manager was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the traffic manager was deployed into." + }, + "value": "[parameters('name')]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..821e67a2c --- /dev/null +++ b/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,47 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.trafficmanagerprofiles-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ntmpmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + } + } +] diff --git a/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..a47795806 --- /dev/null +++ b/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/max/main.test.bicep @@ -0,0 +1,116 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.trafficmanagerprofiles-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ntmpmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + relativeName: '${namePrefix}${serviceShort}001-rn' + location: 'global' + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '76e7bd82-b689-4072-87be-519bfabf733e' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..0239ada31 --- /dev/null +++ b/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,81 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Optional. The location to deploy the first App Service Plan to.') +param location01 string + +@description('Optional. The location to deploy the second App Service Plan to.') +param location02 string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource serverFarm01 'Microsoft.Web/serverfarms@2022-03-01' = { + name: serverFarmName01 + location: location01 + sku: { + name: 'S1' + tier: 'Standard' + size: 'S1' + family: 'S' + capacity: 1 + } + properties: {} +} + +resource serverFarm02 'Microsoft.Web/serverfarms@2022-03-01' = { + name: serverFarmName02 + location: location02 + sku: { + name: 'S1' + tier: 'Standard' + size: 'S1' + family: 'S' + capacity: 1 + } + properties: {} +} + +resource webApp01 'Microsoft.Web/sites@2022-09-01' = { + name: webApp01Name + location: location01 + kind: 'app' + properties: { + serverFarmId: serverFarm01.id + } +} + +resource webApp02 'Microsoft.Web/sites@2022-09-01' = { + name: webApp02Name + location: location02 + kind: 'app' + properties: { + serverFarmId: serverFarm02.id + } +} + +@description('Required. The name of the first App Service Plan to create.') +param serverFarmName01 string + +@description('Required. The name of the second App Service Plan to create.') +param serverFarmName02 string + +@description('Required. The name of the first Web Applicaton to create.') +param webApp01Name string + +@description('Required. The name of the second Web Applicaton to create.') +param webApp02Name string + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the first created Web Application') +output webApp01ResourceId string = webApp01.id + +@description('The resource ID of the second created Web Application') +output webApp02ResourceId string = webApp02.id diff --git a/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..1cec1b3b4 --- /dev/null +++ b/avm/1.1.0/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,131 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.trafficmanagerprofiles-${serviceShort}-rg' + +#disable-next-line no-hardcoded-location +var enforcedLocation01 = 'uksouth' + +#disable-next-line no-hardcoded-location +var enforcedLocation02 = 'ukwest' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ntmpwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation01 +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation01)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: enforcedLocation01 + serverFarmName01: 'dep-${namePrefix}-sf-${serviceShort}01' + serverFarmName02: 'dep-${namePrefix}-sf-${serviceShort}02' + webApp01Name: 'dep-${namePrefix}-wa-${serviceShort}01' + webApp02Name: 'dep-${namePrefix}-wa-${serviceShort}02' + location01: enforcedLocation01 + location02: enforcedLocation02 + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation01)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: enforcedLocation01 + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation01)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: 'global' + monitorConfig: { + protocol: 'https' + port: '443' + path: '/' + } + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + endpoints: [ + { + name: 'webApp01Endpoint' + type: 'Microsoft.Network/trafficManagerProfiles/azureEndpoints' + properties: { + targetResourceId: nestedDependencies.outputs.webApp01ResourceId + weight: 1 + priority: 1 + endpointLocation: enforcedLocation01 + endpointStatus: 'Enabled' + } + } + { + name: 'webApp02Endpoint' + type: 'Microsoft.Network/trafficManagerProfiles/azureEndpoints' + properties: { + targetResourceId: nestedDependencies.outputs.webApp02ResourceId + weight: 1 + priority: 2 + endpointLocation: enforcedLocation02 + endpointStatus: 'Enabled' + } + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/trafficmanagerprofile/version.json b/avm/1.1.0/res/network/trafficmanagerprofile/version.json new file mode 100644 index 000000000..729ac8767 --- /dev/null +++ b/avm/1.1.0/res/network/trafficmanagerprofile/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.2", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-hub/README.md b/avm/1.1.0/res/network/virtual-hub/README.md new file mode 100644 index 000000000..1f2cfbe4f --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/README.md @@ -0,0 +1,934 @@ +# Virtual Hubs `[Microsoft.Network/virtualHubs]` + +This module deploys a Virtual Hub. +If you are planning to deploy a Secure Virtual Hub (with an Azure Firewall integrated), please refer to the Azure Firewall module. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## 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.Network/virtualHubs` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/virtualHubs) | +| `Microsoft.Network/virtualHubs/hubRouteTables` | [2022-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-11-01/virtualHubs/hubRouteTables) | +| `Microsoft.Network/virtualHubs/hubVirtualNetworkConnections` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-01-01/virtualHubs/hubVirtualNetworkConnections) | +| `Microsoft.Network/virtualHubs/routingIntent` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/virtualHubs/routingIntent) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/virtual-hub:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [Using Routing Intent](#example-3-using-routing-intent) +- [WAF-aligned](#example-4-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module virtualHub 'br/public:avm/res/network/virtual-hub:' = { + name: 'virtualHubDeployment' + params: { + // Required parameters + addressPrefix: '10.0.0.0/16' + name: 'nvhmin' + virtualWanId: '' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "addressPrefix": { + "value": "10.0.0.0/16" + }, + "name": { + "value": "nvhmin" + }, + "virtualWanId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-hub:' + +// Required parameters +param addressPrefix = '10.0.0.0/16' +param name = 'nvhmin' +param virtualWanId = '' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module virtualHub 'br/public:avm/res/network/virtual-hub:' = { + name: 'virtualHubDeployment' + params: { + // Required parameters + addressPrefix: '10.1.0.0/16' + name: 'nvhmax' + virtualWanId: '' + // Non-required parameters + hubRouteTables: [ + { + name: 'routeTable1' + } + ] + hubVirtualNetworkConnections: [ + { + name: 'connection1' + remoteVirtualNetworkId: '' + routingConfiguration: { + associatedRouteTable: { + id: '' + } + propagatedRouteTables: { + ids: [ + { + id: '' + } + ] + labels: [ + 'none' + ] + } + } + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "addressPrefix": { + "value": "10.1.0.0/16" + }, + "name": { + "value": "nvhmax" + }, + "virtualWanId": { + "value": "" + }, + // Non-required parameters + "hubRouteTables": { + "value": [ + { + "name": "routeTable1" + } + ] + }, + "hubVirtualNetworkConnections": { + "value": [ + { + "name": "connection1", + "remoteVirtualNetworkId": "", + "routingConfiguration": { + "associatedRouteTable": { + "id": "" + }, + "propagatedRouteTables": { + "ids": [ + { + "id": "" + } + ], + "labels": [ + "none" + ] + } + } + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-hub:' + +// Required parameters +param addressPrefix = '10.1.0.0/16' +param name = 'nvhmax' +param virtualWanId = '' +// Non-required parameters +param hubRouteTables = [ + { + name: 'routeTable1' + } +] +param hubVirtualNetworkConnections = [ + { + name: 'connection1' + remoteVirtualNetworkId: '' + routingConfiguration: { + associatedRouteTable: { + id: '' + } + propagatedRouteTables: { + ids: [ + { + id: '' + } + ] + labels: [ + 'none' + ] + } + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _Using Routing Intent_ + +This instance deploys the module the Virtual WAN hub with Routing Intent enabled; requires an existing Virtual Hub, as well the firewall Resource ID. + + +

+ +via Bicep module + +```bicep +module virtualHub 'br/public:avm/res/network/virtual-hub:' = { + name: 'virtualHubDeployment' + params: { + // Required parameters + addressPrefix: '10.10.0.0/23' + name: 'nvhrtint' + virtualWanId: '' + // Non-required parameters + azureFirewallResourceId: '' + hubRouteTables: [] + hubRoutingPreference: 'ASPath' + hubVirtualNetworkConnections: [ + { + name: 'connection1' + remoteVirtualNetworkId: '' + routingConfiguration: {} + } + ] + internetToFirewall: false + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + privateToFirewall: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "addressPrefix": { + "value": "10.10.0.0/23" + }, + "name": { + "value": "nvhrtint" + }, + "virtualWanId": { + "value": "" + }, + // Non-required parameters + "azureFirewallResourceId": { + "value": "" + }, + "hubRouteTables": { + "value": [] + }, + "hubRoutingPreference": { + "value": "ASPath" + }, + "hubVirtualNetworkConnections": { + "value": [ + { + "name": "connection1", + "remoteVirtualNetworkId": "", + "routingConfiguration": {} + } + ] + }, + "internetToFirewall": { + "value": false + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "privateToFirewall": { + "value": true + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-hub:' + +// Required parameters +param addressPrefix = '10.10.0.0/23' +param name = 'nvhrtint' +param virtualWanId = '' +// Non-required parameters +param azureFirewallResourceId = '' +param hubRouteTables = [] +param hubRoutingPreference = 'ASPath' +param hubVirtualNetworkConnections = [ + { + name: 'connection1' + remoteVirtualNetworkId: '' + routingConfiguration: {} + } +] +param internetToFirewall = false +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateToFirewall = true +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 4: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module virtualHub 'br/public:avm/res/network/virtual-hub:' = { + name: 'virtualHubDeployment' + params: { + // Required parameters + addressPrefix: '10.1.0.0/16' + name: 'nvhwaf' + virtualWanId: '' + // Non-required parameters + hubRouteTables: [ + { + name: 'routeTable1' + } + ] + hubVirtualNetworkConnections: [ + { + name: 'connection1' + remoteVirtualNetworkId: '' + routingConfiguration: { + associatedRouteTable: { + id: '' + } + propagatedRouteTables: { + ids: [ + { + id: '' + } + ] + labels: [ + 'none' + ] + } + } + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "addressPrefix": { + "value": "10.1.0.0/16" + }, + "name": { + "value": "nvhwaf" + }, + "virtualWanId": { + "value": "" + }, + // Non-required parameters + "hubRouteTables": { + "value": [ + { + "name": "routeTable1" + } + ] + }, + "hubVirtualNetworkConnections": { + "value": [ + { + "name": "connection1", + "remoteVirtualNetworkId": "", + "routingConfiguration": { + "associatedRouteTable": { + "id": "" + }, + "propagatedRouteTables": { + "ids": [ + { + "id": "" + } + ], + "labels": [ + "none" + ] + } + } + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-hub:' + +// Required parameters +param addressPrefix = '10.1.0.0/16' +param name = 'nvhwaf' +param virtualWanId = '' +// Non-required parameters +param hubRouteTables = [ + { + name: 'routeTable1' + } +] +param hubVirtualNetworkConnections = [ + { + name: 'connection1' + remoteVirtualNetworkId: '' + routingConfiguration: { + associatedRouteTable: { + id: '' + } + propagatedRouteTables: { + ids: [ + { + id: '' + } + ] + labels: [ + 'none' + ] + } + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefix`](#parameter-addressprefix) | string | Address-prefix for this VirtualHub. | +| [`name`](#parameter-name) | string | The virtual hub name. | +| [`virtualWanId`](#parameter-virtualwanid) | string | Resource ID of the virtual WAN to link to. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowBranchToBranchTraffic`](#parameter-allowbranchtobranchtraffic) | bool | Flag to control transit for VirtualRouter hub. | +| [`azureFirewallResourceId`](#parameter-azurefirewallresourceid) | string | Resource ID of the Azure Firewall to link to. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`expressRouteGatewayId`](#parameter-expressroutegatewayid) | string | Resource ID of the Express Route Gateway to link to. | +| [`hubRouteTables`](#parameter-hubroutetables) | array | Route tables to create for the virtual hub. | +| [`hubRoutingPreference`](#parameter-hubroutingpreference) | string | The preferred routing preference for this virtual hub. | +| [`hubVirtualNetworkConnections`](#parameter-hubvirtualnetworkconnections) | array | Virtual network connections to create for the virtual hub. | +| [`internetToFirewall`](#parameter-internettofirewall) | bool | Configures Routing Intent to forward Internet traffic (0.0.0.0/0) to Azure Firewall. Default is true. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`p2SVpnGatewayId`](#parameter-p2svpngatewayid) | string | Resource ID of the Point-to-Site VPN Gateway to link to. | +| [`preferredRoutingGateway`](#parameter-preferredroutinggateway) | string | The preferred routing gateway types. | +| [`privateToFirewall`](#parameter-privatetofirewall) | bool | Configures Routing Intent to forward Private traffic (RFC 1918) to Azure Firewall. Default is true. | +| [`routeTableRoutes`](#parameter-routetableroutes) | array | VirtualHub route tables. | +| [`securityPartnerProviderId`](#parameter-securitypartnerproviderid) | string | ID of the Security Partner Provider to link to. | +| [`securityProviderName`](#parameter-securityprovidername) | string | The Security Provider name. | +| [`sku`](#parameter-sku) | string | The sku of this VirtualHub. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`virtualHubRouteTableV2s`](#parameter-virtualhubroutetablev2s) | array | List of all virtual hub route table v2s associated with this VirtualHub. | +| [`virtualRouterAsn`](#parameter-virtualrouterasn) | int | VirtualRouter ASN. | +| [`virtualRouterIps`](#parameter-virtualrouterips) | array | VirtualRouter IPs. | +| [`vpnGatewayId`](#parameter-vpngatewayid) | string | Resource ID of the VPN Gateway to link to. | + +### Parameter: `addressPrefix` + +Address-prefix for this VirtualHub. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The virtual hub name. + +- Required: Yes +- Type: string + +### Parameter: `virtualWanId` + +Resource ID of the virtual WAN to link to. + +- Required: Yes +- Type: string + +### Parameter: `allowBranchToBranchTraffic` + +Flag to control transit for VirtualRouter hub. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `azureFirewallResourceId` + +Resource ID of the Azure Firewall to link to. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `expressRouteGatewayId` + +Resource ID of the Express Route Gateway to link to. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `hubRouteTables` + +Route tables to create for the virtual hub. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `hubRoutingPreference` + +The preferred routing preference for this virtual hub. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'ASPath' + 'ExpressRoute' + 'VpnGateway' + ] + ``` + +### Parameter: `hubVirtualNetworkConnections` + +Virtual network connections to create for the virtual hub. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `internetToFirewall` + +Configures Routing Intent to forward Internet traffic (0.0.0.0/0) to Azure Firewall. Default is true. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `p2SVpnGatewayId` + +Resource ID of the Point-to-Site VPN Gateway to link to. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `preferredRoutingGateway` + +The preferred routing gateway types. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'ExpressRoute' + 'None' + 'VpnGateway' + ] + ``` + +### Parameter: `privateToFirewall` + +Configures Routing Intent to forward Private traffic (RFC 1918) to Azure Firewall. Default is true. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `routeTableRoutes` + +VirtualHub route tables. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `securityPartnerProviderId` + +ID of the Security Partner Provider to link to. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `securityProviderName` + +The Security Provider name. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `sku` + +The sku of this VirtualHub. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Standard' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `virtualHubRouteTableV2s` + +List of all virtual hub route table v2s associated with this VirtualHub. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `virtualRouterAsn` + +VirtualRouter ASN. + +- Required: No +- Type: int + +### Parameter: `virtualRouterIps` + +VirtualRouter IPs. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `vpnGatewayId` + +Resource ID of the VPN Gateway to link to. + +- Required: No +- Type: string +- Default: `''` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the virtual hub. | +| `resourceGroupName` | string | The resource group the virtual hub was deployed into. | +| `resourceId` | string | The resource ID of the virtual hub. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/virtual-hub/hub-route-table/README.md b/avm/1.1.0/res/network/virtual-hub/hub-route-table/README.md new file mode 100644 index 000000000..82ca9fee8 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/hub-route-table/README.md @@ -0,0 +1,74 @@ +# Virtual Hub Route Tables `[Microsoft.Network/virtualHubs/hubRouteTables]` + +This module deploys a Virtual Hub Route Table. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/virtualHubs/hubRouteTables` | [2022-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-11-01/virtualHubs/hubRouteTables) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The route table name. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`virtualHubName`](#parameter-virtualhubname) | string | The name of the parent virtual hub. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`labels`](#parameter-labels) | array | List of labels associated with this route table. | +| [`routes`](#parameter-routes) | array | List of all routes. | + +### Parameter: `name` + +The route table name. + +- Required: Yes +- Type: string + +### Parameter: `virtualHubName` + +The name of the parent virtual hub. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `labels` + +List of labels associated with this route table. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `routes` + +List of all routes. + +- Required: No +- Type: array +- Default: `[]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed virtual hub route table. | +| `resourceGroupName` | string | The resource group the virtual hub route table was deployed into. | +| `resourceId` | string | The resource ID of the deployed virtual hub route table. | diff --git a/avm/1.1.0/res/network/virtual-hub/hub-route-table/main.bicep b/avm/1.1.0/res/network/virtual-hub/hub-route-table/main.bicep new file mode 100644 index 000000000..8b93f1286 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/hub-route-table/main.bicep @@ -0,0 +1,36 @@ +metadata name = 'Virtual Hub Route Tables' +metadata description = 'This module deploys a Virtual Hub Route Table.' + +@description('Required. The route table name.') +param name string + +@description('Conditional. The name of the parent virtual hub. Required if the template is used in a standalone deployment.') +param virtualHubName string + +@description('Optional. List of labels associated with this route table.') +param labels array = [] + +@description('Optional. List of all routes.') +param routes array = [] + +resource virtualHub 'Microsoft.Network/virtualHubs@2022-11-01' existing = { + name: virtualHubName +} + +resource hubRouteTable 'Microsoft.Network/virtualHubs/hubRouteTables@2022-11-01' = { + name: name + parent: virtualHub + properties: { + labels: !empty(labels) ? labels : null + routes: !empty(routes) ? routes : null + } +} + +@description('The name of the deployed virtual hub route table.') +output name string = hubRouteTable.name + +@description('The resource ID of the deployed virtual hub route table.') +output resourceId string = hubRouteTable.id + +@description('The resource group the virtual hub route table was deployed into.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/network/virtual-hub/hub-route-table/main.json b/avm/1.1.0/res/network/virtual-hub/hub-route-table/main.json new file mode 100644 index 000000000..e42db3f2d --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/hub-route-table/main.json @@ -0,0 +1,75 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9133722157433973850" + }, + "name": "Virtual Hub Route Tables", + "description": "This module deploys a Virtual Hub Route Table." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The route table name." + } + }, + "virtualHubName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual hub. Required if the template is used in a standalone deployment." + } + }, + "labels": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of labels associated with this route table." + } + }, + "routes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of all routes." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualHubs/hubRouteTables", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualHubName'), parameters('name'))]", + "properties": { + "labels": "[if(not(empty(parameters('labels'))), parameters('labels'), null())]", + "routes": "[if(not(empty(parameters('routes'))), parameters('routes'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual hub route table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual hub route table." + }, + "value": "[resourceId('Microsoft.Network/virtualHubs/hubRouteTables', parameters('virtualHubName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual hub route table was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-hub/hub-routing-intent/README.md b/avm/1.1.0/res/network/virtual-hub/hub-routing-intent/README.md new file mode 100644 index 000000000..08eda721b --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/hub-routing-intent/README.md @@ -0,0 +1,73 @@ +# Virtual Hub Routing Intent `[Microsoft.Network/virtualHubs]` + +This module configures Routing Intent for a Virtual Hub; this module requires an existing Virtual Hub, as well the firewall Resource ID. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Notes](#Notes) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/virtualHubs/routingIntent` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/virtualHubs/routingIntent) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`azureFirewallResourceId`](#parameter-azurefirewallresourceid) | string | Hub firewall Resource ID. | +| [`internetToFirewall`](#parameter-internettofirewall) | bool | Configures Routing Intent to Forward Internet traffic to the firewall (0.0.0.0/0). | +| [`privateToFirewall`](#parameter-privatetofirewall) | bool | Configures Routing Intent to forward Private traffic to the firewall (RFC1918). | +| [`virtualHubName`](#parameter-virtualhubname) | string | Name of the Virtual Hub. | + +### Parameter: `azureFirewallResourceId` + +Hub firewall Resource ID. + +- Required: Yes +- Type: string + +### Parameter: `internetToFirewall` + +Configures Routing Intent to Forward Internet traffic to the firewall (0.0.0.0/0). + +- Required: Yes +- Type: bool + +### Parameter: `privateToFirewall` + +Configures Routing Intent to forward Private traffic to the firewall (RFC1918). + +- Required: Yes +- Type: bool + +### Parameter: `virtualHubName` + +Name of the Virtual Hub. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the Routing Intent configuration. | +| `resourceGroupName` | string | The resource group the Routing Intent configuration was deployed into. | +| `resourceId` | string | The resource ID of the Routing Intent configuration. | + +## Notes + +The use of Routing Intent in a Virtual Hub requires the hub be made 'secure' by associating a firewall (to serve as the next-hop for the routing policy). + +The 'azureFirewall' parameter in Microsoft.Network/virtualHubs is *read-only*; in order to properly deploy a Virtual Hub using Routing Intent, the hub's Resource ID must first be passed to the firewall in order for it to be properly associated. In order for this resource to work properly, the resources need to be created in the following order: + +- **Virtual Hub**: Suggest minimal hub configuration; name/location/addressPrefix/virtualWan.id +- **Firewall**: Including Virtual Hub Resource ID in the firewall configuration +- **Virtual Hub**: Including all remaining parameters + Routing Intent diff --git a/avm/1.1.0/res/network/virtual-hub/hub-routing-intent/main.bicep b/avm/1.1.0/res/network/virtual-hub/hub-routing-intent/main.bicep new file mode 100644 index 000000000..96077424d --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/hub-routing-intent/main.bicep @@ -0,0 +1,72 @@ +metadata name = 'Virtual Hub Routing Intent' +metadata description = 'This module configures Routing Intent for a Virtual Hub; this module requires an existing Virtual Hub, as well the firewall Resource ID.' + +@description('Required. Hub firewall Resource ID.') +param azureFirewallResourceId string + +@description('Required. Name of the Virtual Hub.') +param virtualHubName string + +@description('Required. Configures Routing Intent to forward Private traffic to the firewall (RFC1918).') +param privateToFirewall bool + +@description('Required. Configures Routing Intent to Forward Internet traffic to the firewall (0.0.0.0/0).') +param internetToFirewall bool + +resource virtualHub 'Microsoft.Network/virtualHubs@2022-11-01' existing = { + name: virtualHubName +} + +resource routingIntent 'Microsoft.Network/virtualHubs/routingIntent@2023-11-01' = { + name: 'defaultRouteTable' + parent: virtualHub + properties: { + routingPolicies: (internetToFirewall == true && privateToFirewall == true) + ? [ + { + name: '_policy_PublicTraffic' + destinations: [ + 'Internet' + ] + nextHop: azureFirewallResourceId + } + { + name: '_policy_PrivateTraffic' + destinations: [ + 'PrivateTraffic' + ] + nextHop: azureFirewallResourceId + } + ] + : (internetToFirewall == true && privateToFirewall == false) + ? [ + { + name: '_policy_PublicTraffic' + destinations: [ + 'Internet' + ] + nextHop: azureFirewallResourceId + } + ] + : (internetToFirewall == false && privateToFirewall == true) + ? [ + { + name: '_policy_PrivateTraffic' + destinations: [ + 'PrivateTraffic' + ] + nextHop: azureFirewallResourceId + } + ] + : null + } +} + +@description('The name of the Routing Intent configuration.') +output name string = routingIntent.name + +@description('The resource ID of the Routing Intent configuration.') +output resourceId string = routingIntent.id + +@description('The resource group the Routing Intent configuration was deployed into.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/network/virtual-hub/hub-routing-intent/main.json b/avm/1.1.0/res/network/virtual-hub/hub-routing-intent/main.json new file mode 100644 index 000000000..f3b6d09df --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/hub-routing-intent/main.json @@ -0,0 +1,72 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15649735189663073116" + }, + "name": "Virtual Hub Routing Intent", + "description": "This module configures Routing Intent for a Virtual Hub; this module requires an existing Virtual Hub, as well the firewall Resource ID." + }, + "parameters": { + "azureFirewallResourceId": { + "type": "string", + "metadata": { + "description": "Required. Hub firewall Resource ID." + } + }, + "virtualHubName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Virtual Hub." + } + }, + "privateToFirewall": { + "type": "bool", + "metadata": { + "description": "Required. Configures Routing Intent to forward Private traffic to the firewall (RFC1918)." + } + }, + "internetToFirewall": { + "type": "bool", + "metadata": { + "description": "Required. Configures Routing Intent to Forward Internet traffic to the firewall (0.0.0.0/0)." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualHubs/routingIntent", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('virtualHubName'), 'defaultRouteTable')]", + "properties": { + "routingPolicies": "[if(and(equals(parameters('internetToFirewall'), true()), equals(parameters('privateToFirewall'), true())), createArray(createObject('name', '_policy_PublicTraffic', 'destinations', createArray('Internet'), 'nextHop', parameters('azureFirewallResourceId')), createObject('name', '_policy_PrivateTraffic', 'destinations', createArray('PrivateTraffic'), 'nextHop', parameters('azureFirewallResourceId'))), if(and(equals(parameters('internetToFirewall'), true()), equals(parameters('privateToFirewall'), false())), createArray(createObject('name', '_policy_PublicTraffic', 'destinations', createArray('Internet'), 'nextHop', parameters('azureFirewallResourceId'))), if(and(equals(parameters('internetToFirewall'), false()), equals(parameters('privateToFirewall'), true())), createArray(createObject('name', '_policy_PrivateTraffic', 'destinations', createArray('PrivateTraffic'), 'nextHop', parameters('azureFirewallResourceId'))), null())))]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Routing Intent configuration." + }, + "value": "defaultRouteTable" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Routing Intent configuration." + }, + "value": "[resourceId('Microsoft.Network/virtualHubs/routingIntent', parameters('virtualHubName'), 'defaultRouteTable')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Routing Intent configuration was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-hub/hub-virtual-network-connection/README.md b/avm/1.1.0/res/network/virtual-hub/hub-virtual-network-connection/README.md new file mode 100644 index 000000000..e5a1aca8d --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/hub-virtual-network-connection/README.md @@ -0,0 +1,82 @@ +# Virtual Hub Virtual Network Connections `[Microsoft.Network/virtualHubs/hubVirtualNetworkConnections]` + +This module deploys a Virtual Hub Virtual Network Connection. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/virtualHubs/hubVirtualNetworkConnections` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-01-01/virtualHubs/hubVirtualNetworkConnections) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The connection name. | +| [`remoteVirtualNetworkId`](#parameter-remotevirtualnetworkid) | string | Resource ID of the virtual network to link to. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`virtualHubName`](#parameter-virtualhubname) | string | The name of the parent virtual hub. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableInternetSecurity`](#parameter-enableinternetsecurity) | bool | Enable internet security. | +| [`routingConfiguration`](#parameter-routingconfiguration) | object | Routing Configuration indicating the associated and propagated route tables for this connection. | + +### Parameter: `name` + +The connection name. + +- Required: Yes +- Type: string + +### Parameter: `remoteVirtualNetworkId` + +Resource ID of the virtual network to link to. + +- Required: Yes +- Type: string + +### Parameter: `virtualHubName` + +The name of the parent virtual hub. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `enableInternetSecurity` + +Enable internet security. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `routingConfiguration` + +Routing Configuration indicating the associated and propagated route tables for this connection. + +- Required: No +- Type: object +- Default: `{}` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the virtual hub connection. | +| `resourceGroupName` | string | The resource group the virtual hub connection was deployed into. | +| `resourceId` | string | The resource ID of the virtual hub connection. | diff --git a/avm/1.1.0/res/network/virtual-hub/hub-virtual-network-connection/main.bicep b/avm/1.1.0/res/network/virtual-hub/hub-virtual-network-connection/main.bicep new file mode 100644 index 000000000..347ddea13 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/hub-virtual-network-connection/main.bicep @@ -0,0 +1,42 @@ +metadata name = 'Virtual Hub Virtual Network Connections' +metadata description = 'This module deploys a Virtual Hub Virtual Network Connection.' + +@description('Required. The connection name.') +param name string + +@description('Conditional. The name of the parent virtual hub. Required if the template is used in a standalone deployment.') +param virtualHubName string + +@description('Optional. Enable internet security.') +param enableInternetSecurity bool = true + +@description('Required. Resource ID of the virtual network to link to.') +param remoteVirtualNetworkId string + +@description('Optional. Routing Configuration indicating the associated and propagated route tables for this connection.') +param routingConfiguration object = {} + +resource virtualHub 'Microsoft.Network/virtualHubs@2024-01-01' existing = { + name: virtualHubName +} + +resource hubVirtualNetworkConnection 'Microsoft.Network/virtualHubs/hubVirtualNetworkConnections@2024-01-01' = { + name: name + parent: virtualHub + properties: { + enableInternetSecurity: enableInternetSecurity + remoteVirtualNetwork: { + id: remoteVirtualNetworkId + } + routingConfiguration: !empty(routingConfiguration) ? routingConfiguration : null + } +} + +@description('The resource group the virtual hub connection was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the virtual hub connection.') +output resourceId string = hubVirtualNetworkConnection.id + +@description('The name of the virtual hub connection.') +output name string = hubVirtualNetworkConnection.name diff --git a/avm/1.1.0/res/network/virtual-hub/hub-virtual-network-connection/main.json b/avm/1.1.0/res/network/virtual-hub/hub-virtual-network-connection/main.json new file mode 100644 index 000000000..e58e0c121 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/hub-virtual-network-connection/main.json @@ -0,0 +1,84 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "13762641450479393784" + }, + "name": "Virtual Hub Virtual Network Connections", + "description": "This module deploys a Virtual Hub Virtual Network Connection." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The connection name." + } + }, + "virtualHubName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual hub. Required if the template is used in a standalone deployment." + } + }, + "enableInternetSecurity": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable internet security." + } + }, + "remoteVirtualNetworkId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the virtual network to link to." + } + }, + "routingConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Routing Configuration indicating the associated and propagated route tables for this connection." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualHubs/hubVirtualNetworkConnections", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('virtualHubName'), parameters('name'))]", + "properties": { + "enableInternetSecurity": "[parameters('enableInternetSecurity')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkId')]" + }, + "routingConfiguration": "[if(not(empty(parameters('routingConfiguration'))), parameters('routingConfiguration'), null())]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual hub connection was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual hub connection." + }, + "value": "[resourceId('Microsoft.Network/virtualHubs/hubVirtualNetworkConnections', parameters('virtualHubName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual hub connection." + }, + "value": "[parameters('name')]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-hub/main.bicep b/avm/1.1.0/res/network/virtual-hub/main.bicep new file mode 100644 index 000000000..1b5fe1457 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/main.bicep @@ -0,0 +1,243 @@ +metadata name = 'Virtual Hubs' +metadata description = '''This module deploys a Virtual Hub. +If you are planning to deploy a Secure Virtual Hub (with an Azure Firewall integrated), please refer to the Azure Firewall module.''' + +@description('Required. The virtual hub name.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Required. Address-prefix for this VirtualHub.') +param addressPrefix string + +@description('Optional. Flag to control transit for VirtualRouter hub.') +param allowBranchToBranchTraffic bool = true + +@description('Optional. Resource ID of the Azure Firewall to link to.') +param azureFirewallResourceId string = '' + +@description('Optional. Resource ID of the Express Route Gateway to link to.') +param expressRouteGatewayId string = '' + +@description('Optional. Resource ID of the Point-to-Site VPN Gateway to link to.') +param p2SVpnGatewayId string = '' + +@description('Optional. The preferred routing preference for this virtual hub.') +@allowed([ + 'ASPath' + 'ExpressRoute' + 'VpnGateway' + '' +]) +param hubRoutingPreference string = '' + +@description('Optional. The preferred routing gateway types.') +@allowed([ + 'ExpressRoute' + 'None' + 'VpnGateway' + '' +]) +param preferredRoutingGateway string = '' + +@description('Optional. VirtualHub route tables.') +param routeTableRoutes array = [] + +@description('Optional. ID of the Security Partner Provider to link to.') +param securityPartnerProviderId string = '' + +@description('Optional. The Security Provider name.') +param securityProviderName string = '' + +@allowed([ + 'Basic' + 'Standard' +]) +@description('Optional. The sku of this VirtualHub.') +param sku string = 'Standard' + +@description('Optional. List of all virtual hub route table v2s associated with this VirtualHub.') +param virtualHubRouteTableV2s array = [] + +@description('Optional. VirtualRouter ASN.') +param virtualRouterAsn int? + +@description('Optional. VirtualRouter IPs.') +param virtualRouterIps array = [] + +@description('Required. Resource ID of the virtual WAN to link to.') +param virtualWanId string + +@description('Optional. Resource ID of the VPN Gateway to link to.') +param vpnGatewayId string = '' + +@description('Optional. Configures Routing Intent to forward Internet traffic (0.0.0.0/0) to Azure Firewall. Default is true.') +param internetToFirewall bool = true + +@description('Optional. Configures Routing Intent to forward Private traffic (RFC 1918) to Azure Firewall. Default is true.') +param privateToFirewall bool = true + +@description('Optional. Route tables to create for the virtual hub.') +param hubRouteTables array = [] + +@description('Optional. Virtual network connections to create for the virtual hub.') +param hubVirtualNetworkConnections array = [] + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.res.network-virtualhub.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource virtualHub 'Microsoft.Network/virtualHubs@2023-11-01' = { + name: name + location: location + tags: tags + properties: { + addressPrefix: addressPrefix + allowBranchToBranchTraffic: allowBranchToBranchTraffic + azureFirewall: !empty(azureFirewallResourceId) + ? { + id: azureFirewallResourceId + } + : null + expressRouteGateway: !empty(expressRouteGatewayId) + ? { + id: expressRouteGatewayId + } + : null + p2SVpnGateway: !empty(p2SVpnGatewayId) + ? { + id: p2SVpnGatewayId + } + : null + hubRoutingPreference: !empty(hubRoutingPreference) ? any(hubRoutingPreference) : null + preferredRoutingGateway: !empty(preferredRoutingGateway) ? any(preferredRoutingGateway) : null + routeTable: !empty(routeTableRoutes) + ? { + routes: routeTableRoutes + } + : null + securityPartnerProvider: !empty(securityPartnerProviderId) + ? { + id: securityPartnerProviderId + } + : null + securityProviderName: securityProviderName + sku: sku + virtualHubRouteTableV2s: virtualHubRouteTableV2s + virtualRouterAsn: virtualRouterAsn + virtualRouterIps: !empty(virtualRouterIps) ? virtualRouterIps : null + virtualWan: { + id: virtualWanId + } + vpnGateway: !empty(vpnGatewayId) + ? { + id: vpnGatewayId + } + : null + } +} + +resource virtualHub_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: virtualHub +} + +module virtualHub_routingIntent 'hub-routing-intent/main.bicep' = if (!empty(azureFirewallResourceId) && (internetToFirewall || privateToFirewall)) { + name: '${uniqueString(deployment().name, location)}-routingIntent' + params: { + virtualHubName: virtualHub.name + azureFirewallResourceId: azureFirewallResourceId + internetToFirewall: internetToFirewall + privateToFirewall: privateToFirewall + } +} + +module virtualHub_routeTables 'hub-route-table/main.bicep' = [ + for (routeTable, index) in (hubRouteTables ?? []): { + name: '${uniqueString(deployment().name, location)}-routeTable-${index}' + params: { + virtualHubName: virtualHub.name + name: routeTable.name + labels: contains(routeTable, 'labels') ? routeTable.labels : [] + routes: contains(routeTable, 'routes') ? routeTable.routes : [] + } + } +] + +module virtualHub_hubVirtualNetworkConnections 'hub-virtual-network-connection/main.bicep' = [ + for (virtualNetworkConnection, index) in hubVirtualNetworkConnections: { + name: '${uniqueString(deployment().name, location)}-connection-${index}' + params: { + virtualHubName: virtualHub.name + name: virtualNetworkConnection.name + enableInternetSecurity: contains(virtualNetworkConnection, 'enableInternetSecurity') + ? virtualNetworkConnection.enableInternetSecurity + : true + remoteVirtualNetworkId: virtualNetworkConnection.remoteVirtualNetworkId + routingConfiguration: contains(virtualNetworkConnection, 'routingConfiguration') + ? virtualNetworkConnection.routingConfiguration + : {} + } + dependsOn: [ + virtualHub_routeTables + ] + } +] + +@description('The resource group the virtual hub was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the virtual hub.') +output resourceId string = virtualHub.id + +@description('The name of the virtual hub.') +output name string = virtualHub.name + +@description('The location the resource was deployed into.') +output location string = virtualHub.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? diff --git a/avm/1.1.0/res/network/virtual-hub/main.json b/avm/1.1.0/res/network/virtual-hub/main.json new file mode 100644 index 000000000..f5419b478 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/main.json @@ -0,0 +1,643 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "14261669365957624019" + }, + "name": "Virtual Hubs", + "description": "This module deploys a Virtual Hub.\nIf you are planning to deploy a Secure Virtual Hub (with an Azure Firewall integrated), please refer to the Azure Firewall module." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The virtual hub name." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. Address-prefix for this VirtualHub." + } + }, + "allowBranchToBranchTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Flag to control transit for VirtualRouter hub." + } + }, + "azureFirewallResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the Azure Firewall to link to." + } + }, + "expressRouteGatewayId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the Express Route Gateway to link to." + } + }, + "p2SVpnGatewayId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the Point-to-Site VPN Gateway to link to." + } + }, + "hubRoutingPreference": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ASPath", + "ExpressRoute", + "VpnGateway", + "" + ], + "metadata": { + "description": "Optional. The preferred routing preference for this virtual hub." + } + }, + "preferredRoutingGateway": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ExpressRoute", + "None", + "VpnGateway", + "" + ], + "metadata": { + "description": "Optional. The preferred routing gateway types." + } + }, + "routeTableRoutes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. VirtualHub route tables." + } + }, + "securityPartnerProviderId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the Security Partner Provider to link to." + } + }, + "securityProviderName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Security Provider name." + } + }, + "sku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. The sku of this VirtualHub." + } + }, + "virtualHubRouteTableV2s": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of all virtual hub route table v2s associated with this VirtualHub." + } + }, + "virtualRouterAsn": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. VirtualRouter ASN." + } + }, + "virtualRouterIps": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. VirtualRouter IPs." + } + }, + "virtualWanId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the virtual WAN to link to." + } + }, + "vpnGatewayId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the VPN Gateway to link to." + } + }, + "internetToFirewall": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Configures Routing Intent to forward Internet traffic (0.0.0.0/0) to Azure Firewall. Default is true." + } + }, + "privateToFirewall": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Configures Routing Intent to forward Private traffic (RFC 1918) to Azure Firewall. Default is true." + } + }, + "hubRouteTables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Route tables to create for the virtual hub." + } + }, + "hubVirtualNetworkConnections": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Virtual network connections to create for the virtual hub." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.res.network-virtualhub.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "virtualHub": { + "type": "Microsoft.Network/virtualHubs", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressPrefix": "[parameters('addressPrefix')]", + "allowBranchToBranchTraffic": "[parameters('allowBranchToBranchTraffic')]", + "azureFirewall": "[if(not(empty(parameters('azureFirewallResourceId'))), createObject('id', parameters('azureFirewallResourceId')), null())]", + "expressRouteGateway": "[if(not(empty(parameters('expressRouteGatewayId'))), createObject('id', parameters('expressRouteGatewayId')), null())]", + "p2SVpnGateway": "[if(not(empty(parameters('p2SVpnGatewayId'))), createObject('id', parameters('p2SVpnGatewayId')), null())]", + "hubRoutingPreference": "[if(not(empty(parameters('hubRoutingPreference'))), parameters('hubRoutingPreference'), null())]", + "preferredRoutingGateway": "[if(not(empty(parameters('preferredRoutingGateway'))), parameters('preferredRoutingGateway'), null())]", + "routeTable": "[if(not(empty(parameters('routeTableRoutes'))), createObject('routes', parameters('routeTableRoutes')), null())]", + "securityPartnerProvider": "[if(not(empty(parameters('securityPartnerProviderId'))), createObject('id', parameters('securityPartnerProviderId')), null())]", + "securityProviderName": "[parameters('securityProviderName')]", + "sku": "[parameters('sku')]", + "virtualHubRouteTableV2s": "[parameters('virtualHubRouteTableV2s')]", + "virtualRouterAsn": "[parameters('virtualRouterAsn')]", + "virtualRouterIps": "[if(not(empty(parameters('virtualRouterIps'))), parameters('virtualRouterIps'), null())]", + "virtualWan": { + "id": "[parameters('virtualWanId')]" + }, + "vpnGateway": "[if(not(empty(parameters('vpnGatewayId'))), createObject('id', parameters('vpnGatewayId')), null())]" + } + }, + "virtualHub_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/virtualHubs/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "virtualHub" + ] + }, + "virtualHub_routingIntent": { + "condition": "[and(not(empty(parameters('azureFirewallResourceId'))), or(parameters('internetToFirewall'), parameters('privateToFirewall')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-routingIntent', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualHubName": { + "value": "[parameters('name')]" + }, + "azureFirewallResourceId": { + "value": "[parameters('azureFirewallResourceId')]" + }, + "internetToFirewall": { + "value": "[parameters('internetToFirewall')]" + }, + "privateToFirewall": { + "value": "[parameters('privateToFirewall')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "15649735189663073116" + }, + "name": "Virtual Hub Routing Intent", + "description": "This module configures Routing Intent for a Virtual Hub; this module requires an existing Virtual Hub, as well the firewall Resource ID." + }, + "parameters": { + "azureFirewallResourceId": { + "type": "string", + "metadata": { + "description": "Required. Hub firewall Resource ID." + } + }, + "virtualHubName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Virtual Hub." + } + }, + "privateToFirewall": { + "type": "bool", + "metadata": { + "description": "Required. Configures Routing Intent to forward Private traffic to the firewall (RFC1918)." + } + }, + "internetToFirewall": { + "type": "bool", + "metadata": { + "description": "Required. Configures Routing Intent to Forward Internet traffic to the firewall (0.0.0.0/0)." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualHubs/routingIntent", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('virtualHubName'), 'defaultRouteTable')]", + "properties": { + "routingPolicies": "[if(and(equals(parameters('internetToFirewall'), true()), equals(parameters('privateToFirewall'), true())), createArray(createObject('name', '_policy_PublicTraffic', 'destinations', createArray('Internet'), 'nextHop', parameters('azureFirewallResourceId')), createObject('name', '_policy_PrivateTraffic', 'destinations', createArray('PrivateTraffic'), 'nextHop', parameters('azureFirewallResourceId'))), if(and(equals(parameters('internetToFirewall'), true()), equals(parameters('privateToFirewall'), false())), createArray(createObject('name', '_policy_PublicTraffic', 'destinations', createArray('Internet'), 'nextHop', parameters('azureFirewallResourceId'))), if(and(equals(parameters('internetToFirewall'), false()), equals(parameters('privateToFirewall'), true())), createArray(createObject('name', '_policy_PrivateTraffic', 'destinations', createArray('PrivateTraffic'), 'nextHop', parameters('azureFirewallResourceId'))), null())))]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Routing Intent configuration." + }, + "value": "defaultRouteTable" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Routing Intent configuration." + }, + "value": "[resourceId('Microsoft.Network/virtualHubs/routingIntent', parameters('virtualHubName'), 'defaultRouteTable')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Routing Intent configuration was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "virtualHub" + ] + }, + "virtualHub_routeTables": { + "copy": { + "name": "virtualHub_routeTables", + "count": "[length(coalesce(parameters('hubRouteTables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-routeTable-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualHubName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('hubRouteTables'), createArray())[copyIndex()].name]" + }, + "labels": "[if(contains(coalesce(parameters('hubRouteTables'), createArray())[copyIndex()], 'labels'), createObject('value', coalesce(parameters('hubRouteTables'), createArray())[copyIndex()].labels), createObject('value', createArray()))]", + "routes": "[if(contains(coalesce(parameters('hubRouteTables'), createArray())[copyIndex()], 'routes'), createObject('value', coalesce(parameters('hubRouteTables'), createArray())[copyIndex()].routes), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9133722157433973850" + }, + "name": "Virtual Hub Route Tables", + "description": "This module deploys a Virtual Hub Route Table." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The route table name." + } + }, + "virtualHubName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual hub. Required if the template is used in a standalone deployment." + } + }, + "labels": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of labels associated with this route table." + } + }, + "routes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of all routes." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualHubs/hubRouteTables", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualHubName'), parameters('name'))]", + "properties": { + "labels": "[if(not(empty(parameters('labels'))), parameters('labels'), null())]", + "routes": "[if(not(empty(parameters('routes'))), parameters('routes'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual hub route table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual hub route table." + }, + "value": "[resourceId('Microsoft.Network/virtualHubs/hubRouteTables', parameters('virtualHubName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual hub route table was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "virtualHub" + ] + }, + "virtualHub_hubVirtualNetworkConnections": { + "copy": { + "name": "virtualHub_hubVirtualNetworkConnections", + "count": "[length(parameters('hubVirtualNetworkConnections'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-connection-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualHubName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('hubVirtualNetworkConnections')[copyIndex()].name]" + }, + "enableInternetSecurity": "[if(contains(parameters('hubVirtualNetworkConnections')[copyIndex()], 'enableInternetSecurity'), createObject('value', parameters('hubVirtualNetworkConnections')[copyIndex()].enableInternetSecurity), createObject('value', true()))]", + "remoteVirtualNetworkId": { + "value": "[parameters('hubVirtualNetworkConnections')[copyIndex()].remoteVirtualNetworkId]" + }, + "routingConfiguration": "[if(contains(parameters('hubVirtualNetworkConnections')[copyIndex()], 'routingConfiguration'), createObject('value', parameters('hubVirtualNetworkConnections')[copyIndex()].routingConfiguration), createObject('value', createObject()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "13762641450479393784" + }, + "name": "Virtual Hub Virtual Network Connections", + "description": "This module deploys a Virtual Hub Virtual Network Connection." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The connection name." + } + }, + "virtualHubName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual hub. Required if the template is used in a standalone deployment." + } + }, + "enableInternetSecurity": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable internet security." + } + }, + "remoteVirtualNetworkId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the virtual network to link to." + } + }, + "routingConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Routing Configuration indicating the associated and propagated route tables for this connection." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualHubs/hubVirtualNetworkConnections", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('virtualHubName'), parameters('name'))]", + "properties": { + "enableInternetSecurity": "[parameters('enableInternetSecurity')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkId')]" + }, + "routingConfiguration": "[if(not(empty(parameters('routingConfiguration'))), parameters('routingConfiguration'), null())]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual hub connection was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual hub connection." + }, + "value": "[resourceId('Microsoft.Network/virtualHubs/hubVirtualNetworkConnections', parameters('virtualHubName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual hub connection." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "virtualHub", + "virtualHub_routeTables" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual hub was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual hub." + }, + "value": "[resourceId('Microsoft.Network/virtualHubs', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual hub." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualHub', '2023-11-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-hub/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/virtual-hub/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..bb151ad9d --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +@description('The resource ID of the created Virtual WAN.') +output virtualWWANResourceId string = virtualWan.id diff --git a/avm/1.1.0/res/network/virtual-hub/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/virtual-hub/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..688058b27 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,59 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualHub-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvhmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}-${serviceShort}' + addressPrefix: '10.0.0.0/16' + virtualWanId: nestedDependencies.outputs.virtualWWANResourceId + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/network/virtual-hub/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/virtual-hub/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..12d02b46c --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/tests/e2e/max/dependencies.bicep @@ -0,0 +1,41 @@ +@description('Required. The name of the Virtual WAN to create.') +param virtualWANName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +@description('The resource ID of the created Virtual WAN.') +output virtualWWANResourceId string = virtualWan.id + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id diff --git a/avm/1.1.0/res/network/virtual-hub/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/virtual-hub/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..5b1d77520 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/tests/e2e/max/main.test.bicep @@ -0,0 +1,95 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualHub-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvhmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}-${serviceShort}' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + addressPrefix: '10.1.0.0/16' + virtualWanId: nestedDependencies.outputs.virtualWWANResourceId + hubRouteTables: [ + { + name: 'routeTable1' + } + ] + hubVirtualNetworkConnections: [ + { + name: 'connection1' + remoteVirtualNetworkId: nestedDependencies.outputs.virtualNetworkResourceId + routingConfiguration: { + associatedRouteTable: { + id: '${resourceGroup.id}/providers/Microsoft.Network/virtualHubs/${namePrefix}-${serviceShort}/hubRouteTables/routeTable1' + } + propagatedRouteTables: { + ids: [ + { + id: '${resourceGroup.id}/providers/Microsoft.Network/virtualHubs/${namePrefix}-${serviceShort}/hubRouteTables/routeTable1' + } + ] + labels: [ + 'none' + ] + } + } + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/virtual-hub/tests/e2e/routing-intent/dependencies.bicep b/avm/1.1.0/res/network/virtual-hub/tests/e2e/routing-intent/dependencies.bicep new file mode 100644 index 000000000..39fc4c035 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/tests/e2e/routing-intent/dependencies.bicep @@ -0,0 +1,81 @@ +@description('Required. The name of the Virtual WAN to create.') +param virtualWANName string + +@description('Required. The name of the Virtual Hub to create.') +param virtualHubName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Azure Firewall to create.') +param azureFirewallName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +resource virtualHub 'Microsoft.Network/virtualHubs@2023-11-01' = { + name: virtualHubName + location: location + properties: { + addressPrefix: '10.10.0.0/23' + virtualWan: { + id: virtualWan.id + } + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource azureFirewall 'Microsoft.Network/azureFirewalls@2023-04-01' = { + name: azureFirewallName + location: location + properties: { + sku: { + name: 'AZFW_Hub' + tier: 'Premium' + } + hubIPAddresses: { + publicIPs: { + count: 1 + } + } + virtualHub: { + id: virtualHub.id + } + } +} + + +@description('The resource ID of the created Virtual WAN.') +output virtualWANResourceId string = virtualWan.id + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Azure Firewall') +output azureFirewallResourceId string = azureFirewall.id diff --git a/avm/1.1.0/res/network/virtual-hub/tests/e2e/routing-intent/main.test.bicep b/avm/1.1.0/res/network/virtual-hub/tests/e2e/routing-intent/main.test.bicep new file mode 100644 index 000000000..737caa3be --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/tests/e2e/routing-intent/main.test.bicep @@ -0,0 +1,84 @@ +targetScope = 'subscription' + +metadata name = 'Using Routing Intent' +metadata description = 'This instance deploys the module the Virtual WAN hub with Routing Intent enabled; requires an existing Virtual Hub, as well the firewall Resource ID.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualHub-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvhrtint' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + virtualHubName: '${namePrefix}-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + azureFirewallName: 'dep-${namePrefix}-azfw-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + dependsOn: [nestedDependencies] + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}-${serviceShort}' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + addressPrefix: '10.10.0.0/23' + virtualWanId: nestedDependencies.outputs.virtualWANResourceId + hubRouteTables: [] + hubVirtualNetworkConnections: [ + { + name: 'connection1' + remoteVirtualNetworkId: nestedDependencies.outputs.virtualNetworkResourceId + routingConfiguration: {} + } + ] + hubRoutingPreference: 'ASPath' + azureFirewallResourceId: nestedDependencies.outputs.azureFirewallResourceId + internetToFirewall: false + privateToFirewall: true + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/virtual-hub/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/virtual-hub/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..12d02b46c --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,41 @@ +@description('Required. The name of the Virtual WAN to create.') +param virtualWANName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +var addressPrefix = '10.0.0.0/16' + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +@description('The resource ID of the created Virtual WAN.') +output virtualWWANResourceId string = virtualWan.id + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id diff --git a/avm/1.1.0/res/network/virtual-hub/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/virtual-hub/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..3d3015b25 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,95 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualHub-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvhwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}-${serviceShort}' + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + addressPrefix: '10.1.0.0/16' + virtualWanId: nestedDependencies.outputs.virtualWWANResourceId + hubRouteTables: [ + { + name: 'routeTable1' + } + ] + hubVirtualNetworkConnections: [ + { + name: 'connection1' + remoteVirtualNetworkId: nestedDependencies.outputs.virtualNetworkResourceId + routingConfiguration: { + associatedRouteTable: { + id: '${resourceGroup.id}/providers/Microsoft.Network/virtualHubs/${namePrefix}-${serviceShort}/hubRouteTables/routeTable1' + } + propagatedRouteTables: { + ids: [ + { + id: '${resourceGroup.id}/providers/Microsoft.Network/virtualHubs/${namePrefix}-${serviceShort}/hubRouteTables/routeTable1' + } + ] + labels: [ + 'none' + ] + } + } + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/virtual-hub/version.json b/avm/1.1.0/res/network/virtual-hub/version.json new file mode 100644 index 000000000..1c035df49 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-hub/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.2", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-network-gateway/README.md b/avm/1.1.0/res/network/virtual-network-gateway/README.md new file mode 100644 index 000000000..4d876db39 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/README.md @@ -0,0 +1,3197 @@ +# Virtual Network Gateways `[Microsoft.Network/virtualNetworkGateways]` + +This module deploys a Virtual Network Gateway. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | +| `Microsoft.Network/virtualNetworkGateways` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/virtualNetworkGateways) | +| `Microsoft.Network/virtualNetworkGateways/natRules` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/virtualNetworkGateways/natRules) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/virtual-network-gateway:`. + +- [VPN Active Active with BGP settings](#example-1-vpn-active-active-with-bgp-settings) +- [VPN Active Active with BGP settings](#example-2-vpn-active-active-with-bgp-settings) +- [VPN Active Active without BGP settings using two existent Public IPs](#example-3-vpn-active-active-without-bgp-settings-using-two-existent-public-ips) +- [VPN Active Active without BGP settings](#example-4-vpn-active-active-without-bgp-settings) +- [VPN Active Passive with BGP settings](#example-5-vpn-active-passive-with-bgp-settings) +- [VPN Active Passive with BGP settings using existing Public IP](#example-6-vpn-active-passive-with-bgp-settings-using-existing-public-ip) +- [VPN Active Passive without BGP settings](#example-7-vpn-active-passive-without-bgp-settings) +- [Using only defaults](#example-8-using-only-defaults) +- [ExpressRoute](#example-9-expressroute) +- [Using large parameter set](#example-10-using-large-parameter-set) +- [Using SKU without Availability Zones](#example-11-using-sku-without-availability-zones) +- [VPN](#example-12-vpn) +- [WAF-aligned](#example-13-waf-aligned) + +### Example 1: _VPN Active Active with BGP settings_ + +This instance deploys the module with the VPN Active Active with BGP settings. + + +

+ +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activeActiveBgp' + } + gatewayType: 'Vpn' + name: 'nvgaab001' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgaab' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveBgp" + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgaab001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgaab" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activeActiveBgp' +} +param gatewayType = 'Vpn' +param name = 'nvgaab001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgaab' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
+

+ +### Example 2: _VPN Active Active with BGP settings_ + +This instance deploys the module with the VPN Active Active with APIPA BGP settings. + + +

+ +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + secondCustomBgpIpAddresses: [ + '169.254.22.4' + '169.254.22.5' + ] + } + gatewayType: 'Vpn' + name: 'nvgaaa001' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgaaa' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveBgp", + "customBgpIpAddresses": [ + "169.254.21.4", + "169.254.21.5" + ], + "secondCustomBgpIpAddresses": [ + "169.254.22.4", + "169.254.22.5" + ] + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgaaa001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgaaa" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + secondCustomBgpIpAddresses: [ + '169.254.22.4' + '169.254.22.5' + ] +} +param gatewayType = 'Vpn' +param name = 'nvgaaa001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgaaa' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
+

+ +### Example 3: _VPN Active Active without BGP settings using two existent Public IPs_ + +This instance deploys the module with the VPN Active Active without BGP settings. + + +

+ +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activeActiveNoBgp' + existingSecondPipResourceId: '' + } + gatewayType: 'Vpn' + name: 'nvgaaep001' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgaaep' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + existingFirstPipResourceId: '' + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveNoBgp", + "existingSecondPipResourceId": "" + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgaaep001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgaaep" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "existingFirstPipResourceId": { + "value": "" + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activeActiveNoBgp' + existingSecondPipResourceId: '' +} +param gatewayType = 'Vpn' +param name = 'nvgaaep001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgaaep' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param existingFirstPipResourceId = '' +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
+

+ +### Example 4: _VPN Active Active without BGP settings_ + +This instance deploys the module with the VPN Active Active without BGP settings. + + +

+ +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activeActiveNoBgp' + } + gatewayType: 'Vpn' + name: 'nvgaa001' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgaa' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveNoBgp" + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgaa001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgaa" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activeActiveNoBgp' +} +param gatewayType = 'Vpn' +param name = 'nvgaa001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgaa' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
+

+ +### Example 5: _VPN Active Passive with BGP settings_ + +This instance deploys the module with the VPN Active Passive with APIPA BGP settings. + + +

+ +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + asn: 65815 + clusterMode: 'activePassiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + } + gatewayType: 'Vpn' + name: 'nvgapb001' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgapb' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "asn": 65815, + "clusterMode": "activePassiveBgp", + "customBgpIpAddresses": [ + "169.254.21.4", + "169.254.21.5" + ] + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgapb001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgapb" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + asn: 65815 + clusterMode: 'activePassiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] +} +param gatewayType = 'Vpn' +param name = 'nvgapb001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgapb' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
+

+ +### Example 6: _VPN Active Passive with BGP settings using existing Public IP_ + +This instance deploys the module with the VPN Active Passive with APIPA BGP settings and existing primary public IP. + + +

+ +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + asn: 65815 + clusterMode: 'activePassiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + } + gatewayType: 'Vpn' + name: 'nvgapep001' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgapep' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + existingFirstPipResourceId: '' + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "asn": 65815, + "clusterMode": "activePassiveBgp", + "customBgpIpAddresses": [ + "169.254.21.4", + "169.254.21.5" + ] + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgapep001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgapep" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "existingFirstPipResourceId": { + "value": "" + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + asn: 65815 + clusterMode: 'activePassiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] +} +param gatewayType = 'Vpn' +param name = 'nvgapep001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgapep' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param existingFirstPipResourceId = '' +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
+

+ +### Example 7: _VPN Active Passive without BGP settings_ + +This instance deploys the module with the VPN Active Passive without BGP settings. + + +

+ +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activePassiveNoBgp' + } + gatewayType: 'Vpn' + name: 'nvgap001' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgap' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activePassiveNoBgp" + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgap001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgap" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activePassiveNoBgp' +} +param gatewayType = 'Vpn' +param name = 'nvgap001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgap' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
+

+ +### Example 8: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activeActiveNoBgp' + } + gatewayType: 'Vpn' + name: 'nvgmin001' + vNetResourceId: '' + // Non-required parameters + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveNoBgp" + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgmin001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "VpnGw2AZ" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activeActiveNoBgp' +} +param gatewayType = 'Vpn' +param name = 'nvgmin001' +param vNetResourceId = '' +// Non-required parameters +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +``` + +
+

+ +### Example 9: _ExpressRoute_ + +This instance deploys the module with the ExpressRoute set of required parameters. + + +

+ +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activePassiveBgp' + } + gatewayType: 'ExpressRoute' + name: 'nvger001' + vNetResourceId: '' + // Non-required parameters + domainNameLabel: [ + 'dm-nvger' + ] + firstPipName: 'pip-nvger' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'ErGw1AZ' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activePassiveBgp" + } + }, + "gatewayType": { + "value": "ExpressRoute" + }, + "name": { + "value": "nvger001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "domainNameLabel": { + "value": [ + "dm-nvger" + ] + }, + "firstPipName": { + "value": "pip-nvger" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "ErGw1AZ" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activePassiveBgp' +} +param gatewayType = 'ExpressRoute' +param name = 'nvger001' +param vNetResourceId = '' +// Non-required parameters +param domainNameLabel = [ + 'dm-nvger' +] +param firstPipName = 'pip-nvger' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'ErGw1AZ' +``` + +
+

+ +### Example 10: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + secondCustomBgpIpAddresses: [ + '169.254.22.4' + '169.254.22.5' + ] + secondPipName: 'nvgmax001-pip2' + } + gatewayType: 'Vpn' + name: 'nvgmax001' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgmax' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + natRules: [ + { + externalMappings: [ + { + addressSpace: '192.168.0.0/24' + portRange: '100' + } + ] + internalMappings: [ + { + addressSpace: '10.100.0.0/24' + portRange: '100' + } + ] + mode: 'IngressSnat' + name: 'nat-rule-1-static-IngressSnat' + type: 'Static' + } + { + externalMappings: [ + { + addressSpace: '10.200.0.0/26' + } + ] + internalMappings: [ + { + addressSpace: '172.16.0.0/26' + } + ] + mode: 'EgressSnat' + name: 'nat-rule-2-dynamic-EgressSnat' + type: 'Static' + } + ] + publicIpZones: [ + 1 + 2 + 3 + ] + roleAssignments: [ + { + name: 'db30550e-70b7-4dbe-901e-e9363b69c05f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + skuName: 'VpnGw2AZ' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveBgp", + "customBgpIpAddresses": [ + "169.254.21.4", + "169.254.21.5" + ], + "secondCustomBgpIpAddresses": [ + "169.254.22.4", + "169.254.22.5" + ], + "secondPipName": "nvgmax001-pip2" + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgmax001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgmax" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "natRules": { + "value": [ + { + "externalMappings": [ + { + "addressSpace": "192.168.0.0/24", + "portRange": "100" + } + ], + "internalMappings": [ + { + "addressSpace": "10.100.0.0/24", + "portRange": "100" + } + ], + "mode": "IngressSnat", + "name": "nat-rule-1-static-IngressSnat", + "type": "Static" + }, + { + "externalMappings": [ + { + "addressSpace": "10.200.0.0/26" + } + ], + "internalMappings": [ + { + "addressSpace": "172.16.0.0/26" + } + ], + "mode": "EgressSnat", + "name": "nat-rule-2-dynamic-EgressSnat", + "type": "Static" + } + ] + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "roleAssignments": { + "value": [ + { + "name": "db30550e-70b7-4dbe-901e-e9363b69c05f", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + secondCustomBgpIpAddresses: [ + '169.254.22.4' + '169.254.22.5' + ] + secondPipName: 'nvgmax001-pip2' +} +param gatewayType = 'Vpn' +param name = 'nvgmax001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgmax' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param natRules = [ + { + externalMappings: [ + { + addressSpace: '192.168.0.0/24' + portRange: '100' + } + ] + internalMappings: [ + { + addressSpace: '10.100.0.0/24' + portRange: '100' + } + ] + mode: 'IngressSnat' + name: 'nat-rule-1-static-IngressSnat' + type: 'Static' + } + { + externalMappings: [ + { + addressSpace: '10.200.0.0/26' + } + ] + internalMappings: [ + { + addressSpace: '172.16.0.0/26' + } + ] + mode: 'EgressSnat' + name: 'nat-rule-2-dynamic-EgressSnat' + type: 'Static' + } +] +param publicIpZones = [ + 1 + 2 + 3 +] +param roleAssignments = [ + { + name: 'db30550e-70b7-4dbe-901e-e9363b69c05f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuName = 'VpnGw2AZ' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
+

+ +### Example 11: _Using SKU without Availability Zones_ + +This instance deploys the module with a SKU that does not support Availability Zones. + + +

+ +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activePassiveNoBgp' + } + gatewayType: 'Vpn' + name: 'nvgnaz001' + vNetResourceId: '' + // Non-required parameters + location: '' + publicIpZones: [] + skuName: 'VpnGw1' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activePassiveNoBgp" + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgnaz001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + }, + "publicIpZones": { + "value": [] + }, + "skuName": { + "value": "VpnGw1" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activePassiveNoBgp' +} +param gatewayType = 'Vpn' +param name = 'nvgnaz001' +param vNetResourceId = '' +// Non-required parameters +param location = '' +param publicIpZones = [] +param skuName = 'VpnGw1' +``` + +
+

+ +### Example 12: _VPN_ + +This instance deploys the module with the VPN set of required parameters. + + +

+ +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activeActiveNoBgp' + } + gatewayType: 'Vpn' + name: 'nvgvpn001' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgvpn' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveNoBgp" + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgvpn001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgvpn" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activeActiveNoBgp' +} +param gatewayType = 'Vpn' +param name = 'nvgvpn001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgvpn' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
+

+ +### Example 13: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + asn: 65515 + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + secondCustomBgpIpAddresses: [ + '169.254.22.4' + '169.254.22.5' + ] + } + gatewayType: 'Vpn' + name: 'nvgmwaf001' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgmwaf' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + natRules: [ + { + externalMappings: [ + { + addressSpace: '192.168.0.0/24' + portRange: '100' + } + ] + internalMappings: [ + { + addressSpace: '10.100.0.0/24' + portRange: '100' + } + ] + mode: 'IngressSnat' + name: 'nat-rule-1-static-IngressSnat' + type: 'Static' + } + { + externalMappings: [ + { + addressSpace: '10.200.0.0/26' + } + ] + internalMappings: [ + { + addressSpace: '172.16.0.0/26' + } + ] + mode: 'EgressSnat' + name: 'nat-rule-2-dynamic-EgressSnat' + type: 'Static' + } + ] + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "asn": 65515, + "clusterMode": "activeActiveBgp", + "customBgpIpAddresses": [ + "169.254.21.4", + "169.254.21.5" + ], + "secondCustomBgpIpAddresses": [ + "169.254.22.4", + "169.254.22.5" + ] + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgmwaf001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgmwaf" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "natRules": { + "value": [ + { + "externalMappings": [ + { + "addressSpace": "192.168.0.0/24", + "portRange": "100" + } + ], + "internalMappings": [ + { + "addressSpace": "10.100.0.0/24", + "portRange": "100" + } + ], + "mode": "IngressSnat", + "name": "nat-rule-1-static-IngressSnat", + "type": "Static" + }, + { + "externalMappings": [ + { + "addressSpace": "10.200.0.0/26" + } + ], + "internalMappings": [ + { + "addressSpace": "172.16.0.0/26" + } + ], + "mode": "EgressSnat", + "name": "nat-rule-2-dynamic-EgressSnat", + "type": "Static" + } + ] + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + asn: 65515 + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + secondCustomBgpIpAddresses: [ + '169.254.22.4' + '169.254.22.5' + ] +} +param gatewayType = 'Vpn' +param name = 'nvgmwaf001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgmwaf' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param natRules = [ + { + externalMappings: [ + { + addressSpace: '192.168.0.0/24' + portRange: '100' + } + ] + internalMappings: [ + { + addressSpace: '10.100.0.0/24' + portRange: '100' + } + ] + mode: 'IngressSnat' + name: 'nat-rule-1-static-IngressSnat' + type: 'Static' + } + { + externalMappings: [ + { + addressSpace: '10.200.0.0/26' + } + ] + internalMappings: [ + { + addressSpace: '172.16.0.0/26' + } + ] + mode: 'EgressSnat' + name: 'nat-rule-2-dynamic-EgressSnat' + type: 'Static' + } +] +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`clusterSettings`](#parameter-clustersettings) | object | Specifies one of the following four configurations: Active-Active with (clusterMode = activeActiveBgp) or without (clusterMode = activeActiveNoBgp) BGP, Active-Passive with (clusterMode = activePassiveBgp) or without (clusterMode = activePassiveNoBgp) BGP. | +| [`gatewayType`](#parameter-gatewaytype) | string | Specifies the gateway type. E.g. VPN, ExpressRoute. | +| [`name`](#parameter-name) | string | Specifies the Virtual Network Gateway name. | +| [`skuName`](#parameter-skuname) | string | The SKU of the Gateway. | +| [`vNetResourceId`](#parameter-vnetresourceid) | string | Virtual Network resource ID. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowRemoteVnetTraffic`](#parameter-allowremotevnettraffic) | bool | Configure this gateway to accept traffic from other Azure Virtual Networks. This configuration does not support connectivity to Azure Virtual WAN. | +| [`allowVirtualWanTraffic`](#parameter-allowvirtualwantraffic) | bool | Configures this gateway to accept traffic from remote Virtual WAN networks. | +| [`clientRevokedCertThumbprint`](#parameter-clientrevokedcertthumbprint) | string | Thumbprint of the revoked certificate. This would revoke VPN client certificates matching this thumbprint from connecting to the VNet. | +| [`clientRootCertData`](#parameter-clientrootcertdata) | string | Client root certificate data used to authenticate VPN clients. Cannot be configured if vpnClientAadConfiguration is provided. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`disableIPSecReplayProtection`](#parameter-disableipsecreplayprotection) | bool | disableIPSecReplayProtection flag. Used for VPN Gateways. | +| [`domainNameLabel`](#parameter-domainnamelabel) | array | DNS name(s) of the Public IP resource(s). If you enabled Active-Active mode, you need to provide 2 DNS names, if you want to use this feature. A region specific suffix will be appended to it, e.g.: your-DNS-name.westeurope.cloudapp.azure.com. | +| [`enableBgpRouteTranslationForNat`](#parameter-enablebgproutetranslationfornat) | bool | EnableBgpRouteTranslationForNat flag. Can only be used when "natRules" are enabled on the Virtual Network Gateway. | +| [`enableDnsForwarding`](#parameter-enablednsforwarding) | bool | Whether DNS forwarding is enabled or not and is only supported for Express Route Gateways. The DNS forwarding feature flag must be enabled on the current subscription. | +| [`enablePrivateIpAddress`](#parameter-enableprivateipaddress) | bool | Whether private IP needs to be enabled on this gateway for connections or not. Used for configuring a Site-to-Site VPN connection over ExpressRoute private peering. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`existingFirstPipResourceId`](#parameter-existingfirstpipresourceid) | string | The Public IP resource ID to associate to the Virtual Network Gateway. If empty, then a new Public IP will be created and applied to the Virtual Network Gateway. | +| [`firstPipName`](#parameter-firstpipname) | string | Specifies the name of the Public IP to be created for the Virtual Network Gateway. This will only take effect if no existing Public IP is provided. If neither an existing Public IP nor this parameter is specified, a new Public IP will be created with a default name, using the gateway's name with the '-pip1' suffix. | +| [`gatewayDefaultSiteLocalNetworkGatewayId`](#parameter-gatewaydefaultsitelocalnetworkgatewayid) | string | The reference to the LocalNetworkGateway resource which represents local network site having default routes. Assign Null value in case of removing existing default site setting. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`natRules`](#parameter-natrules) | array | NatRules for virtual network gateway. NAT is supported on the the following SKUs: VpnGw2~5, VpnGw2AZ~5AZ and is supported for IPsec/IKE cross-premises connections only. | +| [`publicIpDiagnosticSettings`](#parameter-publicipdiagnosticsettings) | array | The diagnostic settings of the Public IP. | +| [`publicIPPrefixResourceId`](#parameter-publicipprefixresourceid) | string | Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix. | +| [`publicIpZones`](#parameter-publicipzones) | array | Specifies the zones of the Public IP address. Basic IP SKU does not support Availability Zones. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`vpnClientAadConfiguration`](#parameter-vpnclientaadconfiguration) | object | Configuration for AAD Authentication for P2S Tunnel Type, Cannot be configured if clientRootCertData is provided. | +| [`vpnClientAddressPoolPrefix`](#parameter-vpnclientaddresspoolprefix) | string | The IP address range from which VPN clients will receive an IP address when connected. Range specified must not overlap with on-premise network. | +| [`vpnGatewayGeneration`](#parameter-vpngatewaygeneration) | string | The generation for this VirtualNetworkGateway. Must be None if virtualNetworkGatewayType is not VPN. | +| [`vpnType`](#parameter-vpntype) | string | Specifies the VPN type. | + +### Parameter: `clusterSettings` + +Specifies one of the following four configurations: Active-Active with (clusterMode = activeActiveBgp) or without (clusterMode = activeActiveNoBgp) BGP, Active-Passive with (clusterMode = activePassiveBgp) or without (clusterMode = activePassiveNoBgp) BGP. + +- Required: Yes +- Type: object + +### Parameter: `gatewayType` + +Specifies the gateway type. E.g. VPN, ExpressRoute. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'ExpressRoute' + 'Vpn' + ] + ``` + +### Parameter: `name` + +Specifies the Virtual Network Gateway name. + +- Required: Yes +- Type: string + +### Parameter: `skuName` + +The SKU of the Gateway. + +- Required: No +- Type: string +- Default: `[if(equals(parameters('gatewayType'), 'VPN'), 'VpnGw1AZ', 'ErGw1AZ')]` +- Allowed: + ```Bicep + [ + 'Basic' + 'ErGw1AZ' + 'ErGw2AZ' + 'ErGw3AZ' + 'HighPerformance' + 'Standard' + 'UltraPerformance' + 'VpnGw1' + 'VpnGw1AZ' + 'VpnGw2' + 'VpnGw2AZ' + 'VpnGw3' + 'VpnGw3AZ' + 'VpnGw4' + 'VpnGw4AZ' + 'VpnGw5' + 'VpnGw5AZ' + ] + ``` + +### Parameter: `vNetResourceId` + +Virtual Network resource ID. + +- Required: Yes +- Type: string + +### Parameter: `allowRemoteVnetTraffic` + +Configure this gateway to accept traffic from other Azure Virtual Networks. This configuration does not support connectivity to Azure Virtual WAN. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `allowVirtualWanTraffic` + +Configures this gateway to accept traffic from remote Virtual WAN networks. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `clientRevokedCertThumbprint` + +Thumbprint of the revoked certificate. This would revoke VPN client certificates matching this thumbprint from connecting to the VNet. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `clientRootCertData` + +Client root certificate data used to authenticate VPN clients. Cannot be configured if vpnClientAadConfiguration is provided. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `disableIPSecReplayProtection` + +disableIPSecReplayProtection flag. Used for VPN Gateways. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `domainNameLabel` + +DNS name(s) of the Public IP resource(s). If you enabled Active-Active mode, you need to provide 2 DNS names, if you want to use this feature. A region specific suffix will be appended to it, e.g.: your-DNS-name.westeurope.cloudapp.azure.com. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `enableBgpRouteTranslationForNat` + +EnableBgpRouteTranslationForNat flag. Can only be used when "natRules" are enabled on the Virtual Network Gateway. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableDnsForwarding` + +Whether DNS forwarding is enabled or not and is only supported for Express Route Gateways. The DNS forwarding feature flag must be enabled on the current subscription. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enablePrivateIpAddress` + +Whether private IP needs to be enabled on this gateway for connections or not. Used for configuring a Site-to-Site VPN connection over ExpressRoute private peering. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `existingFirstPipResourceId` + +The Public IP resource ID to associate to the Virtual Network Gateway. If empty, then a new Public IP will be created and applied to the Virtual Network Gateway. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `firstPipName` + +Specifies the name of the Public IP to be created for the Virtual Network Gateway. This will only take effect if no existing Public IP is provided. If neither an existing Public IP nor this parameter is specified, a new Public IP will be created with a default name, using the gateway's name with the '-pip1' suffix. + +- Required: No +- Type: string +- Default: `[format('{0}-pip1', parameters('name'))]` + +### Parameter: `gatewayDefaultSiteLocalNetworkGatewayId` + +The reference to the LocalNetworkGateway resource which represents local network site having default routes. Assign Null value in case of removing existing default site setting. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `natRules` + +NatRules for virtual network gateway. NAT is supported on the the following SKUs: VpnGw2~5, VpnGw2AZ~5AZ and is supported for IPsec/IKE cross-premises connections only. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `publicIpDiagnosticSettings` + +The diagnostic settings of the Public IP. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-publicipdiagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-publicipdiagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-publicipdiagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-publicipdiagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-publicipdiagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-publicipdiagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-publicipdiagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-publicipdiagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-publicipdiagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `publicIpDiagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `publicIpDiagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `publicIpDiagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `publicIpDiagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-publicipdiagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-publicipdiagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-publicipdiagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `publicIpDiagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `publicIpDiagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `publicIpDiagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `publicIpDiagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `publicIpDiagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-publicipdiagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-publicipdiagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `publicIpDiagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `publicIpDiagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `publicIpDiagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `publicIpDiagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `publicIpDiagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `publicIPPrefixResourceId` + +Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `publicIpZones` + +Specifies the zones of the Public IP address. Basic IP SKU does not support Availability Zones. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `vpnClientAadConfiguration` + +Configuration for AAD Authentication for P2S Tunnel Type, Cannot be configured if clientRootCertData is provided. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `vpnClientAddressPoolPrefix` + +The IP address range from which VPN clients will receive an IP address when connected. Range specified must not overlap with on-premise network. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `vpnGatewayGeneration` + +The generation for this VirtualNetworkGateway. Must be None if virtualNetworkGatewayType is not VPN. + +- Required: No +- Type: string +- Default: `'None'` +- Allowed: + ```Bicep + [ + 'Generation1' + 'Generation2' + 'None' + ] + ``` + +### Parameter: `vpnType` + +Specifies the VPN type. + +- Required: No +- Type: string +- Default: `'RouteBased'` +- Allowed: + ```Bicep + [ + 'PolicyBased' + 'RouteBased' + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `activeActive` | bool | Shows if the virtual network gateway is configured in Active-Active mode. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the virtual network gateway. | +| `resourceGroupName` | string | The resource group the virtual network gateway was deployed. | +| `resourceId` | string | The resource ID of the virtual network gateway. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/public-ip-address:0.5.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/virtual-network-gateway/main.bicep b/avm/1.1.0/res/network/virtual-network-gateway/main.bicep new file mode 100644 index 000000000..a213b4102 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/main.bicep @@ -0,0 +1,617 @@ +metadata name = 'Virtual Network Gateways' +metadata description = 'This module deploys a Virtual Network Gateway.' + +@description('Required. Specifies the Virtual Network Gateway name.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The Public IP resource ID to associate to the Virtual Network Gateway. If empty, then a new Public IP will be created and applied to the Virtual Network Gateway.') +param existingFirstPipResourceId string = '' + +@description('Optional. Specifies the name of the Public IP to be created for the Virtual Network Gateway. This will only take effect if no existing Public IP is provided. If neither an existing Public IP nor this parameter is specified, a new Public IP will be created with a default name, using the gateway\'s name with the \'-pip1\' suffix.') +param firstPipName string = '${name}-pip1' + +@description('Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix.') +param publicIPPrefixResourceId string = '' + +@description('Optional. Specifies the zones of the Public IP address. Basic IP SKU does not support Availability Zones.') +param publicIpZones array = [ + 1 + 2 + 3 +] + +@description('Optional. DNS name(s) of the Public IP resource(s). If you enabled Active-Active mode, you need to provide 2 DNS names, if you want to use this feature. A region specific suffix will be appended to it, e.g.: your-DNS-name.westeurope.cloudapp.azure.com.') +param domainNameLabel array = [] + +@description('Required. Specifies the gateway type. E.g. VPN, ExpressRoute.') +@allowed([ + 'Vpn' + 'ExpressRoute' +]) +param gatewayType string + +@description('Optional. The generation for this VirtualNetworkGateway. Must be None if virtualNetworkGatewayType is not VPN.') +@allowed([ + 'Generation1' + 'Generation2' + 'None' +]) +param vpnGatewayGeneration string = 'None' + +@description('Required. The SKU of the Gateway.') +@allowed([ + 'Basic' + 'VpnGw1' + 'VpnGw2' + 'VpnGw3' + 'VpnGw4' + 'VpnGw5' + 'VpnGw1AZ' + 'VpnGw2AZ' + 'VpnGw3AZ' + 'VpnGw4AZ' + 'VpnGw5AZ' + 'Standard' + 'HighPerformance' + 'UltraPerformance' + 'ErGw1AZ' + 'ErGw2AZ' + 'ErGw3AZ' +]) +param skuName string = (gatewayType == 'VPN') ? 'VpnGw1AZ' : 'ErGw1AZ' + +@description('Optional. Specifies the VPN type.') +@allowed([ + 'PolicyBased' + 'RouteBased' +]) +param vpnType string = 'RouteBased' + +@description('Required. Virtual Network resource ID.') +param vNetResourceId string + +@description('Required. Specifies one of the following four configurations: Active-Active with (clusterMode = activeActiveBgp) or without (clusterMode = activeActiveNoBgp) BGP, Active-Passive with (clusterMode = activePassiveBgp) or without (clusterMode = activePassiveNoBgp) BGP.') +param clusterSettings clusterSettingType + +@description('Optional. The IP address range from which VPN clients will receive an IP address when connected. Range specified must not overlap with on-premise network.') +param vpnClientAddressPoolPrefix string = '' + +@description('Optional. Configures this gateway to accept traffic from remote Virtual WAN networks.') +param allowVirtualWanTraffic bool = false + +@description('Optional. Configure this gateway to accept traffic from other Azure Virtual Networks. This configuration does not support connectivity to Azure Virtual WAN.') +param allowRemoteVnetTraffic bool = false + +@description('Optional. disableIPSecReplayProtection flag. Used for VPN Gateways.') +param disableIPSecReplayProtection bool = false + +@description('Optional. Whether DNS forwarding is enabled or not and is only supported for Express Route Gateways. The DNS forwarding feature flag must be enabled on the current subscription.') +param enableDnsForwarding bool = false + +@description('Optional. Whether private IP needs to be enabled on this gateway for connections or not. Used for configuring a Site-to-Site VPN connection over ExpressRoute private peering.') +param enablePrivateIpAddress bool = false + +@description('Optional. The reference to the LocalNetworkGateway resource which represents local network site having default routes. Assign Null value in case of removing existing default site setting.') +param gatewayDefaultSiteLocalNetworkGatewayId string = '' + +@description('Optional. NatRules for virtual network gateway. NAT is supported on the the following SKUs: VpnGw2~5, VpnGw2AZ~5AZ and is supported for IPsec/IKE cross-premises connections only.') +param natRules array = [] + +@description('Optional. EnableBgpRouteTranslationForNat flag. Can only be used when "natRules" are enabled on the Virtual Network Gateway.') +param enableBgpRouteTranslationForNat bool = false + +@description('Optional. Client root certificate data used to authenticate VPN clients. Cannot be configured if vpnClientAadConfiguration is provided.') +param clientRootCertData string = '' + +@description('Optional. Thumbprint of the revoked certificate. This would revoke VPN client certificates matching this thumbprint from connecting to the VNet.') +param clientRevokedCertThumbprint string = '' + +@description('Optional. The diagnostic settings of the Public IP.') +param publicIpDiagnosticSettings diagnosticSettingType + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Configuration for AAD Authentication for P2S Tunnel Type, Cannot be configured if clientRootCertData is provided.') +param vpnClientAadConfiguration object = {} + +// ================// +// Variables // +// ================// + +// Other Variables +var gatewayPipAllocationMethod = skuName == 'Basic' ? 'Dynamic' : 'Static' + +var isExpressRoute = gatewayType == 'ExpressRoute' + +var vpnTypeVar = !isExpressRoute ? vpnType : 'PolicyBased' + +var isBgp = (clusterSettings.clusterMode == 'activeActiveBgp' || clusterSettings.clusterMode == 'activePassiveBgp') && !isExpressRoute + +var isActiveActive = (clusterSettings.clusterMode == 'activeActiveNoBgp' || clusterSettings.clusterMode == 'activeActiveBgp') && !isExpressRoute + +var existingSecondPipResourceIdVar = isActiveActive ? clusterSettings.?existingSecondPipResourceId : null + +var secondPipNameVar = isActiveActive ? (clusterSettings.?secondPipName ?? '${name}-pip2') : null + +var arrayPipNameVar = isActiveActive + ? concat( + !empty(existingFirstPipResourceId) ? [] : [firstPipName], + !empty(existingSecondPipResourceIdVar) ? [] : [secondPipNameVar] + ) + : concat(!empty(existingFirstPipResourceId) ? [] : [firstPipName]) + +// Potential BGP configurations (Active-Active vs Active-Passive) +var bgpSettingsVar = isActiveActive + ? { + asn: clusterSettings.?asn ?? 65515 + bgpPeeringAddresses: [ + { + customBgpIpAddresses: clusterSettings.?customBgpIpAddresses + ipconfigurationId: '${az.resourceId('Microsoft.Network/virtualNetworkGateways', name)}/ipConfigurations/vNetGatewayConfig1' + } + { + customBgpIpAddresses: clusterSettings.?secondCustomBgpIpAddresses + ipconfigurationId: '${az.resourceId('Microsoft.Network/virtualNetworkGateways', name)}/ipConfigurations/vNetGatewayConfig2' + } + ] + } + : { + asn: clusterSettings.?asn ?? 65515 + bgpPeeringAddresses: [ + { + customBgpIpAddresses: clusterSettings.?customBgpIpAddresses + ipconfigurationId: '${az.resourceId('Microsoft.Network/virtualNetworkGateways', name)}/ipConfigurations/vNetGatewayConfig1' + } + ] + } + +// Potential IP configurations (Active-Active vs Active-Passive) +var ipConfiguration = isActiveActive + ? [ + { + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '${vNetResourceId}/subnets/GatewaySubnet' + } + // Use existing Public IP, new Public IP created in this module + publicIPAddress: { + id: !empty(existingFirstPipResourceId) + ? existingFirstPipResourceId + : az.resourceId('Microsoft.Network/publicIPAddresses', firstPipName) + } + } + name: 'vNetGatewayConfig1' + } + { + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '${vNetResourceId}/subnets/GatewaySubnet' + } + publicIPAddress: { + id: isActiveActive + ? !empty(existingSecondPipResourceIdVar) + ? existingSecondPipResourceIdVar + : az.resourceId('Microsoft.Network/publicIPAddresses', secondPipNameVar) + : !empty(existingFirstPipResourceId) + ? existingFirstPipResourceId + : az.resourceId('Microsoft.Network/publicIPAddresses', firstPipName) + } + } + name: 'vNetGatewayConfig2' + } + ] + : [ + { + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '${vNetResourceId}/subnets/GatewaySubnet' + } + publicIPAddress: { + id: !empty(existingFirstPipResourceId) + ? existingFirstPipResourceId + : az.resourceId('Microsoft.Network/publicIPAddresses', firstPipName) + } + } + name: 'vNetGatewayConfig1' + } + ] + +var vpnClientConfiguration = !empty(clientRootCertData) + ? { + vpnClientAddressPool: { + addressPrefixes: [ + vpnClientAddressPoolPrefix + ] + } + vpnClientRootCertificates: [ + { + name: 'RootCert1' + properties: { + publicCertData: clientRootCertData + } + } + ] + vpnClientRevokedCertificates: !empty(clientRevokedCertThumbprint) + ? [ + { + name: 'RevokedCert1' + properties: { + thumbprint: clientRevokedCertThumbprint + } + } + ] + : null + } + : !empty(vpnClientAadConfiguration) + ? { + vpnClientAddressPool: { + addressPrefixes: [ + vpnClientAddressPoolPrefix + ] + } + aadTenant: vpnClientAadConfiguration.aadTenant + aadAudience: vpnClientAadConfiguration.aadAudience + aadIssuer: vpnClientAadConfiguration.aadIssuer + vpnAuthenticationTypes: vpnClientAadConfiguration.vpnAuthenticationTypes + vpnClientProtocols: vpnClientAadConfiguration.vpnClientProtocols + } + : null + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +// ================// +// Deployments // +// ================// + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.res.network-virtualnetworkgateway.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +// Public IPs +@batchSize(1) +module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = [ + for (virtualGatewayPublicIpName, index) in arrayPipNameVar: { + name: virtualGatewayPublicIpName + params: { + name: virtualGatewayPublicIpName + diagnosticSettings: publicIpDiagnosticSettings + location: location + lock: lock + publicIPAllocationMethod: gatewayPipAllocationMethod + publicIpPrefixResourceId: !empty(publicIPPrefixResourceId) ? publicIPPrefixResourceId : '' + tags: tags + skuName: skuName == 'Basic' ? 'Basic' : 'Standard' + zones: skuName != 'Basic' ? publicIpZones : [] + dnsSettings: { + domainNameLabel: length(arrayPipNameVar) == length(domainNameLabel) + ? domainNameLabel[index] + : virtualGatewayPublicIpName + domainNameLabelScope: '' + } + } + } +] + +// VNET Gateway +// ============ +resource virtualNetworkGateway 'Microsoft.Network/virtualNetworkGateways@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + ipConfigurations: ipConfiguration + activeActive: isActiveActive + allowRemoteVnetTraffic: allowRemoteVnetTraffic + allowVirtualWanTraffic: allowVirtualWanTraffic + enableBgp: isBgp + bgpSettings: isBgp ? bgpSettingsVar : null + disableIPSecReplayProtection: disableIPSecReplayProtection + enableDnsForwarding: !isExpressRoute ? enableDnsForwarding : null + enablePrivateIpAddress: enablePrivateIpAddress + enableBgpRouteTranslationForNat: enableBgpRouteTranslationForNat + gatewayType: gatewayType + gatewayDefaultSite: !empty(gatewayDefaultSiteLocalNetworkGatewayId) + ? { + id: gatewayDefaultSiteLocalNetworkGatewayId + } + : null + sku: { + name: skuName + tier: skuName + } + vpnType: vpnTypeVar + vpnClientConfiguration: !empty(vpnClientAddressPoolPrefix) ? vpnClientConfiguration : null + vpnGatewayGeneration: gatewayType == 'Vpn' ? vpnGatewayGeneration : 'None' + } + dependsOn: [ + publicIPAddress + ] +} + +module virtualNetworkGateway_natRules 'nat-rule/main.bicep' = [ + for (natRule, index) in natRules: { + name: '${deployment().name}-NATRule-${index}' + params: { + name: natRule.name + virtualNetworkGatewayName: virtualNetworkGateway.name + externalMappings: natRule.?externalMappings ?? [] + internalMappings: natRule.?internalMappings ?? [] + ipConfigurationId: natRule.?ipConfigurationId ?? '' + mode: natRule.?mode ?? '' + type: natRule.?type ?? '' + } + } +] + +resource virtualNetworkGateway_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: virtualNetworkGateway +} + +resource virtualNetworkGateway_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: virtualNetworkGateway + } +] + +resource virtualNetworkGateway_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + virtualNetworkGateway.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: virtualNetworkGateway + } +] + +// ================// +// Outputs // +// ================// +@description('The resource group the virtual network gateway was deployed.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the virtual network gateway.') +output name string = virtualNetworkGateway.name + +@description('The resource ID of the virtual network gateway.') +output resourceId string = virtualNetworkGateway.id + +@description('Shows if the virtual network gateway is configured in Active-Active mode.') +output activeActive bool = virtualNetworkGateway.properties.activeActive + +@description('The location the resource was deployed into.') +output location string = virtualNetworkGateway.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? + +type activePassiveNoBgpType = { + clusterMode: 'activePassiveNoBgp' +} + +type activeActiveNoBgpType = { + clusterMode: 'activeActiveNoBgp' + + @description('Optional. The secondary Public IP resource ID to associate to the Virtual Network Gateway in the Active-Active mode. If empty, then a new secondary Public IP will be created as part of this module and applied to the Virtual Network Gateway.') + existingSecondPipResourceId: string? + + @description('Optional. Specifies the name of the secondary Public IP to be created for the Virtual Network Gateway in the Active-Active mode. This will only take effect if no existing secondary Public IP is provided. If neither an existing secondary Public IP nor this parameter is specified, a new secondary Public IP will be created with a default name, using the gateway\'s name with the \'-pip2\' suffix.') + secondPipName: string? +} + +type activePassiveBgpType = { + clusterMode: 'activePassiveBgp' + + @description('Optional. The Autonomous System Number value. If it\'s not provided, a default \'65515\' value will be assigned to the ASN.') + @minValue(0) + @maxValue(4294967295) + asn: int? + + @description('Optional. The list of custom BGP IP Address (APIPA) peering addresses which belong to IP configuration.') + customBgpIpAddresses: string[]? +} + +type activeActiveBgpType = { + clusterMode: 'activeActiveBgp' + + @description('Optional. The secondary Public IP resource ID to associate to the Virtual Network Gateway in the Active-Active mode. If empty, then a new secondary Public IP will be created as part of this module and applied to the Virtual Network Gateway.') + existingSecondPipResourceId: string? + + @description('Optional. Specifies the name of the secondary Public IP to be created for the Virtual Network Gateway in the Active-Active mode. This will only take effect if no existing secondary Public IP is provided. If neither an existing secondary Public IP nor this parameter is specified, a new secondary Public IP will be created with a default name, using the gateway\'s name with the \'-pip2\' suffix.') + secondPipName: string? + + @description('Optional. The Autonomous System Number value. If it\'s not provided, a default \'65515\' value will be assigned to the ASN.') + @minValue(0) + @maxValue(4294967295) + asn: int? + + @description('Optional. The list of custom BGP IP Address (APIPA) peering addresses which belong to IP configuration.') + customBgpIpAddresses: string[]? + @description('Optional. The list of the second custom BGP IP Address (APIPA) peering addresses which belong to IP configuration.') + secondCustomBgpIpAddresses: string[]? +} + +@discriminator('clusterMode') +type clusterSettingType = activeActiveNoBgpType | activeActiveBgpType | activePassiveBgpType | activePassiveNoBgpType diff --git a/avm/1.1.0/res/network/virtual-network-gateway/main.json b/avm/1.1.0/res/network/virtual-network-gateway/main.json new file mode 100644 index 000000000..55383394d --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/main.json @@ -0,0 +1,1630 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "7603428291495557736" + }, + "name": "Virtual Network Gateways", + "description": "This module deploys a Virtual Network Gateway." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "activePassiveNoBgpType": { + "type": "object", + "properties": { + "clusterMode": { + "type": "string", + "allowedValues": [ + "activePassiveNoBgp" + ] + } + } + }, + "activeActiveNoBgpType": { + "type": "object", + "properties": { + "clusterMode": { + "type": "string", + "allowedValues": [ + "activeActiveNoBgp" + ] + }, + "existingSecondPipResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondary Public IP resource ID to associate to the Virtual Network Gateway in the Active-Active mode. If empty, then a new secondary Public IP will be created as part of this module and applied to the Virtual Network Gateway." + } + }, + "secondPipName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the name of the secondary Public IP to be created for the Virtual Network Gateway in the Active-Active mode. This will only take effect if no existing secondary Public IP is provided. If neither an existing secondary Public IP nor this parameter is specified, a new secondary Public IP will be created with a default name, using the gateway's name with the '-pip2' suffix." + } + } + } + }, + "activePassiveBgpType": { + "type": "object", + "properties": { + "clusterMode": { + "type": "string", + "allowedValues": [ + "activePassiveBgp" + ] + }, + "asn": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 4294967295, + "metadata": { + "description": "Optional. The Autonomous System Number value. If it's not provided, a default '65515' value will be assigned to the ASN." + } + }, + "customBgpIpAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of custom BGP IP Address (APIPA) peering addresses which belong to IP configuration." + } + } + } + }, + "activeActiveBgpType": { + "type": "object", + "properties": { + "clusterMode": { + "type": "string", + "allowedValues": [ + "activeActiveBgp" + ] + }, + "existingSecondPipResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondary Public IP resource ID to associate to the Virtual Network Gateway in the Active-Active mode. If empty, then a new secondary Public IP will be created as part of this module and applied to the Virtual Network Gateway." + } + }, + "secondPipName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the name of the secondary Public IP to be created for the Virtual Network Gateway in the Active-Active mode. This will only take effect if no existing secondary Public IP is provided. If neither an existing secondary Public IP nor this parameter is specified, a new secondary Public IP will be created with a default name, using the gateway's name with the '-pip2' suffix." + } + }, + "asn": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 4294967295, + "metadata": { + "description": "Optional. The Autonomous System Number value. If it's not provided, a default '65515' value will be assigned to the ASN." + } + }, + "customBgpIpAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of custom BGP IP Address (APIPA) peering addresses which belong to IP configuration." + } + }, + "secondCustomBgpIpAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of the second custom BGP IP Address (APIPA) peering addresses which belong to IP configuration." + } + } + } + }, + "clusterSettingType": { + "type": "object", + "discriminator": { + "propertyName": "clusterMode", + "mapping": { + "activeActiveNoBgp": { + "$ref": "#/definitions/activeActiveNoBgpType" + }, + "activeActiveBgp": { + "$ref": "#/definitions/activeActiveBgpType" + }, + "activePassiveBgp": { + "$ref": "#/definitions/activePassiveBgpType" + }, + "activePassiveNoBgp": { + "$ref": "#/definitions/activePassiveNoBgpType" + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specifies the Virtual Network Gateway name." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "existingFirstPipResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Public IP resource ID to associate to the Virtual Network Gateway. If empty, then a new Public IP will be created and applied to the Virtual Network Gateway." + } + }, + "firstPipName": { + "type": "string", + "defaultValue": "[format('{0}-pip1', parameters('name'))]", + "metadata": { + "description": "Optional. Specifies the name of the Public IP to be created for the Virtual Network Gateway. This will only take effect if no existing Public IP is provided. If neither an existing Public IP nor this parameter is specified, a new Public IP will be created with a default name, using the gateway's name with the '-pip1' suffix." + } + }, + "publicIPPrefixResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIpZones": { + "type": "array", + "defaultValue": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. Specifies the zones of the Public IP address. Basic IP SKU does not support Availability Zones." + } + }, + "domainNameLabel": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. DNS name(s) of the Public IP resource(s). If you enabled Active-Active mode, you need to provide 2 DNS names, if you want to use this feature. A region specific suffix will be appended to it, e.g.: your-DNS-name.westeurope.cloudapp.azure.com." + } + }, + "gatewayType": { + "type": "string", + "allowedValues": [ + "Vpn", + "ExpressRoute" + ], + "metadata": { + "description": "Required. Specifies the gateway type. E.g. VPN, ExpressRoute." + } + }, + "vpnGatewayGeneration": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Generation1", + "Generation2", + "None" + ], + "metadata": { + "description": "Optional. The generation for this VirtualNetworkGateway. Must be None if virtualNetworkGatewayType is not VPN." + } + }, + "skuName": { + "type": "string", + "defaultValue": "[if(equals(parameters('gatewayType'), 'VPN'), 'VpnGw1AZ', 'ErGw1AZ')]", + "allowedValues": [ + "Basic", + "VpnGw1", + "VpnGw2", + "VpnGw3", + "VpnGw4", + "VpnGw5", + "VpnGw1AZ", + "VpnGw2AZ", + "VpnGw3AZ", + "VpnGw4AZ", + "VpnGw5AZ", + "Standard", + "HighPerformance", + "UltraPerformance", + "ErGw1AZ", + "ErGw2AZ", + "ErGw3AZ" + ], + "metadata": { + "description": "Required. The SKU of the Gateway." + } + }, + "vpnType": { + "type": "string", + "defaultValue": "RouteBased", + "allowedValues": [ + "PolicyBased", + "RouteBased" + ], + "metadata": { + "description": "Optional. Specifies the VPN type." + } + }, + "vNetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Virtual Network resource ID." + } + }, + "clusterSettings": { + "$ref": "#/definitions/clusterSettingType", + "metadata": { + "description": "Required. Specifies one of the following four configurations: Active-Active with (clusterMode = activeActiveBgp) or without (clusterMode = activeActiveNoBgp) BGP, Active-Passive with (clusterMode = activePassiveBgp) or without (clusterMode = activePassiveNoBgp) BGP." + } + }, + "vpnClientAddressPoolPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The IP address range from which VPN clients will receive an IP address when connected. Range specified must not overlap with on-premise network." + } + }, + "allowVirtualWanTraffic": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Configures this gateway to accept traffic from remote Virtual WAN networks." + } + }, + "allowRemoteVnetTraffic": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Configure this gateway to accept traffic from other Azure Virtual Networks. This configuration does not support connectivity to Azure Virtual WAN." + } + }, + "disableIPSecReplayProtection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. disableIPSecReplayProtection flag. Used for VPN Gateways." + } + }, + "enableDnsForwarding": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether DNS forwarding is enabled or not and is only supported for Express Route Gateways. The DNS forwarding feature flag must be enabled on the current subscription." + } + }, + "enablePrivateIpAddress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether private IP needs to be enabled on this gateway for connections or not. Used for configuring a Site-to-Site VPN connection over ExpressRoute private peering." + } + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The reference to the LocalNetworkGateway resource which represents local network site having default routes. Assign Null value in case of removing existing default site setting." + } + }, + "natRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. NatRules for virtual network gateway. NAT is supported on the the following SKUs: VpnGw2~5, VpnGw2AZ~5AZ and is supported for IPsec/IKE cross-premises connections only." + } + }, + "enableBgpRouteTranslationForNat": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. EnableBgpRouteTranslationForNat flag. Can only be used when \"natRules\" are enabled on the Virtual Network Gateway." + } + }, + "clientRootCertData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Client root certificate data used to authenticate VPN clients. Cannot be configured if vpnClientAadConfiguration is provided." + } + }, + "clientRevokedCertThumbprint": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Thumbprint of the revoked certificate. This would revoke VPN client certificates matching this thumbprint from connecting to the VNet." + } + }, + "publicIpDiagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the Public IP." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "vpnClientAadConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Configuration for AAD Authentication for P2S Tunnel Type, Cannot be configured if clientRootCertData is provided." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "gatewayPipAllocationMethod": "[if(equals(parameters('skuName'), 'Basic'), 'Dynamic', 'Static')]", + "isExpressRoute": "[equals(parameters('gatewayType'), 'ExpressRoute')]", + "vpnTypeVar": "[if(not(variables('isExpressRoute')), parameters('vpnType'), 'PolicyBased')]", + "isBgp": "[and(or(equals(parameters('clusterSettings').clusterMode, 'activeActiveBgp'), equals(parameters('clusterSettings').clusterMode, 'activePassiveBgp')), not(variables('isExpressRoute')))]", + "isActiveActive": "[and(or(equals(parameters('clusterSettings').clusterMode, 'activeActiveNoBgp'), equals(parameters('clusterSettings').clusterMode, 'activeActiveBgp')), not(variables('isExpressRoute')))]", + "existingSecondPipResourceIdVar": "[if(variables('isActiveActive'), tryGet(parameters('clusterSettings'), 'existingSecondPipResourceId'), null())]", + "secondPipNameVar": "[if(variables('isActiveActive'), coalesce(tryGet(parameters('clusterSettings'), 'secondPipName'), format('{0}-pip2', parameters('name'))), null())]", + "arrayPipNameVar": "[if(variables('isActiveActive'), concat(if(not(empty(parameters('existingFirstPipResourceId'))), createArray(), createArray(parameters('firstPipName'))), if(not(empty(variables('existingSecondPipResourceIdVar'))), createArray(), createArray(variables('secondPipNameVar')))), concat(if(not(empty(parameters('existingFirstPipResourceId'))), createArray(), createArray(parameters('firstPipName')))))]", + "bgpSettingsVar": "[if(variables('isActiveActive'), createObject('asn', coalesce(tryGet(parameters('clusterSettings'), 'asn'), 65515), 'bgpPeeringAddresses', createArray(createObject('customBgpIpAddresses', tryGet(parameters('clusterSettings'), 'customBgpIpAddresses'), 'ipconfigurationId', format('{0}/ipConfigurations/vNetGatewayConfig1', resourceId('Microsoft.Network/virtualNetworkGateways', parameters('name')))), createObject('customBgpIpAddresses', tryGet(parameters('clusterSettings'), 'secondCustomBgpIpAddresses'), 'ipconfigurationId', format('{0}/ipConfigurations/vNetGatewayConfig2', resourceId('Microsoft.Network/virtualNetworkGateways', parameters('name')))))), createObject('asn', coalesce(tryGet(parameters('clusterSettings'), 'asn'), 65515), 'bgpPeeringAddresses', createArray(createObject('customBgpIpAddresses', tryGet(parameters('clusterSettings'), 'customBgpIpAddresses'), 'ipconfigurationId', format('{0}/ipConfigurations/vNetGatewayConfig1', resourceId('Microsoft.Network/virtualNetworkGateways', parameters('name')))))))]", + "ipConfiguration": "[if(variables('isActiveActive'), createArray(createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', if(not(empty(parameters('existingFirstPipResourceId'))), parameters('existingFirstPipResourceId'), resourceId('Microsoft.Network/publicIPAddresses', parameters('firstPipName'))))), 'name', 'vNetGatewayConfig1'), createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', if(variables('isActiveActive'), if(not(empty(variables('existingSecondPipResourceIdVar'))), variables('existingSecondPipResourceIdVar'), resourceId('Microsoft.Network/publicIPAddresses', variables('secondPipNameVar'))), if(not(empty(parameters('existingFirstPipResourceId'))), parameters('existingFirstPipResourceId'), resourceId('Microsoft.Network/publicIPAddresses', parameters('firstPipName')))))), 'name', 'vNetGatewayConfig2')), createArray(createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', if(not(empty(parameters('existingFirstPipResourceId'))), parameters('existingFirstPipResourceId'), resourceId('Microsoft.Network/publicIPAddresses', parameters('firstPipName'))))), 'name', 'vNetGatewayConfig1')))]", + "vpnClientConfiguration": "[if(not(empty(parameters('clientRootCertData'))), createObject('vpnClientAddressPool', createObject('addressPrefixes', createArray(parameters('vpnClientAddressPoolPrefix'))), 'vpnClientRootCertificates', createArray(createObject('name', 'RootCert1', 'properties', createObject('publicCertData', parameters('clientRootCertData')))), 'vpnClientRevokedCertificates', if(not(empty(parameters('clientRevokedCertThumbprint'))), createArray(createObject('name', 'RevokedCert1', 'properties', createObject('thumbprint', parameters('clientRevokedCertThumbprint')))), null())), if(not(empty(parameters('vpnClientAadConfiguration'))), createObject('vpnClientAddressPool', createObject('addressPrefixes', createArray(parameters('vpnClientAddressPoolPrefix'))), 'aadTenant', parameters('vpnClientAadConfiguration').aadTenant, 'aadAudience', parameters('vpnClientAadConfiguration').aadAudience, 'aadIssuer', parameters('vpnClientAadConfiguration').aadIssuer, 'vpnAuthenticationTypes', parameters('vpnClientAadConfiguration').vpnAuthenticationTypes, 'vpnClientProtocols', parameters('vpnClientAadConfiguration').vpnClientProtocols), null()))]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.res.network-virtualnetworkgateway.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "virtualNetworkGateway": { + "type": "Microsoft.Network/virtualNetworkGateways", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "ipConfigurations": "[variables('ipConfiguration')]", + "activeActive": "[variables('isActiveActive')]", + "allowRemoteVnetTraffic": "[parameters('allowRemoteVnetTraffic')]", + "allowVirtualWanTraffic": "[parameters('allowVirtualWanTraffic')]", + "enableBgp": "[variables('isBgp')]", + "bgpSettings": "[if(variables('isBgp'), variables('bgpSettingsVar'), null())]", + "disableIPSecReplayProtection": "[parameters('disableIPSecReplayProtection')]", + "enableDnsForwarding": "[if(not(variables('isExpressRoute')), parameters('enableDnsForwarding'), null())]", + "enablePrivateIpAddress": "[parameters('enablePrivateIpAddress')]", + "enableBgpRouteTranslationForNat": "[parameters('enableBgpRouteTranslationForNat')]", + "gatewayType": "[parameters('gatewayType')]", + "gatewayDefaultSite": "[if(not(empty(parameters('gatewayDefaultSiteLocalNetworkGatewayId'))), createObject('id', parameters('gatewayDefaultSiteLocalNetworkGatewayId')), null())]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuName')]" + }, + "vpnType": "[variables('vpnTypeVar')]", + "vpnClientConfiguration": "[if(not(empty(parameters('vpnClientAddressPoolPrefix'))), variables('vpnClientConfiguration'), null())]", + "vpnGatewayGeneration": "[if(equals(parameters('gatewayType'), 'Vpn'), parameters('vpnGatewayGeneration'), 'None')]" + }, + "dependsOn": [ + "publicIPAddress" + ] + }, + "virtualNetworkGateway_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/virtualNetworkGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "virtualNetworkGateway" + ] + }, + "virtualNetworkGateway_diagnosticSettings": { + "copy": { + "name": "virtualNetworkGateway_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/virtualNetworkGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "virtualNetworkGateway" + ] + }, + "virtualNetworkGateway_roleAssignments": { + "copy": { + "name": "virtualNetworkGateway_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworkGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworkGateways', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "virtualNetworkGateway" + ] + }, + "publicIPAddress": { + "copy": { + "name": "publicIPAddress", + "count": "[length(variables('arrayPipNameVar'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[variables('arrayPipNameVar')[copyIndex()]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('arrayPipNameVar')[copyIndex()]]" + }, + "diagnosticSettings": { + "value": "[parameters('publicIpDiagnosticSettings')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "publicIPAllocationMethod": { + "value": "[variables('gatewayPipAllocationMethod')]" + }, + "publicIpPrefixResourceId": "[if(not(empty(parameters('publicIPPrefixResourceId'))), createObject('value', parameters('publicIPPrefixResourceId')), createObject('value', ''))]", + "tags": { + "value": "[parameters('tags')]" + }, + "skuName": "[if(equals(parameters('skuName'), 'Basic'), createObject('value', 'Basic'), createObject('value', 'Standard'))]", + "zones": "[if(not(equals(parameters('skuName'), 'Basic')), createObject('value', parameters('publicIpZones')), createObject('value', createArray()))]", + "dnsSettings": { + "value": { + "domainNameLabel": "[if(equals(length(variables('arrayPipNameVar')), length(parameters('domainNameLabel'))), parameters('domainNameLabel')[copyIndex()], variables('arrayPipNameVar')[copyIndex()])]", + "domainNameLabelScope": "" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "14450344965065009842" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "", + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "metadata": { + "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + } + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.5.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": null + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" + } + } + } + } + }, + "virtualNetworkGateway_natRules": { + "copy": { + "name": "virtualNetworkGateway_natRules", + "count": "[length(parameters('natRules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NATRule-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('natRules')[copyIndex()].name]" + }, + "virtualNetworkGatewayName": { + "value": "[parameters('name')]" + }, + "externalMappings": { + "value": "[coalesce(tryGet(parameters('natRules')[copyIndex()], 'externalMappings'), createArray())]" + }, + "internalMappings": { + "value": "[coalesce(tryGet(parameters('natRules')[copyIndex()], 'internalMappings'), createArray())]" + }, + "ipConfigurationId": { + "value": "[coalesce(tryGet(parameters('natRules')[copyIndex()], 'ipConfigurationId'), '')]" + }, + "mode": { + "value": "[coalesce(tryGet(parameters('natRules')[copyIndex()], 'mode'), '')]" + }, + "type": { + "value": "[coalesce(tryGet(parameters('natRules')[copyIndex()], 'type'), '')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9322793849134607569" + }, + "name": "VPN Gateway NAT Rules", + "description": "This module deploys a Virtual Network Gateway NAT Rule." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NAT rule." + } + }, + "virtualNetworkGatewayName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network Gateway this NAT rule is associated with. Required if the template is used in a standalone deployment." + } + }, + "externalMappings": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An address prefix range of destination IPs on the outside network that source IPs will be mapped to. In other words, your post-NAT address prefix range." + } + }, + "internalMappings": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An address prefix range of source IPs on the inside network that will be mapped to a set of external IPs. In other words, your pre-NAT address prefix range." + } + }, + "ipConfigurationId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. A NAT rule must be configured to a specific Virtual Network Gateway instance. This is applicable to Dynamic NAT only. Static NAT rules are automatically applied to both Virtual Network Gateway instances." + } + }, + "mode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "EgressSnat", + "IngressSnat" + ], + "metadata": { + "description": "Optional. The type of NAT rule for Virtual Network NAT. IngressSnat mode (also known as Ingress Source NAT) is applicable to traffic entering the Azure hub's site-to-site Virtual Network gateway. EgressSnat mode (also known as Egress Source NAT) is applicable to traffic leaving the Azure hub's Site-to-site Virtual Network gateway." + } + }, + "type": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The type of NAT rule for Virtual Network NAT. Static one-to-one NAT establishes a one-to-one relationship between an internal address and an external address while Dynamic NAT assigns an IP and port based on availability." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworkGateways/natRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkGatewayName'), parameters('name'))]", + "properties": { + "externalMappings": "[parameters('externalMappings')]", + "internalMappings": "[parameters('internalMappings')]", + "ipConfigurationId": "[if(not(empty(parameters('ipConfigurationId'))), parameters('ipConfigurationId'), null())]", + "mode": "[if(not(empty(parameters('mode'))), parameters('mode'), null())]", + "type": "[if(not(empty(parameters('type'))), parameters('type'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the NAT rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the NAT rule." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworkGateways/natRules', parameters('virtualNetworkGatewayName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the NAT rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "virtualNetworkGateway" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network gateway was deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network gateway." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network gateway." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworkGateways', parameters('name'))]" + }, + "activeActive": { + "type": "bool", + "metadata": { + "description": "Shows if the virtual network gateway is configured in Active-Active mode." + }, + "value": "[reference('virtualNetworkGateway').activeActive]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetworkGateway', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-network-gateway/nat-rule/README.md b/avm/1.1.0/res/network/virtual-network-gateway/nat-rule/README.md new file mode 100644 index 000000000..4a3987328 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/nat-rule/README.md @@ -0,0 +1,117 @@ +# VPN Gateway NAT Rules `[Microsoft.Network/virtualNetworkGateways/natRules]` + +This module deploys a Virtual Network Gateway NAT Rule. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/virtualNetworkGateways/natRules` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/virtualNetworkGateways/natRules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the NAT rule. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`virtualNetworkGatewayName`](#parameter-virtualnetworkgatewayname) | string | The name of the parent Virtual Network Gateway this NAT rule is associated with. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`externalMappings`](#parameter-externalmappings) | array | An address prefix range of destination IPs on the outside network that source IPs will be mapped to. In other words, your post-NAT address prefix range. | +| [`internalMappings`](#parameter-internalmappings) | array | An address prefix range of source IPs on the inside network that will be mapped to a set of external IPs. In other words, your pre-NAT address prefix range. | +| [`ipConfigurationId`](#parameter-ipconfigurationid) | string | A NAT rule must be configured to a specific Virtual Network Gateway instance. This is applicable to Dynamic NAT only. Static NAT rules are automatically applied to both Virtual Network Gateway instances. | +| [`mode`](#parameter-mode) | string | The type of NAT rule for Virtual Network NAT. IngressSnat mode (also known as Ingress Source NAT) is applicable to traffic entering the Azure hub's site-to-site Virtual Network gateway. EgressSnat mode (also known as Egress Source NAT) is applicable to traffic leaving the Azure hub's Site-to-site Virtual Network gateway. | +| [`type`](#parameter-type) | string | The type of NAT rule for Virtual Network NAT. Static one-to-one NAT establishes a one-to-one relationship between an internal address and an external address while Dynamic NAT assigns an IP and port based on availability. | + +### Parameter: `name` + +The name of the NAT rule. + +- Required: Yes +- Type: string + +### Parameter: `virtualNetworkGatewayName` + +The name of the parent Virtual Network Gateway this NAT rule is associated with. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `externalMappings` + +An address prefix range of destination IPs on the outside network that source IPs will be mapped to. In other words, your post-NAT address prefix range. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `internalMappings` + +An address prefix range of source IPs on the inside network that will be mapped to a set of external IPs. In other words, your pre-NAT address prefix range. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `ipConfigurationId` + +A NAT rule must be configured to a specific Virtual Network Gateway instance. This is applicable to Dynamic NAT only. Static NAT rules are automatically applied to both Virtual Network Gateway instances. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `mode` + +The type of NAT rule for Virtual Network NAT. IngressSnat mode (also known as Ingress Source NAT) is applicable to traffic entering the Azure hub's site-to-site Virtual Network gateway. EgressSnat mode (also known as Egress Source NAT) is applicable to traffic leaving the Azure hub's Site-to-site Virtual Network gateway. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'EgressSnat' + 'IngressSnat' + ] + ``` + +### Parameter: `type` + +The type of NAT rule for Virtual Network NAT. Static one-to-one NAT establishes a one-to-one relationship between an internal address and an external address while Dynamic NAT assigns an IP and port based on availability. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Dynamic' + 'Static' + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the NAT rule. | +| `resourceGroupName` | string | The name of the resource group the NAT rule was deployed into. | +| `resourceId` | string | The resource ID of the NAT rule. | diff --git a/avm/1.1.0/res/network/virtual-network-gateway/nat-rule/main.bicep b/avm/1.1.0/res/network/virtual-network-gateway/nat-rule/main.bicep new file mode 100644 index 000000000..510a09ada --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/nat-rule/main.bicep @@ -0,0 +1,58 @@ +metadata name = 'VPN Gateway NAT Rules' +metadata description = 'This module deploys a Virtual Network Gateway NAT Rule.' + +@description('Required. The name of the NAT rule.') +param name string + +@description('Conditional. The name of the parent Virtual Network Gateway this NAT rule is associated with. Required if the template is used in a standalone deployment.') +param virtualNetworkGatewayName string + +@description('Optional. An address prefix range of destination IPs on the outside network that source IPs will be mapped to. In other words, your post-NAT address prefix range.') +param externalMappings array = [] + +@description('Optional. An address prefix range of source IPs on the inside network that will be mapped to a set of external IPs. In other words, your pre-NAT address prefix range.') +param internalMappings array = [] + +@description('Optional. A NAT rule must be configured to a specific Virtual Network Gateway instance. This is applicable to Dynamic NAT only. Static NAT rules are automatically applied to both Virtual Network Gateway instances.') +param ipConfigurationId string = '' + +@description('Optional. The type of NAT rule for Virtual Network NAT. IngressSnat mode (also known as Ingress Source NAT) is applicable to traffic entering the Azure hub\'s site-to-site Virtual Network gateway. EgressSnat mode (also known as Egress Source NAT) is applicable to traffic leaving the Azure hub\'s Site-to-site Virtual Network gateway.') +@allowed([ + '' + 'EgressSnat' + 'IngressSnat' +]) +param mode string = '' + +@description('Optional. The type of NAT rule for Virtual Network NAT. Static one-to-one NAT establishes a one-to-one relationship between an internal address and an external address while Dynamic NAT assigns an IP and port based on availability.') +@allowed([ + '' + 'Dynamic' + 'Static' +]) +param type string = '' + +resource virtualNetworkGateway 'Microsoft.Network/virtualNetworkGateways@2023-04-01' existing = { + name: virtualNetworkGatewayName +} + +resource natRule 'Microsoft.Network/virtualNetworkGateways/natRules@2023-04-01' = { + name: name + parent: virtualNetworkGateway + properties: { + externalMappings: externalMappings + internalMappings: internalMappings + ipConfigurationId: !empty(ipConfigurationId) ? ipConfigurationId : null + mode: !empty(mode) ? any(mode) : null + type: !empty(type) ? any(type) : null + } +} + +@description('The name of the NAT rule.') +output name string = natRule.name + +@description('The resource ID of the NAT rule.') +output resourceId string = natRule.id + +@description('The name of the resource group the NAT rule was deployed into.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/network/virtual-network-gateway/nat-rule/main.json b/avm/1.1.0/res/network/virtual-network-gateway/nat-rule/main.json new file mode 100644 index 000000000..368de8bf9 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/nat-rule/main.json @@ -0,0 +1,109 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9322793849134607569" + }, + "name": "VPN Gateway NAT Rules", + "description": "This module deploys a Virtual Network Gateway NAT Rule." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NAT rule." + } + }, + "virtualNetworkGatewayName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network Gateway this NAT rule is associated with. Required if the template is used in a standalone deployment." + } + }, + "externalMappings": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An address prefix range of destination IPs on the outside network that source IPs will be mapped to. In other words, your post-NAT address prefix range." + } + }, + "internalMappings": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An address prefix range of source IPs on the inside network that will be mapped to a set of external IPs. In other words, your pre-NAT address prefix range." + } + }, + "ipConfigurationId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. A NAT rule must be configured to a specific Virtual Network Gateway instance. This is applicable to Dynamic NAT only. Static NAT rules are automatically applied to both Virtual Network Gateway instances." + } + }, + "mode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "EgressSnat", + "IngressSnat" + ], + "metadata": { + "description": "Optional. The type of NAT rule for Virtual Network NAT. IngressSnat mode (also known as Ingress Source NAT) is applicable to traffic entering the Azure hub's site-to-site Virtual Network gateway. EgressSnat mode (also known as Egress Source NAT) is applicable to traffic leaving the Azure hub's Site-to-site Virtual Network gateway." + } + }, + "type": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The type of NAT rule for Virtual Network NAT. Static one-to-one NAT establishes a one-to-one relationship between an internal address and an external address while Dynamic NAT assigns an IP and port based on availability." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworkGateways/natRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkGatewayName'), parameters('name'))]", + "properties": { + "externalMappings": "[parameters('externalMappings')]", + "internalMappings": "[parameters('internalMappings')]", + "ipConfigurationId": "[if(not(empty(parameters('ipConfigurationId'))), parameters('ipConfigurationId'), null())]", + "mode": "[if(not(empty(parameters('mode'))), parameters('mode'), null())]", + "type": "[if(not(empty(parameters('type'))), parameters('type'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the NAT rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the NAT rule." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworkGateways/natRules', parameters('virtualNetworkGatewayName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the NAT rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/dependencies.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/dependencies.bicep new file mode 100644 index 000000000..c3aebf111 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/main.test.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/main.test.bicep new file mode 100644 index 000000000..6270baf59 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/main.test.bicep @@ -0,0 +1,83 @@ +targetScope = 'subscription' + +metadata name = 'VPN Active Active with BGP settings' +metadata description = 'This instance deploys the module with the VPN Active Active with BGP settings.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgaab' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode: 'activeActiveBgp' + } + + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/dependencies.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/dependencies.bicep new file mode 100644 index 000000000..c3aebf111 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/main.test.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/main.test.bicep new file mode 100644 index 000000000..16fe84418 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/main.test.bicep @@ -0,0 +1,85 @@ +targetScope = 'subscription' + +metadata name = 'VPN Active Active with BGP settings' +metadata description = 'This instance deploys the module with the VPN Active Active with APIPA BGP settings.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgaaa' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: ['169.254.21.4','169.254.21.5'] + secondCustomBgpIpAddresses: ['169.254.22.4','169.254.22.5'] + } + + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/dependencies.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/dependencies.bicep new file mode 100644 index 000000000..8c33f3008 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/dependencies.bicep @@ -0,0 +1,96 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Local Network Gateway to create.') +param localNetworkGatewayName string + +@description('Required. The name of the Public IP to create.') +param existingFirstPipName string + +@description('Required. The name of the secondary Public IP to create in the active-active configuration.') +param existingSecondPipName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +resource existingFirstPip 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: existingFirstPipName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +resource existingSecondPip 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: existingSecondPipName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id + +@description('The resource ID of the existing Public IP.') +output existingFirstPipResourceId string = existingFirstPip.id + +@description('The resource ID of the existing secondary Public IP.') +output existingSecondPipResourceId string = existingSecondPip.id diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/main.test.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/main.test.bicep new file mode 100644 index 000000000..5a0f74ba0 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveExistingPip/main.test.bicep @@ -0,0 +1,88 @@ +targetScope = 'subscription' + +metadata name = 'VPN Active Active without BGP settings using two existent Public IPs' +metadata description = 'This instance deploys the module with the VPN Active Active without BGP settings.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgaaep' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + existingFirstPipName: 'dep-${namePrefix}-pip-${serviceShort}-existing1' + existingSecondPipName: 'dep-${namePrefix}-pip-${serviceShort}-existing2' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + existingFirstPipResourceId: nestedDependencies.outputs.existingFirstPipResourceId + + clusterSettings: { + clusterMode: 'activeActiveNoBgp' + existingSecondPipResourceId: nestedDependencies.outputs.existingSecondPipResourceId + } + + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/dependencies.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/dependencies.bicep new file mode 100644 index 000000000..c3aebf111 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/main.test.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/main.test.bicep new file mode 100644 index 000000000..7d799c5c2 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/main.test.bicep @@ -0,0 +1,83 @@ +targetScope = 'subscription' + +metadata name = 'VPN Active Active without BGP settings' +metadata description = 'This instance deploys the module with the VPN Active Active without BGP settings.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgaa' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode: 'activeActiveNoBgp' + } + + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/dependencies.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/dependencies.bicep new file mode 100644 index 000000000..c3aebf111 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/main.test.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/main.test.bicep new file mode 100644 index 000000000..1aa9da7c3 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/main.test.bicep @@ -0,0 +1,85 @@ +targetScope = 'subscription' + +metadata name = 'VPN Active Passive with BGP settings' +metadata description = 'This instance deploys the module with the VPN Active Passive with APIPA BGP settings.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgapb' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode:'activePassiveBgp' + customBgpIpAddresses: ['169.254.21.4','169.254.21.5'] + asn: 65815 + } + + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/dependencies.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/dependencies.bicep new file mode 100644 index 000000000..61e10ff9d --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/dependencies.bicep @@ -0,0 +1,74 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Local Network Gateway to create.') +param localNetworkGatewayName string + +@description('Required. The name of the Public IP to create.') +param existingFirstPipName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + + +resource existingFirstPip 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: existingFirstPipName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id + +@description('The resource ID of the existing Public IP.') +output existingFirstPipResourceId string = existingFirstPip.id + diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/main.test.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/main.test.bicep new file mode 100644 index 000000000..27c179eef --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveExistingPip/main.test.bicep @@ -0,0 +1,87 @@ +targetScope = 'subscription' + +metadata name = 'VPN Active Passive with BGP settings using existing Public IP' +metadata description = 'This instance deploys the module with the VPN Active Passive with APIPA BGP settings and existing primary public IP.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgapep' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + existingFirstPipName: 'dep-${namePrefix}-pip-${serviceShort}-existing1' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + existingFirstPipResourceId: nestedDependencies.outputs.existingFirstPipResourceId + clusterSettings: { + clusterMode:'activePassiveBgp' + customBgpIpAddresses: ['169.254.21.4','169.254.21.5'] + asn: 65815 + } + + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/dependencies.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/dependencies.bicep new file mode 100644 index 000000000..c3aebf111 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/main.test.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/main.test.bicep new file mode 100644 index 000000000..ee3904f4b --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/main.test.bicep @@ -0,0 +1,83 @@ +targetScope = 'subscription' + +metadata name = 'VPN Active Passive without BGP settings' +metadata description = 'This instance deploys the module with the VPN Active Passive without BGP settings.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgap' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode:'activePassiveNoBgp' + } + + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..c3aebf111 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..06f382ecb --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,73 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + publicIpZones: [ + 1 + 2 + 3 + ] + clusterSettings: { + clusterMode:'activeActiveNoBgp' + } + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/expressRoute/dependencies.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/expressRoute/dependencies.bicep new file mode 100644 index 000000000..223faddfb --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/expressRoute/dependencies.bicep @@ -0,0 +1,30 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep new file mode 100644 index 000000000..1e1790c92 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep @@ -0,0 +1,75 @@ +targetScope = 'subscription' + +metadata name = 'ExpressRoute' +metadata description = 'This instance deploys the module with the ExpressRoute set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvger' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + skuName: 'ErGw1AZ' + gatewayType: 'ExpressRoute' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings:{ + clusterMode: 'activePassiveBgp' + } + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + firstPipName: '${namePrefix}-pip-${serviceShort}' + publicIpZones: [ + 1 + 2 + 3 + ] + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..ab4fdf887 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/max/dependencies.bicep @@ -0,0 +1,60 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..8ea291f85 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep @@ -0,0 +1,180 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode: 'activeActiveBgp' + secondPipName: '${namePrefix}${serviceShort}001-pip2' + customBgpIpAddresses: ['169.254.21.4', '169.254.21.5'] + secondCustomBgpIpAddresses: ['169.254.22.4', '169.254.22.5'] + } + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + publicIpZones: [ + 1 + 2 + 3 + ] + roleAssignments: [ + { + name: 'db30550e-70b7-4dbe-901e-e9363b69c05f' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + vpnType: 'RouteBased' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + natRules: [ + { + name: 'nat-rule-1-static-IngressSnat' + type: 'Static' + mode: 'IngressSnat' + internalMappings: [ + { + addressSpace: '10.100.0.0/24' + portRange: '100' + } + ] + externalMappings: [ + { + addressSpace: '192.168.0.0/24' + portRange: '100' + } + ] + } + { + name: 'nat-rule-2-dynamic-EgressSnat' + type: 'Static' + mode: 'EgressSnat' + internalMappings: [ + { + addressSpace: '172.16.0.0/26' + } + ] + externalMappings: [ + { + addressSpace: '10.200.0.0/26' + } + ] + } + ] + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/dependencies.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/dependencies.bicep new file mode 100644 index 000000000..c3aebf111 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep new file mode 100644 index 000000000..fc3410af5 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep @@ -0,0 +1,69 @@ +targetScope = 'subscription' + +metadata name = 'Using SKU without Availability Zones' +metadata description = 'This instance deploys the module with a SKU that does not support Availability Zones.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgnaz' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + skuName: 'VpnGw1' + gatewayType: 'Vpn' + publicIpZones: [] + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode: 'activePassiveNoBgp' + } + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn/dependencies.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn/dependencies.bicep new file mode 100644 index 000000000..c3aebf111 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn/main.test.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn/main.test.bicep new file mode 100644 index 000000000..4258c36c8 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/vpn/main.test.bicep @@ -0,0 +1,82 @@ +targetScope = 'subscription' + +metadata name = 'VPN' +metadata description = 'This instance deploys the module with the VPN set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgvpn' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings:{ + clusterMode: 'activeActiveNoBgp' + } + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..c3aebf111 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..7b3e65186 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,156 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgmwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: ['169.254.21.4', '169.254.21.5'] + secondCustomBgpIpAddresses: ['169.254.22.4', '169.254.22.5'] + asn: 65515 + } + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + natRules: [ + { + name: 'nat-rule-1-static-IngressSnat' + type: 'Static' + mode: 'IngressSnat' + internalMappings: [ + { + addressSpace: '10.100.0.0/24' + portRange: '100' + } + ] + externalMappings: [ + { + addressSpace: '192.168.0.0/24' + portRange: '100' + } + ] + } + { + name: 'nat-rule-2-dynamic-EgressSnat' + type: 'Static' + mode: 'EgressSnat' + internalMappings: [ + { + addressSpace: '172.16.0.0/26' + } + ] + externalMappings: [ + { + addressSpace: '10.200.0.0/26' + } + ] + } + ] + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/1.1.0/res/network/virtual-network-gateway/version.json b/avm/1.1.0/res/network/virtual-network-gateway/version.json new file mode 100644 index 000000000..ea4f3b6e6 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network-gateway/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-network/ORPHANED.md b/avm/1.1.0/res/network/virtual-network/ORPHANED.md new file mode 100644 index 000000000..ef8fa911d --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/ORPHANED.md @@ -0,0 +1,4 @@ +⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ + +- Only security and bug fixes are being handled by the AVM core team at present. +- If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-network/README.md b/avm/1.1.0/res/network/virtual-network/README.md new file mode 100644 index 000000000..c00fb5013 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/README.md @@ -0,0 +1,2015 @@ +# Virtual Networks `[Microsoft.Network/virtualNetworks]` + +> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ +> +> - Only security and bug fixes are being handled by the AVM core team at present. +> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! + +This module deploys a Virtual Network (vNet). + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/virtualNetworks` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-01-01/virtualNetworks) | +| `Microsoft.Network/virtualNetworks/subnets` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-01-01/virtualNetworks/subnets) | +| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-01-01/virtualNetworks/virtualNetworkPeerings) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/virtual-network:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using an IPv6 address space](#example-2-using-an-ipv6-address-space) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [Deploying a bi-directional peering](#example-4-deploying-a-bi-directional-peering) +- [WAF-aligned](#example-5-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module virtualNetwork 'br/public:avm/res/network/virtual-network:' = { + name: 'virtualNetworkDeployment' + params: { + // Required parameters + addressPrefixes: [ + '10.0.0.0/16' + ] + name: 'nvnmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "addressPrefixes": { + "value": [ + "10.0.0.0/16" + ] + }, + "name": { + "value": "nvnmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network:' + +// Required parameters +param addressPrefixes = [ + '10.0.0.0/16' +] +param name = 'nvnmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using an IPv6 address space_ + +This instance deploys the module using an IPv6 address space. + + +

+ +via Bicep module + +```bicep +module virtualNetwork 'br/public:avm/res/network/virtual-network:' = { + name: 'virtualNetworkDeployment' + params: { + // Required parameters + addressPrefixes: [ + '10.0.0.0/21' + 'fd00:592b:3014::/64' + ] + name: 'nvnipv6001' + // Non-required parameters + location: '' + subnets: [ + { + addressPrefixes: [ + '10.0.0.0/24' + 'fd00:592b:3014::/64' + ] + name: 'ipv6-subnet' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "addressPrefixes": { + "value": [ + "10.0.0.0/21", + "fd00:592b:3014::/64" + ] + }, + "name": { + "value": "nvnipv6001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "subnets": { + "value": [ + { + "addressPrefixes": [ + "10.0.0.0/24", + "fd00:592b:3014::/64" + ], + "name": "ipv6-subnet" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network:' + +// Required parameters +param addressPrefixes = [ + '10.0.0.0/21' + 'fd00:592b:3014::/64' +] +param name = 'nvnipv6001' +// Non-required parameters +param location = '' +param subnets = [ + { + addressPrefixes: [ + '10.0.0.0/24' + 'fd00:592b:3014::/64' + ] + name: 'ipv6-subnet' + } +] +``` + +
+

+ +### Example 3: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module virtualNetwork 'br/public:avm/res/network/virtual-network:' = { + name: 'virtualNetworkDeployment' + params: { + // Required parameters + addressPrefixes: [ + '' + ] + name: 'nvnmax001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.4' + '10.0.1.5' + ] + flowTimeoutInMinutes: 20 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'f5c27a7b-9b18-4dc1-b002-db3c38e80b64' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'az-subnet-x-001' + networkSecurityGroupResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + routeTableResourceId: '' + serviceEndpoints: [ + 'Microsoft.Sql' + 'Microsoft.Storage' + ] + } + { + addressPrefix: '' + delegation: 'Microsoft.Netapp/volumes' + name: 'az-subnet-x-002' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'az-subnet-x-003' + networkSecurityGroupResourceId: '' + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + addressPrefix: '' + name: 'az-subnet-x-004' + natGatewayResourceId: '' + networkSecurityGroupResourceId: '' + routeTableResourceId: '' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "addressPrefixes": { + "value": [ + "" + ] + }, + "name": { + "value": "nvnmax001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "dnsServers": { + "value": [ + "10.0.1.4", + "10.0.1.5" + ] + }, + "flowTimeoutInMinutes": { + "value": 20 + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "f5c27a7b-9b18-4dc1-b002-db3c38e80b64", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "subnets": { + "value": [ + { + "addressPrefix": "", + "name": "GatewaySubnet" + }, + { + "addressPrefix": "", + "name": "az-subnet-x-001", + "networkSecurityGroupResourceId": "", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "routeTableResourceId": "", + "serviceEndpoints": [ + "Microsoft.Sql", + "Microsoft.Storage" + ] + }, + { + "addressPrefix": "", + "delegation": "Microsoft.Netapp/volumes", + "name": "az-subnet-x-002", + "networkSecurityGroupResourceId": "" + }, + { + "addressPrefix": "", + "name": "az-subnet-x-003", + "networkSecurityGroupResourceId": "", + "privateEndpointNetworkPolicies": "Disabled", + "privateLinkServiceNetworkPolicies": "Enabled" + }, + { + "addressPrefix": "", + "name": "az-subnet-x-004", + "natGatewayResourceId": "", + "networkSecurityGroupResourceId": "", + "routeTableResourceId": "" + }, + { + "addressPrefix": "", + "name": "AzureBastionSubnet", + "networkSecurityGroupResourceId": "" + }, + { + "addressPrefix": "", + "name": "AzureFirewallSubnet" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network:' + +// Required parameters +param addressPrefixes = [ + '' +] +param name = 'nvnmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param dnsServers = [ + '10.0.1.4' + '10.0.1.5' +] +param flowTimeoutInMinutes = 20 +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'f5c27a7b-9b18-4dc1-b002-db3c38e80b64' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param subnets = [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'az-subnet-x-001' + networkSecurityGroupResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + routeTableResourceId: '' + serviceEndpoints: [ + 'Microsoft.Sql' + 'Microsoft.Storage' + ] + } + { + addressPrefix: '' + delegation: 'Microsoft.Netapp/volumes' + name: 'az-subnet-x-002' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'az-subnet-x-003' + networkSecurityGroupResourceId: '' + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + addressPrefix: '' + name: 'az-subnet-x-004' + natGatewayResourceId: '' + networkSecurityGroupResourceId: '' + routeTableResourceId: '' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 4: _Deploying a bi-directional peering_ + +This instance deploys the module with both an inbound and outbound peering. + + +

+ +via Bicep module + +```bicep +module virtualNetwork 'br/public:avm/res/network/virtual-network:' = { + name: 'virtualNetworkDeployment' + params: { + // Required parameters + addressPrefixes: [ + '10.1.0.0/24' + ] + name: 'nvnpeer001' + // Non-required parameters + location: '' + peerings: [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + remotePeeringAllowForwardedTraffic: true + remotePeeringAllowVirtualNetworkAccess: true + remotePeeringEnabled: true + remotePeeringName: 'customName' + remoteVirtualNetworkResourceId: '' + useRemoteGateways: false + } + ] + subnets: [ + { + addressPrefix: '10.1.0.0/26' + name: 'GatewaySubnet' + } + { + addressPrefix: '10.1.0.64/26' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '10.1.0.128/26' + name: 'AzureFirewallSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "addressPrefixes": { + "value": [ + "10.1.0.0/24" + ] + }, + "name": { + "value": "nvnpeer001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "peerings": { + "value": [ + { + "allowForwardedTraffic": true, + "allowGatewayTransit": false, + "allowVirtualNetworkAccess": true, + "remotePeeringAllowForwardedTraffic": true, + "remotePeeringAllowVirtualNetworkAccess": true, + "remotePeeringEnabled": true, + "remotePeeringName": "customName", + "remoteVirtualNetworkResourceId": "", + "useRemoteGateways": false + } + ] + }, + "subnets": { + "value": [ + { + "addressPrefix": "10.1.0.0/26", + "name": "GatewaySubnet" + }, + { + "addressPrefix": "10.1.0.64/26", + "name": "AzureBastionSubnet", + "networkSecurityGroupResourceId": "" + }, + { + "addressPrefix": "10.1.0.128/26", + "name": "AzureFirewallSubnet" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network:' + +// Required parameters +param addressPrefixes = [ + '10.1.0.0/24' +] +param name = 'nvnpeer001' +// Non-required parameters +param location = '' +param peerings = [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + remotePeeringAllowForwardedTraffic: true + remotePeeringAllowVirtualNetworkAccess: true + remotePeeringEnabled: true + remotePeeringName: 'customName' + remoteVirtualNetworkResourceId: '' + useRemoteGateways: false + } +] +param subnets = [ + { + addressPrefix: '10.1.0.0/26' + name: 'GatewaySubnet' + } + { + addressPrefix: '10.1.0.64/26' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '10.1.0.128/26' + name: 'AzureFirewallSubnet' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 5: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module virtualNetwork 'br/public:avm/res/network/virtual-network:' = { + name: 'virtualNetworkDeployment' + params: { + // Required parameters + addressPrefixes: [ + '' + ] + name: 'nvnwaf001' + // Non-required parameters + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.4' + '10.0.1.5' + ] + flowTimeoutInMinutes: 20 + location: '' + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'az-subnet-x-001' + networkSecurityGroupResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + routeTableResourceId: '' + serviceEndpoints: [ + 'Microsoft.Sql' + 'Microsoft.Storage' + ] + } + { + addressPrefix: '' + delegation: 'Microsoft.Netapp/volumes' + name: 'az-subnet-x-002' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'az-subnet-x-003' + networkSecurityGroupResourceId: '' + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "addressPrefixes": { + "value": [ + "" + ] + }, + "name": { + "value": "nvnwaf001" + }, + // Non-required parameters + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "dnsServers": { + "value": [ + "10.0.1.4", + "10.0.1.5" + ] + }, + "flowTimeoutInMinutes": { + "value": 20 + }, + "location": { + "value": "" + }, + "subnets": { + "value": [ + { + "addressPrefix": "", + "name": "GatewaySubnet" + }, + { + "addressPrefix": "", + "name": "az-subnet-x-001", + "networkSecurityGroupResourceId": "", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Reader" + } + ], + "routeTableResourceId": "", + "serviceEndpoints": [ + "Microsoft.Sql", + "Microsoft.Storage" + ] + }, + { + "addressPrefix": "", + "delegation": "Microsoft.Netapp/volumes", + "name": "az-subnet-x-002", + "networkSecurityGroupResourceId": "" + }, + { + "addressPrefix": "", + "name": "az-subnet-x-003", + "networkSecurityGroupResourceId": "", + "privateEndpointNetworkPolicies": "Disabled", + "privateLinkServiceNetworkPolicies": "Enabled" + }, + { + "addressPrefix": "", + "name": "AzureBastionSubnet", + "networkSecurityGroupResourceId": "" + }, + { + "addressPrefix": "", + "name": "AzureFirewallSubnet" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network:' + +// Required parameters +param addressPrefixes = [ + '' +] +param name = 'nvnwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param dnsServers = [ + '10.0.1.4' + '10.0.1.5' +] +param flowTimeoutInMinutes = 20 +param location = '' +param subnets = [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'az-subnet-x-001' + networkSecurityGroupResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + routeTableResourceId: '' + serviceEndpoints: [ + 'Microsoft.Sql' + 'Microsoft.Storage' + ] + } + { + addressPrefix: '' + delegation: 'Microsoft.Netapp/volumes' + name: 'az-subnet-x-002' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'az-subnet-x-003' + networkSecurityGroupResourceId: '' + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefixes`](#parameter-addressprefixes) | array | An Array of 1 or more IP Address Prefixes for the Virtual Network. | +| [`name`](#parameter-name) | string | The name of the Virtual Network (vNet). | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ddosProtectionPlanResourceId`](#parameter-ddosprotectionplanresourceid) | string | Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`dnsServers`](#parameter-dnsservers) | array | DNS Servers associated to the Virtual Network. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`enableVmProtection`](#parameter-enablevmprotection) | bool | Indicates if VM protection is enabled for all the subnets in the virtual network. | +| [`flowTimeoutInMinutes`](#parameter-flowtimeoutinminutes) | int | The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`peerings`](#parameter-peerings) | array | Virtual Network Peering configurations. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`subnets`](#parameter-subnets) | array | An Array of subnets to deploy to the Virtual Network. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`virtualNetworkBgpCommunity`](#parameter-virtualnetworkbgpcommunity) | string | The BGP community associated with the virtual network. | +| [`vnetEncryption`](#parameter-vnetencryption) | bool | Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property. | +| [`vnetEncryptionEnforcement`](#parameter-vnetencryptionenforcement) | string | If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled. | + +### Parameter: `addressPrefixes` + +An Array of 1 or more IP Address Prefixes for the Virtual Network. + +- Required: Yes +- Type: array + +### Parameter: `name` + +The name of the Virtual Network (vNet). + +- Required: Yes +- Type: string + +### Parameter: `ddosProtectionPlanResourceId` + +Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of the diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of the diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `dnsServers` + +DNS Servers associated to the Virtual Network. + +- Required: No +- Type: array + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableVmProtection` + +Indicates if VM protection is enabled for all the subnets in the virtual network. + +- Required: No +- Type: bool + +### Parameter: `flowTimeoutInMinutes` + +The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null. + +- Required: No +- Type: int +- Default: `0` +- MaxValue: 30 + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` +- MaxValue: 30 + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object +- MaxValue: 30 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` +- MaxValue: 30 + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `peerings` + +Virtual Network Peering configurations. + +- Required: No +- Type: array +- MaxValue: 30 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`remoteVirtualNetworkResourceId`](#parameter-peeringsremotevirtualnetworkresourceid) | string | The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowForwardedTraffic`](#parameter-peeringsallowforwardedtraffic) | bool | Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true. | +| [`allowGatewayTransit`](#parameter-peeringsallowgatewaytransit) | bool | If gateway links can be used in remote virtual networking to link to this virtual network. Default is false. | +| [`allowVirtualNetworkAccess`](#parameter-peeringsallowvirtualnetworkaccess) | bool | Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true. | +| [`doNotVerifyRemoteGateways`](#parameter-peeringsdonotverifyremotegateways) | bool | Do not verify the provisioning state of the remote gateway. Default is true. | +| [`name`](#parameter-peeringsname) | string | The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName. | +| [`remotePeeringAllowForwardedTraffic`](#parameter-peeringsremotepeeringallowforwardedtraffic) | bool | Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true. | +| [`remotePeeringAllowGatewayTransit`](#parameter-peeringsremotepeeringallowgatewaytransit) | bool | If gateway links can be used in remote virtual networking to link to this virtual network. Default is false. | +| [`remotePeeringAllowVirtualNetworkAccess`](#parameter-peeringsremotepeeringallowvirtualnetworkaccess) | bool | Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true. | +| [`remotePeeringDoNotVerifyRemoteGateways`](#parameter-peeringsremotepeeringdonotverifyremotegateways) | bool | Do not verify the provisioning state of the remote gateway. Default is true. | +| [`remotePeeringEnabled`](#parameter-peeringsremotepeeringenabled) | bool | Deploy the outbound and the inbound peering. | +| [`remotePeeringName`](#parameter-peeringsremotepeeringname) | string | The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName. | +| [`remotePeeringUseRemoteGateways`](#parameter-peeringsremotepeeringuseremotegateways) | bool | If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false. | +| [`useRemoteGateways`](#parameter-peeringsuseremotegateways) | bool | If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false. | + +### Parameter: `peerings.remoteVirtualNetworkResourceId` + +The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID. + +- Required: Yes +- Type: string +- MaxValue: 30 + +### Parameter: `peerings.allowForwardedTraffic` + +Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true. + +- Required: No +- Type: bool +- MaxValue: 30 + +### Parameter: `peerings.allowGatewayTransit` + +If gateway links can be used in remote virtual networking to link to this virtual network. Default is false. + +- Required: No +- Type: bool +- MaxValue: 30 + +### Parameter: `peerings.allowVirtualNetworkAccess` + +Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true. + +- Required: No +- Type: bool +- MaxValue: 30 + +### Parameter: `peerings.doNotVerifyRemoteGateways` + +Do not verify the provisioning state of the remote gateway. Default is true. + +- Required: No +- Type: bool +- MaxValue: 30 + +### Parameter: `peerings.name` + +The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `peerings.remotePeeringAllowForwardedTraffic` + +Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true. + +- Required: No +- Type: bool +- MaxValue: 30 + +### Parameter: `peerings.remotePeeringAllowGatewayTransit` + +If gateway links can be used in remote virtual networking to link to this virtual network. Default is false. + +- Required: No +- Type: bool +- MaxValue: 30 + +### Parameter: `peerings.remotePeeringAllowVirtualNetworkAccess` + +Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true. + +- Required: No +- Type: bool +- MaxValue: 30 + +### Parameter: `peerings.remotePeeringDoNotVerifyRemoteGateways` + +Do not verify the provisioning state of the remote gateway. Default is true. + +- Required: No +- Type: bool +- MaxValue: 30 + +### Parameter: `peerings.remotePeeringEnabled` + +Deploy the outbound and the inbound peering. + +- Required: No +- Type: bool +- MaxValue: 30 + +### Parameter: `peerings.remotePeeringName` + +The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `peerings.remotePeeringUseRemoteGateways` + +If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false. + +- Required: No +- Type: bool +- MaxValue: 30 + +### Parameter: `peerings.useRemoteGateways` + +If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false. + +- Required: No +- Type: bool +- MaxValue: 30 + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- MaxValue: 30 +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string +- MaxValue: 30 + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string +- MaxValue: 30 + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` +- MaxValue: 30 + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` +- MaxValue: 30 + +### Parameter: `subnets` + +An Array of subnets to deploy to the Virtual Network. + +- Required: No +- Type: array +- MaxValue: 30 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-subnetsname) | string | The Name of the subnet resource. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefix`](#parameter-subnetsaddressprefix) | string | The address prefix for the subnet. Required if `addressPrefixes` is empty. | +| [`addressPrefixes`](#parameter-subnetsaddressprefixes) | array | List of address prefixes for the subnet. Required if `addressPrefix` is empty. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationGatewayIPConfigurations`](#parameter-subnetsapplicationgatewayipconfigurations) | array | Application gateway IP configurations of virtual network resource. | +| [`defaultOutboundAccess`](#parameter-subnetsdefaultoutboundaccess) | bool | Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet. | +| [`delegation`](#parameter-subnetsdelegation) | string | The delegation to enable on the subnet. | +| [`natGatewayResourceId`](#parameter-subnetsnatgatewayresourceid) | string | The resource ID of the NAT Gateway to use for the subnet. | +| [`networkSecurityGroupResourceId`](#parameter-subnetsnetworksecuritygroupresourceid) | string | The resource ID of the network security group to assign to the subnet. | +| [`privateEndpointNetworkPolicies`](#parameter-subnetsprivateendpointnetworkpolicies) | string | enable or disable apply network policies on private endpoint in the subnet. | +| [`privateLinkServiceNetworkPolicies`](#parameter-subnetsprivatelinkservicenetworkpolicies) | string | enable or disable apply network policies on private link service in the subnet. | +| [`roleAssignments`](#parameter-subnetsroleassignments) | array | Array of role assignments to create. | +| [`routeTableResourceId`](#parameter-subnetsroutetableresourceid) | string | The resource ID of the route table to assign to the subnet. | +| [`serviceEndpointPolicies`](#parameter-subnetsserviceendpointpolicies) | array | An array of service endpoint policies. | +| [`serviceEndpoints`](#parameter-subnetsserviceendpoints) | array | The service endpoints to enable on the subnet. | +| [`sharingScope`](#parameter-subnetssharingscope) | string | Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty. | + +### Parameter: `subnets.name` + +The Name of the subnet resource. + +- Required: Yes +- Type: string +- MaxValue: 30 + +### Parameter: `subnets.addressPrefix` + +The address prefix for the subnet. Required if `addressPrefixes` is empty. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `subnets.addressPrefixes` + +List of address prefixes for the subnet. Required if `addressPrefix` is empty. + +- Required: No +- Type: array +- MaxValue: 30 + +### Parameter: `subnets.applicationGatewayIPConfigurations` + +Application gateway IP configurations of virtual network resource. + +- Required: No +- Type: array +- MaxValue: 30 + +### Parameter: `subnets.defaultOutboundAccess` + +Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet. + +- Required: No +- Type: bool +- MaxValue: 30 + +### Parameter: `subnets.delegation` + +The delegation to enable on the subnet. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `subnets.natGatewayResourceId` + +The resource ID of the NAT Gateway to use for the subnet. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `subnets.networkSecurityGroupResourceId` + +The resource ID of the network security group to assign to the subnet. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `subnets.privateEndpointNetworkPolicies` + +enable or disable apply network policies on private endpoint in the subnet. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + 'NetworkSecurityGroupEnabled' + 'RouteTableEnabled' + ] + ``` +- MaxValue: 30 + +### Parameter: `subnets.privateLinkServiceNetworkPolicies` + +enable or disable apply network policies on private link service in the subnet. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` +- MaxValue: 30 + +### Parameter: `subnets.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- MaxValue: 30 +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-subnetsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-subnetsroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-subnetsroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-subnetsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-subnetsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-subnetsroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-subnetsroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-subnetsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `subnets.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string +- MaxValue: 30 + +### Parameter: `subnets.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string +- MaxValue: 30 + +### Parameter: `subnets.roleAssignments.condition` + +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". + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `subnets.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` +- MaxValue: 30 + +### Parameter: `subnets.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `subnets.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `subnets.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `subnets.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` +- MaxValue: 30 + +### Parameter: `subnets.routeTableResourceId` + +The resource ID of the route table to assign to the subnet. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `subnets.serviceEndpointPolicies` + +An array of service endpoint policies. + +- Required: No +- Type: array +- MaxValue: 30 + +### Parameter: `subnets.serviceEndpoints` + +The service endpoints to enable on the subnet. + +- Required: No +- Type: array +- MaxValue: 30 + +### Parameter: `subnets.sharingScope` + +Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'DelegatedServices' + 'Tenant' + ] + ``` +- MaxValue: 30 + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- MaxValue: 30 + +### Parameter: `virtualNetworkBgpCommunity` + +The BGP community associated with the virtual network. + +- Required: No +- Type: string +- MaxValue: 30 + +### Parameter: `vnetEncryption` + +Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property. + +- Required: No +- Type: bool +- Default: `False` +- MaxValue: 30 + +### Parameter: `vnetEncryptionEnforcement` + +If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled. + +- Required: No +- Type: string +- Default: `'AllowUnencrypted'` +- Allowed: + ```Bicep + [ + 'AllowUnencrypted' + 'DropUnencrypted' + ] + ``` +- MaxValue: 30 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the virtual network. | +| `resourceGroupName` | string | The resource group the virtual network was deployed into. | +| `resourceId` | string | The resource ID of the virtual network. | +| `subnetNames` | array | The names of the deployed subnets. | +| `subnetResourceIds` | array | The resource IDs of the deployed subnets. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.2.1` | Remote reference | + +## Notes + +### Considerations + +The network security group and route table resources must reside in the same resource group as the virtual network. + +### Parameter Usage: `peerings` + +As the virtual network peering array allows you to deploy not only a one-way but also two-way peering (i.e reverse), you can use the following ***additional*** properties on top of what is documented in _[virtualNetworkPeering](virtual-network-peering/README.md)_. + +| Parameter Name | Type | Default Value | Possible Values | Description | +| :-- | :-- | :-- | :-- | :-- | +| `remotePeeringEnabled` | bool | `false` | | Optional. Set to true to also deploy the reverse peering for the configured remote virtual networks to the local network | +| `remotePeeringName` | string | `'${last(split(peering.remoteVirtualNetworkId, '/'))}-${name}'` | | Optional. The Name of VNET Peering resource. If not provided, default value will be - | +| `remotePeeringAllowForwardedTraffic` | bool | `true` | | Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. | +| `remotePeeringAllowGatewayTransit` | bool | `false` | | Optional. If gateway links can be used in remote virtual networking to link to this virtual network. | +| `remotePeeringAllowVirtualNetworkAccess` | bool | `true` | | Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. | +| `remotePeeringDoNotVerifyRemoteGateways` | bool | `true` | | Optional. If we need to verify the provisioning state of the remote gateway. | +| `remotePeeringUseRemoteGateways` | bool | `false` | | Optional. If remote gateways can be used on this virtual network. If the flag is set to `true`, and allowGatewayTransit on local peering is also `true`, virtual network will use gateways of local virtual network for transit. Only one peering can have this flag set to `true`. This flag cannot be set if virtual network already has a gateway. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/virtual-network/main.bicep b/avm/1.1.0/res/network/virtual-network/main.bicep new file mode 100644 index 000000000..6701e1014 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/main.bicep @@ -0,0 +1,392 @@ +metadata name = 'Virtual Networks' +metadata description = 'This module deploys a Virtual Network (vNet).' + +@description('Required. The name of the Virtual Network (vNet).') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Required. An Array of 1 or more IP Address Prefixes for the Virtual Network.') +param addressPrefixes array + +@description('Optional. The BGP community associated with the virtual network.') +param virtualNetworkBgpCommunity string? + +@description('Optional. An Array of subnets to deploy to the Virtual Network.') +param subnets subnetType[]? + +@description('Optional. DNS Servers associated to the Virtual Network.') +param dnsServers string[]? + +@description('Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it\'s left blank, DDoS protection will not be configured. If it\'s provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription.') +param ddosProtectionPlanResourceId string? + +@description('Optional. Virtual Network Peering configurations.') +param peerings peeringType[]? + +@description('Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property.') +param vnetEncryption bool = false + +@allowed([ + 'AllowUnencrypted' + 'DropUnencrypted' +]) +@description('Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled.') +param vnetEncryptionEnforcement string = 'AllowUnencrypted' + +@maxValue(30) +@description('Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null.') +param flowTimeoutInMinutes int = 0 + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Indicates if VM protection is enabled for all the subnets in the virtual network.') +param enableVmProtection bool? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +// ============ // +// Dependencies // +// ============ // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-virtualnetwork.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-01-01' = { + name: name + location: location + tags: tags + properties: { + addressSpace: { + addressPrefixes: addressPrefixes + } + bgpCommunities: !empty(virtualNetworkBgpCommunity) + ? { + virtualNetworkCommunity: virtualNetworkBgpCommunity! + } + : null + ddosProtectionPlan: !empty(ddosProtectionPlanResourceId) + ? { + id: ddosProtectionPlanResourceId + } + : null + dhcpOptions: !empty(dnsServers) + ? { + dnsServers: array(dnsServers) + } + : null + enableDdosProtection: !empty(ddosProtectionPlanResourceId) + encryption: vnetEncryption == true + ? { + enabled: vnetEncryption + enforcement: vnetEncryptionEnforcement + } + : null + flowTimeoutInMinutes: flowTimeoutInMinutes != 0 ? flowTimeoutInMinutes : null + enableVmProtection: enableVmProtection + } +} + +@batchSize(1) +module virtualNetwork_subnets 'subnet/main.bicep' = [ + for (subnet, index) in (subnets ?? []): { + name: '${uniqueString(deployment().name, location)}-subnet-${index}' + params: { + virtualNetworkName: virtualNetwork.name + name: subnet.name + addressPrefix: subnet.?addressPrefix + addressPrefixes: subnet.?addressPrefixes + applicationGatewayIPConfigurations: subnet.?applicationGatewayIPConfigurations + delegation: subnet.?delegation + natGatewayResourceId: subnet.?natGatewayResourceId + networkSecurityGroupResourceId: subnet.?networkSecurityGroupResourceId + privateEndpointNetworkPolicies: subnet.?privateEndpointNetworkPolicies + privateLinkServiceNetworkPolicies: subnet.?privateLinkServiceNetworkPolicies + roleAssignments: subnet.?roleAssignments + routeTableResourceId: subnet.?routeTableResourceId + serviceEndpointPolicies: subnet.?serviceEndpointPolicies + serviceEndpoints: subnet.?serviceEndpoints + defaultOutboundAccess: subnet.?defaultOutboundAccess + sharingScope: subnet.?sharingScope + } + } +] + +// Local to Remote peering +module virtualNetwork_peering_local 'virtual-network-peering/main.bicep' = [ + for (peering, index) in (peerings ?? []): { + name: '${uniqueString(deployment().name, location)}-virtualNetworkPeering-local-${index}' + // This is a workaround for an error in which the peering is deployed whilst the subnet creation is still taking place + // TODO: https://github.com/Azure/bicep/issues/1013 would be a better solution + dependsOn: [ + virtualNetwork_subnets + ] + params: { + localVnetName: virtualNetwork.name + remoteVirtualNetworkResourceId: peering.remoteVirtualNetworkResourceId + name: peering.?name + allowForwardedTraffic: peering.?allowForwardedTraffic + allowGatewayTransit: peering.?allowGatewayTransit + allowVirtualNetworkAccess: peering.?allowVirtualNetworkAccess + doNotVerifyRemoteGateways: peering.?doNotVerifyRemoteGateways + useRemoteGateways: peering.?useRemoteGateways + } + } +] + +// Remote to local peering (reverse) +module virtualNetwork_peering_remote 'virtual-network-peering/main.bicep' = [ + for (peering, index) in (peerings ?? []): if (peering.?remotePeeringEnabled ?? false) { + name: '${uniqueString(deployment().name, location)}-virtualNetworkPeering-remote-${index}' + // This is a workaround for an error in which the peering is deployed whilst the subnet creation is still taking place + // TODO: https://github.com/Azure/bicep/issues/1013 would be a better solution + dependsOn: [ + virtualNetwork_subnets + ] + scope: resourceGroup( + split(peering.remoteVirtualNetworkResourceId, '/')[2], + split(peering.remoteVirtualNetworkResourceId, '/')[4] + ) + params: { + localVnetName: last(split(peering.remoteVirtualNetworkResourceId, '/')) + remoteVirtualNetworkResourceId: virtualNetwork.id + name: peering.?remotePeeringName + allowForwardedTraffic: peering.?remotePeeringAllowForwardedTraffic + allowGatewayTransit: peering.?remotePeeringAllowGatewayTransit + allowVirtualNetworkAccess: peering.?remotePeeringAllowVirtualNetworkAccess + doNotVerifyRemoteGateways: peering.?remotePeeringDoNotVerifyRemoteGateways + useRemoteGateways: peering.?remotePeeringUseRemoteGateways + } + } +] + +resource virtualNetwork_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: virtualNetwork +} + +resource virtualNetwork_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: virtualNetwork + } +] + +resource virtualNetwork_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(virtualNetwork.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: virtualNetwork + } +] + +@description('The resource group the virtual network was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the virtual network.') +output resourceId string = virtualNetwork.id + +@description('The name of the virtual network.') +output name string = virtualNetwork.name + +@description('The names of the deployed subnets.') +output subnetNames array = [for (subnet, index) in (subnets ?? []): virtualNetwork_subnets[index].outputs.name] + +@description('The resource IDs of the deployed subnets.') +output subnetResourceIds array = [ + for (subnet, index) in (subnets ?? []): virtualNetwork_subnets[index].outputs.resourceId +] + +@description('The location the resource was deployed into.') +output location string = virtualNetwork.location + +// =============== // +// Definitions // +// =============== // + +type peeringType = { + @description('Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName.') + name: string? + + @description('Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID.') + remoteVirtualNetworkResourceId: string + + @description('Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true.') + allowForwardedTraffic: bool? + + @description('Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false.') + allowGatewayTransit: bool? + + @description('Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true.') + allowVirtualNetworkAccess: bool? + + @description('Optional. Do not verify the provisioning state of the remote gateway. Default is true.') + doNotVerifyRemoteGateways: bool? + + @description('Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false.') + useRemoteGateways: bool? + + @description('Optional. Deploy the outbound and the inbound peering.') + remotePeeringEnabled: bool? + + @description('Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName.') + remotePeeringName: string? + + @description('Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true.') + remotePeeringAllowForwardedTraffic: bool? + + @description('Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false.') + remotePeeringAllowGatewayTransit: bool? + + @description('Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true.') + remotePeeringAllowVirtualNetworkAccess: bool? + + @description('Optional. Do not verify the provisioning state of the remote gateway. Default is true.') + remotePeeringDoNotVerifyRemoteGateways: bool? + + @description('Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false.') + remotePeeringUseRemoteGateways: bool? +} + +type subnetType = { + @description('Required. The Name of the subnet resource.') + name: string + + @description('Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty.') + addressPrefix: string? + + @description('Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty.') + addressPrefixes: string[]? + + @description('Optional. Application gateway IP configurations of virtual network resource.') + applicationGatewayIPConfigurations: object[]? + + @description('Optional. The delegation to enable on the subnet.') + delegation: string? + + @description('Optional. The resource ID of the NAT Gateway to use for the subnet.') + natGatewayResourceId: string? + + @description('Optional. The resource ID of the network security group to assign to the subnet.') + networkSecurityGroupResourceId: string? + + @description('Optional. enable or disable apply network policies on private endpoint in the subnet.') + privateEndpointNetworkPolicies: ('Disabled' | 'Enabled' | 'NetworkSecurityGroupEnabled' | 'RouteTableEnabled')? + + @description('Optional. enable or disable apply network policies on private link service in the subnet.') + privateLinkServiceNetworkPolicies: ('Disabled' | 'Enabled')? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType[]? + + @description('Optional. The resource ID of the route table to assign to the subnet.') + routeTableResourceId: string? + + @description('Optional. An array of service endpoint policies.') + serviceEndpointPolicies: object[]? + + @description('Optional. The service endpoints to enable on the subnet.') + serviceEndpoints: string[]? + + @description('Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet.') + defaultOutboundAccess: bool? + + @description('Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty.') + sharingScope: ('DelegatedServices' | 'Tenant')? +} diff --git a/avm/1.1.0/res/network/virtual-network/main.json b/avm/1.1.0/res/network/virtual-network/main.json new file mode 100644 index 000000000..e81d0e5bb --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/main.json @@ -0,0 +1,1526 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "2376075998560091019" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet)." + }, + "definitions": { + "peeringType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + }, + "remotePeeringEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Deploy the outbound and the inbound peering." + } + }, + "remotePeeringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." + } + }, + "remotePeeringAllowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "remotePeeringAllowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "remotePeeringAllowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "remotePeeringDoNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "remotePeeringUseRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + } + }, + "subnetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Virtual Network (vNet)." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Required. An Array of 1 or more IP Address Prefixes for the Virtual Network." + } + }, + "virtualNetworkBgpCommunity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The BGP community associated with the virtual network." + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An Array of subnets to deploy to the Virtual Network." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. DNS Servers associated to the Virtual Network." + } + }, + "ddosProtectionPlanResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + } + }, + "peerings": { + "type": "array", + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Virtual Network Peering configurations." + } + }, + "vnetEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." + } + }, + "vnetEncryptionEnforcement": { + "type": "string", + "defaultValue": "AllowUnencrypted", + "allowedValues": [ + "AllowUnencrypted", + "DropUnencrypted" + ], + "metadata": { + "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." + } + }, + "flowTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "maxValue": 30, + "metadata": { + "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableVmProtection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "virtualNetwork": { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressSpace": { + "addressPrefixes": "[parameters('addressPrefixes')]" + }, + "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", + "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", + "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", + "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", + "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]" + } + }, + "virtualNetwork_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_diagnosticSettings": { + "copy": { + "name": "virtualNetwork_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_roleAssignments": { + "copy": { + "name": "virtualNetwork_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_subnets": { + "copy": { + "name": "virtualNetwork_subnets", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-subnet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualNetworkName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" + }, + "addressPrefix": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" + }, + "addressPrefixes": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" + }, + "applicationGatewayIPConfigurations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" + }, + "delegation": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" + }, + "natGatewayResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" + }, + "networkSecurityGroupResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" + }, + "privateEndpointNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" + }, + "privateLinkServiceNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "routeTableResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" + }, + "serviceEndpointPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" + }, + "serviceEndpoints": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" + }, + "defaultOutboundAccess": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" + }, + "sharingScope": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "6924527964815690853" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "virtualNetworkName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "serviceEndpoints", + "count": "[length(parameters('serviceEndpoints'))]", + "input": { + "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + } + } + ], + "addressPrefix": "[parameters('addressPrefix')]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", + "privateEndpointNetworkPolicies": "[parameters('privateEndpointNetworkPolicies')]", + "privateLinkServiceNetworkPolicies": "[parameters('privateLinkServiceNetworkPolicies')]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" + } + }, + "subnet_roleAssignments": { + "copy": { + "name": "subnet_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}/subnets/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "subnet" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_local": { + "copy": { + "name": "virtualNetwork_peering_local", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[parameters('name')]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "6667873480569726785" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork", + "virtualNetwork_subnets" + ] + }, + "virtualNetwork_peering_remote": { + "copy": { + "name": "virtualNetwork_peering_remote", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "6667873480569726785" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork", + "virtualNetwork_subnets" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network." + }, + "value": "[parameters('name')]" + }, + "subnetNames": { + "type": "array", + "metadata": { + "description": "The names of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" + } + }, + "subnetResourceIds": { + "type": "array", + "metadata": { + "description": "The resource IDs of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetwork', '2024-01-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-network/subnet/README.md b/avm/1.1.0/res/network/virtual-network/subnet/README.md new file mode 100644 index 000000000..3bc00d1f2 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/subnet/README.md @@ -0,0 +1,308 @@ +# Virtual Network Subnets `[Microsoft.Network/virtualNetworks/subnets]` + +This module deploys a Virtual Network Subnet. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/virtualNetworks/subnets` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-01-01/virtualNetworks/subnets) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The Name of the subnet resource. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefix`](#parameter-addressprefix) | string | The address prefix for the subnet. Required if `addressPrefixes` is empty. | +| [`addressPrefixes`](#parameter-addressprefixes) | array | List of address prefixes for the subnet. Required if `addressPrefix` is empty. | +| [`virtualNetworkName`](#parameter-virtualnetworkname) | string | The name of the parent virtual network. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationGatewayIPConfigurations`](#parameter-applicationgatewayipconfigurations) | array | Application gateway IP configurations of virtual network resource. | +| [`defaultOutboundAccess`](#parameter-defaultoutboundaccess) | bool | Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet. | +| [`delegation`](#parameter-delegation) | string | The delegation to enable on the subnet. | +| [`natGatewayResourceId`](#parameter-natgatewayresourceid) | string | The resource ID of the NAT Gateway to use for the subnet. | +| [`networkSecurityGroupResourceId`](#parameter-networksecuritygroupresourceid) | string | The resource ID of the network security group to assign to the subnet. | +| [`privateEndpointNetworkPolicies`](#parameter-privateendpointnetworkpolicies) | string | Enable or disable apply network policies on private endpoint in the subnet. | +| [`privateLinkServiceNetworkPolicies`](#parameter-privatelinkservicenetworkpolicies) | string | Enable or disable apply network policies on private link service in the subnet. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`routeTableResourceId`](#parameter-routetableresourceid) | string | The resource ID of the route table to assign to the subnet. | +| [`serviceEndpointPolicies`](#parameter-serviceendpointpolicies) | array | An array of service endpoint policies. | +| [`serviceEndpoints`](#parameter-serviceendpoints) | array | The service endpoints to enable on the subnet. | +| [`sharingScope`](#parameter-sharingscope) | string | Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty. | + +### Parameter: `name` + +The Name of the subnet resource. + +- Required: Yes +- Type: string + +### Parameter: `addressPrefix` + +The address prefix for the subnet. Required if `addressPrefixes` is empty. + +- Required: No +- Type: string + +### Parameter: `addressPrefixes` + +List of address prefixes for the subnet. Required if `addressPrefix` is empty. + +- Required: No +- Type: array + +### Parameter: `virtualNetworkName` + +The name of the parent virtual network. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `applicationGatewayIPConfigurations` + +Application gateway IP configurations of virtual network resource. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `defaultOutboundAccess` + +Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet. + +- Required: No +- Type: bool + +### Parameter: `delegation` + +The delegation to enable on the subnet. + +- Required: No +- Type: string + +### Parameter: `natGatewayResourceId` + +The resource ID of the NAT Gateway to use for the subnet. + +- Required: No +- Type: string + +### Parameter: `networkSecurityGroupResourceId` + +The resource ID of the network security group to assign to the subnet. + +- Required: No +- Type: string + +### Parameter: `privateEndpointNetworkPolicies` + +Enable or disable apply network policies on private endpoint in the subnet. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + 'NetworkSecurityGroupEnabled' + 'RouteTableEnabled' + ] + ``` + +### Parameter: `privateLinkServiceNetworkPolicies` + +Enable or disable apply network policies on private link service in the subnet. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `routeTableResourceId` + +The resource ID of the route table to assign to the subnet. + +- Required: No +- Type: string + +### Parameter: `serviceEndpointPolicies` + +An array of service endpoint policies. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `serviceEndpoints` + +The service endpoints to enable on the subnet. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `sharingScope` + +Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'DelegatedServices' + 'Tenant' + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `addressPrefix` | string | The address prefix for the subnet. | +| `addressPrefixes` | array | List of address prefixes for the subnet. | +| `name` | string | The name of the virtual network peering. | +| `resourceGroupName` | string | The resource group the virtual network peering was deployed into. | +| `resourceId` | string | The resource ID of the virtual network peering. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.2.1` | Remote reference | + +## Notes + +The `privateEndpointNetworkPolicies` property must be set to disabled for subnets that contain private endpoints. It confirms that NSGs rules will not apply to private endpoints (currently not supported, [reference](https://learn.microsoft.com/en-us/azure/private-link/private-endpoint-overview#limitations)). Default Value when not specified is "Enabled". diff --git a/avm/1.1.0/res/network/virtual-network/subnet/main.bicep b/avm/1.1.0/res/network/virtual-network/subnet/main.bicep new file mode 100644 index 000000000..70d9b6320 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/subnet/main.bicep @@ -0,0 +1,170 @@ +metadata name = 'Virtual Network Subnets' +metadata description = 'This module deploys a Virtual Network Subnet.' + +@description('Required. The Name of the subnet resource.') +param name string + +@description('Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment.') +param virtualNetworkName string + +@description('Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty.') +param addressPrefix string? + +@description('Optional. The resource ID of the network security group to assign to the subnet.') +param networkSecurityGroupResourceId string? + +@description('Optional. The resource ID of the route table to assign to the subnet.') +param routeTableResourceId string? + +@description('Optional. The service endpoints to enable on the subnet.') +param serviceEndpoints string[] = [] + +@description('Optional. The delegation to enable on the subnet.') +param delegation string? + +@description('Optional. The resource ID of the NAT Gateway to use for the subnet.') +param natGatewayResourceId string? + +@description('Optional. Enable or disable apply network policies on private endpoint in the subnet.') +@allowed([ + 'Disabled' + 'Enabled' + 'NetworkSecurityGroupEnabled' + 'RouteTableEnabled' +]) +param privateEndpointNetworkPolicies string? + +@description('Optional. Enable or disable apply network policies on private link service in the subnet.') +@allowed([ + 'Disabled' + 'Enabled' +]) +param privateLinkServiceNetworkPolicies string? + +@description('Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty.') +param addressPrefixes string[]? + +@description('Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet.') +param defaultOutboundAccess bool? + +@description('Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty.') +param sharingScope ('DelegatedServices' | 'Tenant')? + +@description('Optional. Application gateway IP configurations of virtual network resource.') +param applicationGatewayIPConfigurations array = [] + +@description('Optional. An array of service endpoint policies.') +param serviceEndpointPolicies array = [] + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-01-01' existing = { + name: virtualNetworkName +} + +resource subnet 'Microsoft.Network/virtualNetworks/subnets@2024-01-01' = { + name: name + parent: virtualNetwork + properties: { + addressPrefix: addressPrefix + addressPrefixes: addressPrefixes + networkSecurityGroup: !empty(networkSecurityGroupResourceId) + ? { + id: networkSecurityGroupResourceId + } + : null + routeTable: !empty(routeTableResourceId) + ? { + id: routeTableResourceId + } + : null + natGateway: !empty(natGatewayResourceId) + ? { + id: natGatewayResourceId + } + : null + serviceEndpoints: [ + for endpoint in serviceEndpoints: { + service: endpoint + } + ] + delegations: !empty(delegation) + ? [ + { + name: delegation + properties: { + serviceName: delegation + } + } + ] + : [] + privateEndpointNetworkPolicies: privateEndpointNetworkPolicies + privateLinkServiceNetworkPolicies: privateLinkServiceNetworkPolicies + applicationGatewayIPConfigurations: applicationGatewayIPConfigurations + serviceEndpointPolicies: serviceEndpointPolicies + defaultOutboundAccess: defaultOutboundAccess + sharingScope: sharingScope + } +} + +resource subnet_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(subnet.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: subnet + } +] + +@description('The resource group the virtual network peering was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the virtual network peering.') +output name string = subnet.name + +@description('The resource ID of the virtual network peering.') +output resourceId string = subnet.id + +@description('The address prefix for the subnet.') +output addressPrefix string = subnet.properties.?addressPrefix ?? '' + +@description('List of address prefixes for the subnet.') +output addressPrefixes array = subnet.properties.?addressPrefixes ?? [] diff --git a/avm/1.1.0/res/network/virtual-network/subnet/main.json b/avm/1.1.0/res/network/virtual-network/subnet/main.json new file mode 100644 index 000000000..44761e1d2 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/subnet/main.json @@ -0,0 +1,338 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "6924527964815690853" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "virtualNetworkName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled", + "NetworkSecurityGroupEnabled", + "RouteTableEnabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "serviceEndpoints", + "count": "[length(parameters('serviceEndpoints'))]", + "input": { + "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + } + } + ], + "addressPrefix": "[parameters('addressPrefix')]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", + "privateEndpointNetworkPolicies": "[parameters('privateEndpointNetworkPolicies')]", + "privateLinkServiceNetworkPolicies": "[parameters('privateLinkServiceNetworkPolicies')]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" + } + }, + "subnet_roleAssignments": { + "copy": { + "name": "subnet_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}/subnets/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "subnet" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-network/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/virtual-network/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..2c649a41d --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,51 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworks-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvnmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + addressPrefixes: [ + '10.0.0.0/16' + ] + } + } +] diff --git a/avm/1.1.0/res/network/virtual-network/tests/e2e/ipv6/main.test.bicep b/avm/1.1.0/res/network/virtual-network/tests/e2e/ipv6/main.test.bicep new file mode 100644 index 000000000..f1e732cda --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/tests/e2e/ipv6/main.test.bicep @@ -0,0 +1,61 @@ +targetScope = 'subscription' + +metadata name = 'Using an IPv6 address space' +metadata description = 'This instance deploys the module using an IPv6 address space.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworks-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvnipv6' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + addressPrefixes: [ + '10.0.0.0/21' + 'fd00:592b:3014::/64' + ] + subnets: [ + { + name: 'ipv6-subnet' + addressPrefixes: [ + '10.0.0.0/24' + 'fd00:592b:3014::/64' + ] + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/virtual-network/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/virtual-network/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..b7275d12a --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/tests/e2e/max/dependencies.bicep @@ -0,0 +1,163 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Route Table to create.') +param routeTableName string + +@description('Required. The name of the Network Security Group to create.') +param networkSecurityGroupName string + +@description('Required. The name of the Bastion Network Security Group to create.') +param networkSecurityGroupBastionName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource routeTable 'Microsoft.Network/routeTables@2023-04-01' = { + name: routeTableName + location: location +} + +resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: networkSecurityGroupName + location: location +} + +resource networkSecurityGroupBastion 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: networkSecurityGroupBastionName + location: location + properties: { + securityRules: [ + { + name: 'AllowHttpsInbound' + properties: { + priority: 120 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'Internet' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowGatewayManagerInbound' + properties: { + priority: 130 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'GatewayManager' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowAzureLoadBalancerInbound' + properties: { + priority: 140 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'AzureLoadBalancer' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionHostCommunication' + properties: { + priority: 150 + protocol: '*' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowSshOutbound' + properties: { + priority: 100 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '22' + '3389' + ] + } + } + { + name: 'AllowAzureCloudOutbound' + properties: { + priority: 110 + protocol: 'Tcp' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'AzureCloud' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionCommunication' + properties: { + priority: 120 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowHttpOutbound' + properties: { + priority: 130 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'Internet' + destinationPortRange: '80' + } + } + ] + } +} + +@description('The resource ID of the created Route Table.') +output routeTableResourceId string = routeTable.id + +@description('The resource ID of the created Network Security Group.') +output networkSecurityGroupResourceId string = networkSecurityGroup.id + +@description('The resource ID of the created Bastion Network Security Group.') +output networkSecurityGroupBastionResourceId string = networkSecurityGroupBastion.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/virtual-network/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/virtual-network/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..20abe577d --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/tests/e2e/max/main.test.bicep @@ -0,0 +1,193 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworks-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvnmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + routeTableName: 'dep-${namePrefix}-rt-${serviceShort}' + networkSecurityGroupName: 'dep-${namePrefix}-nsg-${serviceShort}' + networkSecurityGroupBastionName: 'dep-${namePrefix}-nsg-bastion-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +var addressPrefix = '10.0.0.0/16' +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + addressPrefixes: [ + addressPrefix + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + dnsServers: [ + '10.0.1.4' + '10.0.1.5' + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'f5c27a7b-9b18-4dc1-b002-db3c38e80b64' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + flowTimeoutInMinutes: 20 + subnets: [ + { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + name: 'GatewaySubnet' + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 1) + name: '${namePrefix}-az-subnet-x-001' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupResourceId + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + routeTableResourceId: nestedDependencies.outputs.routeTableResourceId + serviceEndpoints: [ + 'Microsoft.Storage' + 'Microsoft.Sql' + ] + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 2) + delegation: 'Microsoft.Netapp/volumes' + name: '${namePrefix}-az-subnet-x-002' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupResourceId + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 3) + name: '${namePrefix}-az-subnet-x-003' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupResourceId + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 4) + name: '${namePrefix}-az-subnet-x-004' + networkSecurityGroupResourceId: '' + natGatewayResourceId: '' + routeTableResourceId: '' + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 5) + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupBastionResourceId + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 6) + name: 'AzureFirewallSubnet' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/virtual-network/tests/e2e/vnetPeering/dependencies.bicep b/avm/1.1.0/res/network/virtual-network/tests/e2e/vnetPeering/dependencies.bicep new file mode 100644 index 000000000..15d8c62e0 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/tests/e2e/vnetPeering/dependencies.bicep @@ -0,0 +1,158 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Bastion Network Security Group to create.') +param networkSecurityGroupBastionName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-11-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource networkSecurityGroupBastion 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: networkSecurityGroupBastionName + location: location + properties: { + securityRules: [ + { + name: 'AllowHttpsInbound' + properties: { + priority: 120 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'Internet' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowGatewayManagerInbound' + properties: { + priority: 130 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'GatewayManager' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowAzureLoadBalancerInbound' + properties: { + priority: 140 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'AzureLoadBalancer' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionHostCommunication' + properties: { + priority: 150 + protocol: '*' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowSshOutbound' + properties: { + priority: 100 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '22' + '3389' + ] + } + } + { + name: 'AllowAzureCloudOutbound' + properties: { + priority: 110 + protocol: 'Tcp' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'AzureCloud' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionCommunication' + properties: { + priority: 120 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowHttpOutbound' + properties: { + priority: 130 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'Internet' + destinationPortRange: '80' + } + } + ] + } +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Bastion Network Security Group.') +output networkSecurityGroupBastionResourceId string = networkSecurityGroupBastion.id diff --git a/avm/1.1.0/res/network/virtual-network/tests/e2e/vnetPeering/main.test.bicep b/avm/1.1.0/res/network/virtual-network/tests/e2e/vnetPeering/main.test.bicep new file mode 100644 index 000000000..e2b47292d --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/tests/e2e/vnetPeering/main.test.bicep @@ -0,0 +1,94 @@ +targetScope = 'subscription' + +metadata name = 'Deploying a bi-directional peering' +metadata description = 'This instance deploys the module with both an inbound and outbound peering.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworks-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvnpeer' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + networkSecurityGroupBastionName: 'dep-${namePrefix}-nsg-bastion-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + addressPrefixes: [ + '10.1.0.0/24' + ] + subnets: [ + { + addressPrefix: '10.1.0.0/26' + name: 'GatewaySubnet' + } + { + addressPrefix: '10.1.0.64/26' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupBastionResourceId + } + { + addressPrefix: '10.1.0.128/26' + name: 'AzureFirewallSubnet' + } + ] + peerings: [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + remotePeeringAllowForwardedTraffic: true + remotePeeringAllowVirtualNetworkAccess: true + remotePeeringEnabled: true + remotePeeringName: 'customName' + remoteVirtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + useRemoteGateways: false + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/virtual-network/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/virtual-network/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..b7275d12a --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,163 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Route Table to create.') +param routeTableName string + +@description('Required. The name of the Network Security Group to create.') +param networkSecurityGroupName string + +@description('Required. The name of the Bastion Network Security Group to create.') +param networkSecurityGroupBastionName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource routeTable 'Microsoft.Network/routeTables@2023-04-01' = { + name: routeTableName + location: location +} + +resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: networkSecurityGroupName + location: location +} + +resource networkSecurityGroupBastion 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: networkSecurityGroupBastionName + location: location + properties: { + securityRules: [ + { + name: 'AllowHttpsInbound' + properties: { + priority: 120 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'Internet' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowGatewayManagerInbound' + properties: { + priority: 130 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'GatewayManager' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowAzureLoadBalancerInbound' + properties: { + priority: 140 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'AzureLoadBalancer' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionHostCommunication' + properties: { + priority: 150 + protocol: '*' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowSshOutbound' + properties: { + priority: 100 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '22' + '3389' + ] + } + } + { + name: 'AllowAzureCloudOutbound' + properties: { + priority: 110 + protocol: 'Tcp' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'AzureCloud' + destinationPortRange: '443' + } + } + { + name: 'AllowBastionCommunication' + properties: { + priority: 120 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + { + name: 'AllowHttpOutbound' + properties: { + priority: 130 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'Internet' + destinationPortRange: '80' + } + } + ] + } +} + +@description('The resource ID of the created Route Table.') +output routeTableResourceId string = routeTable.id + +@description('The resource ID of the created Network Security Group.') +output networkSecurityGroupResourceId string = networkSecurityGroup.id + +@description('The resource ID of the created Bastion Network Security Group.') +output networkSecurityGroupBastionResourceId string = networkSecurityGroupBastion.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/virtual-network/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/virtual-network/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..5539eb56a --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,147 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworks-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvnwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + routeTableName: 'dep-${namePrefix}-rt-${serviceShort}' + networkSecurityGroupName: 'dep-${namePrefix}-nsg-${serviceShort}' + networkSecurityGroupBastionName: 'dep-${namePrefix}-nsg-bastion-${serviceShort}' + location: resourceLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +var addressPrefix = '10.0.0.0/16' +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + addressPrefixes: [ + addressPrefix + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + dnsServers: [ + '10.0.1.4' + '10.0.1.5' + ] + flowTimeoutInMinutes: 20 + subnets: [ + { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + name: 'GatewaySubnet' + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 1) + name: '${namePrefix}-az-subnet-x-001' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupResourceId + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + routeTableResourceId: nestedDependencies.outputs.routeTableResourceId + serviceEndpoints: [ + 'Microsoft.Storage' + 'Microsoft.Sql' + ] + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 2) + delegation: 'Microsoft.Netapp/volumes' + name: '${namePrefix}-az-subnet-x-002' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupResourceId + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 3) + name: '${namePrefix}-az-subnet-x-003' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupResourceId + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 4) + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: nestedDependencies.outputs.networkSecurityGroupBastionResourceId + } + { + addressPrefix: cidrSubnet(addressPrefix, 24, 5) + name: 'AzureFirewallSubnet' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/virtual-network/version.json b/avm/1.1.0/res/network/virtual-network/version.json new file mode 100644 index 000000000..ea4f3b6e6 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-network/virtual-network-peering/README.md b/avm/1.1.0/res/network/virtual-network/virtual-network-peering/README.md new file mode 100644 index 000000000..ef10225be --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/virtual-network-peering/README.md @@ -0,0 +1,110 @@ +# Virtual Network Peerings `[Microsoft.Network/virtualNetworks/virtualNetworkPeerings]` + +This module deploys a Virtual Network Peering. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2024-01-01/virtualNetworks/virtualNetworkPeerings) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`remoteVirtualNetworkResourceId`](#parameter-remotevirtualnetworkresourceid) | string | The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`localVnetName`](#parameter-localvnetname) | string | The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowForwardedTraffic`](#parameter-allowforwardedtraffic) | bool | Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true. | +| [`allowGatewayTransit`](#parameter-allowgatewaytransit) | bool | If gateway links can be used in remote virtual networking to link to this virtual network. Default is false. | +| [`allowVirtualNetworkAccess`](#parameter-allowvirtualnetworkaccess) | bool | Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true. | +| [`doNotVerifyRemoteGateways`](#parameter-donotverifyremotegateways) | bool | If we need to verify the provisioning state of the remote gateway. Default is true. | +| [`name`](#parameter-name) | string | The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName. | +| [`useRemoteGateways`](#parameter-useremotegateways) | bool | If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false. | + +### Parameter: `remoteVirtualNetworkResourceId` + +The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID. + +- Required: Yes +- Type: string + +### Parameter: `localVnetName` + +The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `allowForwardedTraffic` + +Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `allowGatewayTransit` + +If gateway links can be used in remote virtual networking to link to this virtual network. Default is false. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `allowVirtualNetworkAccess` + +Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `doNotVerifyRemoteGateways` + +If we need to verify the provisioning state of the remote gateway. Default is true. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `name` + +The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName. + +- Required: No +- Type: string +- Default: `[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]` + +### Parameter: `useRemoteGateways` + +If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false. + +- Required: No +- Type: bool +- Default: `False` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the virtual network peering. | +| `resourceGroupName` | string | The resource group the virtual network peering was deployed into. | +| `resourceId` | string | The resource ID of the virtual network peering. | diff --git a/avm/1.1.0/res/network/virtual-network/virtual-network-peering/main.bicep b/avm/1.1.0/res/network/virtual-network/virtual-network-peering/main.bicep new file mode 100644 index 000000000..4808dc5b2 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/virtual-network-peering/main.bicep @@ -0,0 +1,54 @@ +metadata name = 'Virtual Network Peerings' +metadata description = 'This module deploys a Virtual Network Peering.' + +@description('Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName.') +param name string = 'peer-${localVnetName}-${last(split(remoteVirtualNetworkResourceId, '/'))}' + +@description('Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment.') +param localVnetName string + +@description('Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID.') +param remoteVirtualNetworkResourceId string + +@description('Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true.') +param allowForwardedTraffic bool = true + +@description('Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false.') +param allowGatewayTransit bool = false + +@description('Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true.') +param allowVirtualNetworkAccess bool = true + +@description('Optional. If we need to verify the provisioning state of the remote gateway. Default is true.') +param doNotVerifyRemoteGateways bool = true + +@description('Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false.') +param useRemoteGateways bool = false + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-11-01' existing = { + name: localVnetName +} + +resource virtualNetworkPeering 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2024-01-01' = { + name: name + parent: virtualNetwork + properties: { + allowForwardedTraffic: allowForwardedTraffic + allowGatewayTransit: allowGatewayTransit + allowVirtualNetworkAccess: allowVirtualNetworkAccess + doNotVerifyRemoteGateways: doNotVerifyRemoteGateways + useRemoteGateways: useRemoteGateways + remoteVirtualNetwork: { + id: remoteVirtualNetworkResourceId + } + } +} + +@description('The resource group the virtual network peering was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the virtual network peering.') +output name string = virtualNetworkPeering.name + +@description('The resource ID of the virtual network peering.') +output resourceId string = virtualNetworkPeering.id diff --git a/avm/1.1.0/res/network/virtual-network/virtual-network-peering/main.json b/avm/1.1.0/res/network/virtual-network/virtual-network-peering/main.json new file mode 100644 index 000000000..ee192848f --- /dev/null +++ b/avm/1.1.0/res/network/virtual-network/virtual-network-peering/main.json @@ -0,0 +1,109 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "6667873480569726785" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-wan/README.md b/avm/1.1.0/res/network/virtual-wan/README.md new file mode 100644 index 000000000..c635065b6 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-wan/README.md @@ -0,0 +1,607 @@ +# Virtual WANs `[Microsoft.Network/virtualWans]` + +This module deploys a Virtual WAN. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/virtualWans` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/virtualWans) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/virtual-wan:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module virtualWan 'br/public:avm/res/network/virtual-wan:' = { + name: 'virtualWanDeployment' + params: { + name: 'nvwmin001' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "nvwmin001" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-wan:' + +param name = 'nvwmin001' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module virtualWan 'br/public:avm/res/network/virtual-wan:' = { + name: 'virtualWanDeployment' + params: { + // Required parameters + name: 'nvwmax001' + // Non-required parameters + allowBranchToBranchTraffic: true + allowVnetToVnetTraffic: true + disableVpnEncryption: true + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '360a3e7e-49bf-4e94-839f-14c91e8e0c23' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + type: 'Basic' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nvwmax001" + }, + // Non-required parameters + "allowBranchToBranchTraffic": { + "value": true + }, + "allowVnetToVnetTraffic": { + "value": true + }, + "disableVpnEncryption": { + "value": true + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "360a3e7e-49bf-4e94-839f-14c91e8e0c23", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "type": { + "value": "Basic" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-wan:' + +// Required parameters +param name = 'nvwmax001' +// Non-required parameters +param allowBranchToBranchTraffic = true +param allowVnetToVnetTraffic = true +param disableVpnEncryption = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '360a3e7e-49bf-4e94-839f-14c91e8e0c23' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param type = 'Basic' +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module virtualWan 'br/public:avm/res/network/virtual-wan:' = { + name: 'virtualWanDeployment' + params: { + // Required parameters + name: 'nvwwaf001' + // Non-required parameters + allowBranchToBranchTraffic: true + allowVnetToVnetTraffic: true + disableVpnEncryption: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + type: 'Basic' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nvwwaf001" + }, + // Non-required parameters + "allowBranchToBranchTraffic": { + "value": true + }, + "allowVnetToVnetTraffic": { + "value": true + }, + "disableVpnEncryption": { + "value": true + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "type": { + "value": "Basic" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-wan:' + +// Required parameters +param name = 'nvwwaf001' +// Non-required parameters +param allowBranchToBranchTraffic = true +param allowVnetToVnetTraffic = true +param disableVpnEncryption = true +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param type = 'Basic' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Virtual WAN. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowBranchToBranchTraffic`](#parameter-allowbranchtobranchtraffic) | bool | True if branch to branch traffic is allowed. | +| [`allowVnetToVnetTraffic`](#parameter-allowvnettovnettraffic) | bool | True if VNET to VNET traffic is allowed. | +| [`disableVpnEncryption`](#parameter-disablevpnencryption) | bool | VPN encryption to be disabled or not. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location where all resources will be created. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`type`](#parameter-type) | string | The type of the Virtual WAN. | + +### Parameter: `name` + +Name of the Virtual WAN. + +- Required: Yes +- Type: string + +### Parameter: `allowBranchToBranchTraffic` + +True if branch to branch traffic is allowed. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `allowVnetToVnetTraffic` + +True if VNET to VNET traffic is allowed. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `disableVpnEncryption` + +VPN encryption to be disabled or not. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location where all resources will be created. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `type` + +The type of the Virtual WAN. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Standard' + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the virtual WAN. | +| `resourceGroupName` | string | The resource group the virtual WAN was deployed into. | +| `resourceId` | string | The resource ID of the virtual WAN. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/virtual-wan/main.bicep b/avm/1.1.0/res/network/virtual-wan/main.bicep new file mode 100644 index 000000000..fce9e7486 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-wan/main.bicep @@ -0,0 +1,137 @@ +metadata name = 'Virtual WANs' +metadata description = 'This module deploys a Virtual WAN.' + +@description('Optional. Location where all resources will be created.') +param location string = resourceGroup().location + +@description('Required. Name of the Virtual WAN.') +param name string + +@description('Optional. The type of the Virtual WAN.') +@allowed([ + 'Standard' + 'Basic' +]) +param type string = 'Standard' + +@description('Optional. True if branch to branch traffic is allowed.') +param allowBranchToBranchTraffic bool = false + +@description('Optional. True if VNET to VNET traffic is allowed.') +param allowVnetToVnetTraffic bool = false + +@description('Optional. VPN encryption to be disabled or not.') +param disableVpnEncryption bool = false + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.network-virtualwan.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + allowBranchToBranchTraffic: allowBranchToBranchTraffic + allowVnetToVnetTraffic: allowVnetToVnetTraffic ? allowVnetToVnetTraffic : null + disableVpnEncryption: disableVpnEncryption + type: type + } +} + +resource virtualWan_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: virtualWan +} + +resource virtualWan_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(virtualWan.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: virtualWan + } +] + +@description('The name of the virtual WAN.') +output name string = virtualWan.name + +@description('The resource ID of the virtual WAN.') +output resourceId string = virtualWan.id + +@description('The resource group the virtual WAN was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = virtualWan.location diff --git a/avm/1.1.0/res/network/virtual-wan/main.json b/avm/1.1.0/res/network/virtual-wan/main.json new file mode 100644 index 000000000..d02cf9a99 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-wan/main.json @@ -0,0 +1,317 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "17894213695332592187" + }, + "name": "Virtual WANs", + "description": "This module deploys a Virtual WAN." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location where all resources will be created." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Virtual WAN." + } + }, + "type": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Standard", + "Basic" + ], + "metadata": { + "description": "Optional. The type of the Virtual WAN." + } + }, + "allowBranchToBranchTraffic": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. True if branch to branch traffic is allowed." + } + }, + "allowVnetToVnetTraffic": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. True if VNET to VNET traffic is allowed." + } + }, + "disableVpnEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. VPN encryption to be disabled or not." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualwan.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "virtualWan": { + "type": "Microsoft.Network/virtualWans", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "allowBranchToBranchTraffic": "[parameters('allowBranchToBranchTraffic')]", + "allowVnetToVnetTraffic": "[if(parameters('allowVnetToVnetTraffic'), parameters('allowVnetToVnetTraffic'), null())]", + "disableVpnEncryption": "[parameters('disableVpnEncryption')]", + "type": "[parameters('type')]" + } + }, + "virtualWan_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/virtualWans/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "virtualWan" + ] + }, + "virtualWan_roleAssignments": { + "copy": { + "name": "virtualWan_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualWans/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualWans', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "virtualWan" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual WAN." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual WAN." + }, + "value": "[resourceId('Microsoft.Network/virtualWans', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual WAN was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualWan', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/virtual-wan/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/virtual-wan/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..8f4937014 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-wan/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,47 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualwans-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvwmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + } + } +] diff --git a/avm/1.1.0/res/network/virtual-wan/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/virtual-wan/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..9f6d36711 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-wan/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param resourceLocation string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: resourceLocation +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/virtual-wan/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/virtual-wan/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..9ab896dd6 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-wan/tests/e2e/max/main.test.bicep @@ -0,0 +1,92 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualwans-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvwmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + resourceLocation: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + allowBranchToBranchTraffic: true + allowVnetToVnetTraffic: true + disableVpnEncryption: true + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '360a3e7e-49bf-4e94-839f-14c91e8e0c23' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + type: 'Basic' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/virtual-wan/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/virtual-wan/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..7be39e253 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-wan/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/network/virtual-wan/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/virtual-wan/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..b2ee92d41 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-wan/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,56 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualwans-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvwwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + allowBranchToBranchTraffic: true + allowVnetToVnetTraffic: true + disableVpnEncryption: true + type: 'Basic' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/virtual-wan/version.json b/avm/1.1.0/res/network/virtual-wan/version.json new file mode 100644 index 000000000..c177b1bb5 --- /dev/null +++ b/avm/1.1.0/res/network/virtual-wan/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/vpn-gateway/README.md b/avm/1.1.0/res/network/vpn-gateway/README.md new file mode 100644 index 000000000..5bc27b3de --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/README.md @@ -0,0 +1,748 @@ +# VPN Gateways `[Microsoft.Network/vpnGateways]` + +This module deploys a VPN Gateway. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) +- [Data Collection](#Data-Collection) + +## 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.Network/vpnGateways` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/vpnGateways) | +| `Microsoft.Network/vpnGateways/natRules` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/vpnGateways/natRules) | +| `Microsoft.Network/vpnGateways/vpnConnections` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/vpnGateways/vpnConnections) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/vpn-gateway:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = { + name: 'vpnGatewayDeployment' + params: { + // Required parameters + name: 'vpngmin001' + virtualHubResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "vpngmin001" + }, + "virtualHubResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-gateway:' + +// Required parameters +param name = 'vpngmin001' +param virtualHubResourceId = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = { + name: 'vpnGatewayDeployment' + params: { + // Required parameters + name: 'vpngmax001' + virtualHubResourceId: '' + // Non-required parameters + bgpSettings: { + asn: 65515 + peerWeight: 0 + } + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + natRules: [ + { + externalMappings: [ + { + addressSpace: '192.168.21.0/24' + } + ] + internalMappings: [ + { + addressSpace: '10.4.0.0/24' + } + ] + mode: 'EgressSnat' + name: 'natRule1' + type: 'Static' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vpnConnections: [ + { + connectionBandwidth: 100 + enableBgp: false + enableInternetSecurity: true + enableRateLimiting: false + name: '' + remoteVpnSiteResourceId: '' + routingWeight: 0 + useLocalAzureIpAddress: false + usePolicyBasedTrafficSelectors: false + vpnConnectionProtocolType: 'IKEv2' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "vpngmax001" + }, + "virtualHubResourceId": { + "value": "" + }, + // Non-required parameters + "bgpSettings": { + "value": { + "asn": 65515, + "peerWeight": 0 + } + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "natRules": { + "value": [ + { + "externalMappings": [ + { + "addressSpace": "192.168.21.0/24" + } + ], + "internalMappings": [ + { + "addressSpace": "10.4.0.0/24" + } + ], + "mode": "EgressSnat", + "name": "natRule1", + "type": "Static" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "vpnConnections": { + "value": [ + { + "connectionBandwidth": 100, + "enableBgp": false, + "enableInternetSecurity": true, + "enableRateLimiting": false, + "name": "", + "remoteVpnSiteResourceId": "", + "routingWeight": 0, + "useLocalAzureIpAddress": false, + "usePolicyBasedTrafficSelectors": false, + "vpnConnectionProtocolType": "IKEv2" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-gateway:' + +// Required parameters +param name = 'vpngmax001' +param virtualHubResourceId = '' +// Non-required parameters +param bgpSettings = { + asn: 65515 + peerWeight: 0 +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param natRules = [ + { + externalMappings: [ + { + addressSpace: '192.168.21.0/24' + } + ] + internalMappings: [ + { + addressSpace: '10.4.0.0/24' + } + ] + mode: 'EgressSnat' + name: 'natRule1' + type: 'Static' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vpnConnections = [ + { + connectionBandwidth: 100 + enableBgp: false + enableInternetSecurity: true + enableRateLimiting: false + name: '' + remoteVpnSiteResourceId: '' + routingWeight: 0 + useLocalAzureIpAddress: false + usePolicyBasedTrafficSelectors: false + vpnConnectionProtocolType: 'IKEv2' + } +] +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = { + name: 'vpnGatewayDeployment' + params: { + // Required parameters + name: 'vpngwaf001' + virtualHubResourceId: '' + // Non-required parameters + bgpSettings: { + asn: 65515 + peerWeight: 0 + } + location: '' + natRules: [ + { + externalMappings: [ + { + addressSpace: '192.168.21.0/24' + } + ] + internalMappings: [ + { + addressSpace: '10.4.0.0/24' + } + ] + mode: 'EgressSnat' + name: 'natRule1' + type: 'Static' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vpnConnections: [ + { + connectionBandwidth: 100 + enableBgp: false + enableInternetSecurity: true + enableRateLimiting: false + name: '' + remoteVpnSiteResourceId: '' + routingWeight: 0 + useLocalAzureIpAddress: false + usePolicyBasedTrafficSelectors: false + vpnConnectionProtocolType: 'IKEv2' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "vpngwaf001" + }, + "virtualHubResourceId": { + "value": "" + }, + // Non-required parameters + "bgpSettings": { + "value": { + "asn": 65515, + "peerWeight": 0 + } + }, + "location": { + "value": "" + }, + "natRules": { + "value": [ + { + "externalMappings": [ + { + "addressSpace": "192.168.21.0/24" + } + ], + "internalMappings": [ + { + "addressSpace": "10.4.0.0/24" + } + ], + "mode": "EgressSnat", + "name": "natRule1", + "type": "Static" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "vpnConnections": { + "value": [ + { + "connectionBandwidth": 100, + "enableBgp": false, + "enableInternetSecurity": true, + "enableRateLimiting": false, + "name": "", + "remoteVpnSiteResourceId": "", + "routingWeight": 0, + "useLocalAzureIpAddress": false, + "usePolicyBasedTrafficSelectors": false, + "vpnConnectionProtocolType": "IKEv2" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-gateway:' + +// Required parameters +param name = 'vpngwaf001' +param virtualHubResourceId = '' +// Non-required parameters +param bgpSettings = { + asn: 65515 + peerWeight: 0 +} +param location = '' +param natRules = [ + { + externalMappings: [ + { + addressSpace: '192.168.21.0/24' + } + ] + internalMappings: [ + { + addressSpace: '10.4.0.0/24' + } + ] + mode: 'EgressSnat' + name: 'natRule1' + type: 'Static' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vpnConnections = [ + { + connectionBandwidth: 100 + enableBgp: false + enableInternetSecurity: true + enableRateLimiting: false + name: '' + remoteVpnSiteResourceId: '' + routingWeight: 0 + useLocalAzureIpAddress: false + usePolicyBasedTrafficSelectors: false + vpnConnectionProtocolType: 'IKEv2' + } +] +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the VPN gateway. | +| [`virtualHubResourceId`](#parameter-virtualhubresourceid) | string | The resource ID of a virtual Hub to connect to. Note: The virtual Hub and Gateway must be deployed into the same location. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`bgpSettings`](#parameter-bgpsettings) | object | BGP settings details. | +| [`enableBgpRouteTranslationForNat`](#parameter-enablebgproutetranslationfornat) | bool | Enable BGP routes translation for NAT on this VPN gateway. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`isRoutingPreferenceInternet`](#parameter-isroutingpreferenceinternet) | bool | Enable routing preference property for the public IP interface of the VPN gateway. | +| [`location`](#parameter-location) | string | Location where all resources will be created. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`natRules`](#parameter-natrules) | array | List of all the NAT Rules to associate with the gateway. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`vpnConnections`](#parameter-vpnconnections) | array | The VPN connections to create in the VPN gateway. | +| [`vpnGatewayScaleUnit`](#parameter-vpngatewayscaleunit) | int | The scale unit for this VPN gateway. | + +### Parameter: `name` + +Name of the VPN gateway. + +- Required: Yes +- Type: string + +### Parameter: `virtualHubResourceId` + +The resource ID of a virtual Hub to connect to. Note: The virtual Hub and Gateway must be deployed into the same location. + +- Required: Yes +- Type: string + +### Parameter: `bgpSettings` + +BGP settings details. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `enableBgpRouteTranslationForNat` + +Enable BGP routes translation for NAT on this VPN gateway. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `isRoutingPreferenceInternet` + +Enable routing preference property for the public IP interface of the VPN gateway. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `location` + +Location where all resources will be created. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `natRules` + +List of all the NAT Rules to associate with the gateway. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `vpnConnections` + +The VPN connections to create in the VPN gateway. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `vpnGatewayScaleUnit` + +The scale unit for this VPN gateway. + +- Required: No +- Type: int +- Default: `2` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the VPN gateway. | +| `resourceGroupName` | string | The name of the resource group the VPN gateway was deployed into. | +| `resourceId` | string | The resource ID of the VPN gateway. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Notes + +### Parameter Usage: `bgpSettings` + +

+ +Parameter JSON format + +```json +"bgpSettings": { + "asn": 65515, + "peerWeight": 0, + "bgpPeeringAddresses": [ + { + "ipconfigurationId": "Instance0", + "defaultBgpIpAddresses": [ + "10.0.0.12" + ], + "customBgpIpAddresses": [], + "tunnelIpAddresses": [ + "20.84.35.53", + "10.0.0.4" + ] + }, + { + "ipconfigurationId": "Instance1", + "defaultBgpIpAddresses": [ + "10.0.0.13" + ], + "customBgpIpAddresses": [], + "tunnelIpAddresses": [ + "20.84.34.225", + "10.0.0.5" + ] + } + ] +} +``` + +
+ +
+ +Bicep format + +```bicep +bgpSettings: { + asn: 65515 + peerWeight: 0 + bgpPeeringAddresses: [ + { + ipconfigurationId: 'Instance0' + defaultBgpIpAddresses: [ + '10.0.0.12' + ] + customBgpIpAddresses: [] + tunnelIpAddresses: [ + '20.84.35.53' + '10.0.0.4' + ] + } + { + ipconfigurationId: 'Instance1' + defaultBgpIpAddresses: [ + '10.0.0.13' + ] + customBgpIpAddresses: [] + tunnelIpAddresses: [ + '20.84.34.225' + '10.0.0.5' + ] + } + ] +} +``` + +
+

+ +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/vpn-gateway/main.bicep b/avm/1.1.0/res/network/vpn-gateway/main.bicep new file mode 100644 index 000000000..763c83c38 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/main.bicep @@ -0,0 +1,163 @@ +metadata name = 'VPN Gateways' +metadata description = 'This module deploys a VPN Gateway.' + +@description('Required. Name of the VPN gateway.') +param name string + +@description('Optional. Location where all resources will be created.') +param location string = resourceGroup().location + +@description('Optional. The VPN connections to create in the VPN gateway.') +param vpnConnections array = [] + +@description('Optional. List of all the NAT Rules to associate with the gateway.') +param natRules array = [] + +@description('Required. The resource ID of a virtual Hub to connect to. Note: The virtual Hub and Gateway must be deployed into the same location.') +param virtualHubResourceId string + +@description('Optional. BGP settings details.') +param bgpSettings object = {} + +@description('Optional. Enable BGP routes translation for NAT on this VPN gateway.') +param enableBgpRouteTranslationForNat bool = false + +@description('Optional. Enable routing preference property for the public IP interface of the VPN gateway.') +param isRoutingPreferenceInternet bool = false + +@description('Optional. The scale unit for this VPN gateway.') +param vpnGatewayScaleUnit int = 2 + +@description('Optional. Tags of the resource.') +param tags object? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.res.network-vpngateway.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource vpnGateway 'Microsoft.Network/vpnGateways@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + bgpSettings: bgpSettings + enableBgpRouteTranslationForNat: enableBgpRouteTranslationForNat + isRoutingPreferenceInternet: isRoutingPreferenceInternet + vpnGatewayScaleUnit: vpnGatewayScaleUnit + connections: [ + for (connection, index) in vpnConnections: { + name: connection.name + properties: { + connectionBandwidth: connection.?connectionBandwidth + enableBgp: connection.?enableBgp + enableInternetSecurity: connection.?enableInternetSecurity + remoteVpnSite: contains(connection, 'remoteVpnSiteResourceId') + ? { + id: connection.remoteVpnSiteResourceId + } + : null + enableRateLimiting: connection.?enableRateLimiting + routingConfiguration: connection.?routingConfiguration + routingWeight: connection.?routingWeight + sharedKey: connection.?sharedKey + useLocalAzureIpAddress: connection.?useLocalAzureIpAddress + usePolicyBasedTrafficSelectors: connection.?usePolicyBasedTrafficSelectors + vpnConnectionProtocolType: connection.?vpnConnectionProtocolType + ipsecPolicies: connection.?ipsecPolicies + trafficSelectorPolicies: connection.?trafficSelectorPolicies + vpnLinkConnections: connection.?vpnLinkConnections + } + } + ] + virtualHub: { + id: virtualHubResourceId + } + } +} + +resource vpnGateway_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: vpnGateway +} + +module vpnGateway_natRules 'nat-rule/main.bicep' = [ + for (natRule, index) in natRules: { + name: '${deployment().name}-NATRule-${index}' + params: { + name: natRule.name + vpnGatewayName: vpnGateway.name + externalMappings: natRule.?externalMappings + internalMappings: natRule.?internalMappings + ipConfigurationId: natRule.?ipConfigurationId + mode: natRule.?mode + type: natRule.?type + } + } +] + +module vpnGateway_vpnConnections 'vpn-connection/main.bicep' = [ + for (connection, index) in vpnConnections: { + name: '${deployment().name}-Connection-${index}' + params: { + name: connection.name + vpnGatewayName: vpnGateway.name + connectionBandwidth: connection.?connectionBandwidth + enableBgp: connection.?enableBgp + enableInternetSecurity: connection.?enableInternetSecurity + remoteVpnSiteResourceId: connection.?remoteVpnSiteResourceId + enableRateLimiting: connection.?enableRateLimiting + routingConfiguration: connection.?routingConfiguration + routingWeight: connection.?routingWeight + sharedKey: connection.?sharedKey + useLocalAzureIpAddress: connection.?useLocalAzureIpAddress + usePolicyBasedTrafficSelectors: connection.?usePolicyBasedTrafficSelectors + vpnConnectionProtocolType: connection.?vpnConnectionProtocolType + ipsecPolicies: connection.?ipsecPolicies + trafficSelectorPolicies: connection.?trafficSelectorPolicies + vpnLinkConnections: connection.?vpnLinkConnections + } + } +] + +@description('The name of the VPN gateway.') +output name string = vpnGateway.name + +@description('The resource ID of the VPN gateway.') +output resourceId string = vpnGateway.id + +@description('The name of the resource group the VPN gateway was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = vpnGateway.location diff --git a/avm/1.1.0/res/network/vpn-gateway/main.json b/avm/1.1.0/res/network/vpn-gateway/main.json new file mode 100644 index 000000000..1a963a774 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/main.json @@ -0,0 +1,635 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "13461484235913765557" + }, + "name": "VPN Gateways", + "description": "This module deploys a VPN Gateway." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the VPN gateway." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location where all resources will be created." + } + }, + "vpnConnections": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The VPN connections to create in the VPN gateway." + } + }, + "natRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of all the NAT Rules to associate with the gateway." + } + }, + "virtualHubResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a virtual Hub to connect to. Note: The virtual Hub and Gateway must be deployed into the same location." + } + }, + "bgpSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. BGP settings details." + } + }, + "enableBgpRouteTranslationForNat": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable BGP routes translation for NAT on this VPN gateway." + } + }, + "isRoutingPreferenceInternet": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable routing preference property for the public IP interface of the VPN gateway." + } + }, + "vpnGatewayScaleUnit": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Optional. The scale unit for this VPN gateway." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.res.network-vpngateway.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "vpnGateway": { + "type": "Microsoft.Network/vpnGateways", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "connections", + "count": "[length(parameters('vpnConnections'))]", + "input": { + "name": "[parameters('vpnConnections')[copyIndex('connections')].name]", + "properties": { + "connectionBandwidth": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'connectionBandwidth')]", + "enableBgp": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'enableBgp')]", + "enableInternetSecurity": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'enableInternetSecurity')]", + "remoteVpnSite": "[if(contains(parameters('vpnConnections')[copyIndex('connections')], 'remoteVpnSiteResourceId'), createObject('id', parameters('vpnConnections')[copyIndex('connections')].remoteVpnSiteResourceId), null())]", + "enableRateLimiting": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'enableRateLimiting')]", + "routingConfiguration": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'routingConfiguration')]", + "routingWeight": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'routingWeight')]", + "sharedKey": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'sharedKey')]", + "useLocalAzureIpAddress": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'useLocalAzureIpAddress')]", + "usePolicyBasedTrafficSelectors": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'usePolicyBasedTrafficSelectors')]", + "vpnConnectionProtocolType": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'vpnConnectionProtocolType')]", + "ipsecPolicies": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'ipsecPolicies')]", + "trafficSelectorPolicies": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'trafficSelectorPolicies')]", + "vpnLinkConnections": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'vpnLinkConnections')]" + } + } + } + ], + "bgpSettings": "[parameters('bgpSettings')]", + "enableBgpRouteTranslationForNat": "[parameters('enableBgpRouteTranslationForNat')]", + "isRoutingPreferenceInternet": "[parameters('isRoutingPreferenceInternet')]", + "vpnGatewayScaleUnit": "[parameters('vpnGatewayScaleUnit')]", + "virtualHub": { + "id": "[parameters('virtualHubResourceId')]" + } + } + }, + "vpnGateway_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/vpnGateways/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "vpnGateway" + ] + }, + "vpnGateway_natRules": { + "copy": { + "name": "vpnGateway_natRules", + "count": "[length(parameters('natRules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NATRule-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('natRules')[copyIndex()].name]" + }, + "vpnGatewayName": { + "value": "[parameters('name')]" + }, + "externalMappings": { + "value": "[tryGet(parameters('natRules')[copyIndex()], 'externalMappings')]" + }, + "internalMappings": { + "value": "[tryGet(parameters('natRules')[copyIndex()], 'internalMappings')]" + }, + "ipConfigurationId": { + "value": "[tryGet(parameters('natRules')[copyIndex()], 'ipConfigurationId')]" + }, + "mode": { + "value": "[tryGet(parameters('natRules')[copyIndex()], 'mode')]" + }, + "type": { + "value": "[tryGet(parameters('natRules')[copyIndex()], 'type')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "11380942489395706225" + }, + "name": "VPN Gateway NAT Rules", + "description": "This module deploys a VPN Gateway NAT Rule." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NAT rule." + } + }, + "vpnGatewayName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent VPN gateway this NAT rule is associated with. Required if the template is used in a standalone deployment." + } + }, + "externalMappings": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An address prefix range of destination IPs on the outside network that source IPs will be mapped to. In other words, your post-NAT address prefix range." + } + }, + "internalMappings": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An address prefix range of source IPs on the inside network that will be mapped to a set of external IPs. In other words, your pre-NAT address prefix range." + } + }, + "ipConfigurationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A NAT rule must be configured to a specific VPN Gateway instance. This is applicable to Dynamic NAT only. Static NAT rules are automatically applied to both VPN Gateway instances." + } + }, + "mode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "EgressSnat", + "IngressSnat" + ], + "metadata": { + "description": "Optional. The type of NAT rule for VPN NAT. IngressSnat mode (also known as Ingress Source NAT) is applicable to traffic entering the Azure hub's site-to-site VPN gateway. EgressSnat mode (also known as Egress Source NAT) is applicable to traffic leaving the Azure hub's Site-to-site VPN gateway." + } + }, + "type": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The type of NAT rule for VPN NAT. Static one-to-one NAT establishes a one-to-one relationship between an internal address and an external address while Dynamic NAT assigns an IP and port based on availability." + } + } + }, + "resources": { + "vpnGateway": { + "existing": true, + "type": "Microsoft.Network/vpnGateways", + "apiVersion": "2023-04-01", + "name": "[parameters('vpnGatewayName')]" + }, + "natRule": { + "type": "Microsoft.Network/vpnGateways/natRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('vpnGatewayName'), parameters('name'))]", + "properties": { + "externalMappings": "[parameters('externalMappings')]", + "internalMappings": "[parameters('internalMappings')]", + "ipConfigurationId": "[parameters('ipConfigurationId')]", + "mode": "[parameters('mode')]", + "type": "[parameters('type')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the NAT rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the NAT rule." + }, + "value": "[resourceId('Microsoft.Network/vpnGateways/natRules', parameters('vpnGatewayName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the NAT rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "vpnGateway" + ] + }, + "vpnGateway_vpnConnections": { + "copy": { + "name": "vpnGateway_vpnConnections", + "count": "[length(parameters('vpnConnections'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Connection-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('vpnConnections')[copyIndex()].name]" + }, + "vpnGatewayName": { + "value": "[parameters('name')]" + }, + "connectionBandwidth": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'connectionBandwidth')]" + }, + "enableBgp": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'enableBgp')]" + }, + "enableInternetSecurity": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'enableInternetSecurity')]" + }, + "remoteVpnSiteResourceId": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'remoteVpnSiteResourceId')]" + }, + "enableRateLimiting": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'enableRateLimiting')]" + }, + "routingConfiguration": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'routingConfiguration')]" + }, + "routingWeight": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'routingWeight')]" + }, + "sharedKey": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'sharedKey')]" + }, + "useLocalAzureIpAddress": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'useLocalAzureIpAddress')]" + }, + "usePolicyBasedTrafficSelectors": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'usePolicyBasedTrafficSelectors')]" + }, + "vpnConnectionProtocolType": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'vpnConnectionProtocolType')]" + }, + "ipsecPolicies": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'ipsecPolicies')]" + }, + "trafficSelectorPolicies": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'trafficSelectorPolicies')]" + }, + "vpnLinkConnections": { + "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'vpnLinkConnections')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "6343342170986309278" + }, + "name": "VPN Gateway VPN Connections", + "description": "This module deploys a VPN Gateway VPN Connection." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the VPN connection." + } + }, + "vpnGatewayName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent VPN gateway this VPN connection is associated with. Required if the template is used in a standalone deployment." + } + }, + "ipsecPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The IPSec policies to be considered by this connection." + } + }, + "trafficSelectorPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The traffic selector policies to be considered by this connection." + } + }, + "vpnLinkConnections": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of all VPN site link connections to the gateway." + } + }, + "routingConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Routing configuration indicating the associated and propagated route tables for this connection." + } + }, + "usePolicyBasedTrafficSelectors": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable policy-based traffic selectors." + } + }, + "useLocalAzureIpAddress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Use local Azure IP to initiate connection." + } + }, + "enableRateLimiting": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable rate limiting." + } + }, + "enableInternetSecurity": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable internet security." + } + }, + "enableBgp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable BGP flag." + } + }, + "routingWeight": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Routing weight for VPN connection." + } + }, + "connectionBandwidth": { + "type": "int", + "defaultValue": 10, + "metadata": { + "description": "Optional. Expected bandwidth in MBPS." + } + }, + "vpnConnectionProtocolType": { + "type": "string", + "defaultValue": "IKEv2", + "allowedValues": [ + "IKEv1", + "IKEv2" + ], + "metadata": { + "description": "Optional. Gateway connection protocol." + } + }, + "sharedKey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. SharedKey for the VPN connection." + } + }, + "remoteVpnSiteResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Reference to a VPN site to link to." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/vpnGateways/vpnConnections", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('vpnGatewayName'), parameters('name'))]", + "properties": { + "connectionBandwidth": "[parameters('connectionBandwidth')]", + "enableBgp": "[parameters('enableBgp')]", + "enableInternetSecurity": "[parameters('enableInternetSecurity')]", + "enableRateLimiting": "[parameters('enableRateLimiting')]", + "ipsecPolicies": "[parameters('ipsecPolicies')]", + "remoteVpnSite": "[if(not(empty(parameters('remoteVpnSiteResourceId'))), createObject('id', parameters('remoteVpnSiteResourceId')), null())]", + "routingConfiguration": "[parameters('routingConfiguration')]", + "routingWeight": "[parameters('routingWeight')]", + "sharedKey": "[parameters('sharedKey')]", + "trafficSelectorPolicies": "[parameters('trafficSelectorPolicies')]", + "useLocalAzureIpAddress": "[parameters('useLocalAzureIpAddress')]", + "usePolicyBasedTrafficSelectors": "[parameters('usePolicyBasedTrafficSelectors')]", + "vpnConnectionProtocolType": "[parameters('vpnConnectionProtocolType')]", + "vpnLinkConnections": "[parameters('vpnLinkConnections')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the VPN connection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the VPN connection." + }, + "value": "[resourceId('Microsoft.Network/vpnGateways/vpnConnections', parameters('vpnGatewayName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the VPN connection was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "vpnGateway" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the VPN gateway." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the VPN gateway." + }, + "value": "[resourceId('Microsoft.Network/vpnGateways', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the VPN gateway was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vpnGateway', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/vpn-gateway/nat-rule/README.md b/avm/1.1.0/res/network/vpn-gateway/nat-rule/README.md new file mode 100644 index 000000000..94beb1b84 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/nat-rule/README.md @@ -0,0 +1,112 @@ +# VPN Gateway NAT Rules `[Microsoft.Network/vpnGateways/natRules]` + +This module deploys a VPN Gateway NAT Rule. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/vpnGateways/natRules` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/vpnGateways/natRules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the NAT rule. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`vpnGatewayName`](#parameter-vpngatewayname) | string | The name of the parent VPN gateway this NAT rule is associated with. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`externalMappings`](#parameter-externalmappings) | array | An address prefix range of destination IPs on the outside network that source IPs will be mapped to. In other words, your post-NAT address prefix range. | +| [`internalMappings`](#parameter-internalmappings) | array | An address prefix range of source IPs on the inside network that will be mapped to a set of external IPs. In other words, your pre-NAT address prefix range. | +| [`ipConfigurationId`](#parameter-ipconfigurationid) | string | A NAT rule must be configured to a specific VPN Gateway instance. This is applicable to Dynamic NAT only. Static NAT rules are automatically applied to both VPN Gateway instances. | +| [`mode`](#parameter-mode) | string | The type of NAT rule for VPN NAT. IngressSnat mode (also known as Ingress Source NAT) is applicable to traffic entering the Azure hub's site-to-site VPN gateway. EgressSnat mode (also known as Egress Source NAT) is applicable to traffic leaving the Azure hub's Site-to-site VPN gateway. | +| [`type`](#parameter-type) | string | The type of NAT rule for VPN NAT. Static one-to-one NAT establishes a one-to-one relationship between an internal address and an external address while Dynamic NAT assigns an IP and port based on availability. | + +### Parameter: `name` + +The name of the NAT rule. + +- Required: Yes +- Type: string + +### Parameter: `vpnGatewayName` + +The name of the parent VPN gateway this NAT rule is associated with. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `externalMappings` + +An address prefix range of destination IPs on the outside network that source IPs will be mapped to. In other words, your post-NAT address prefix range. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `internalMappings` + +An address prefix range of source IPs on the inside network that will be mapped to a set of external IPs. In other words, your pre-NAT address prefix range. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `ipConfigurationId` + +A NAT rule must be configured to a specific VPN Gateway instance. This is applicable to Dynamic NAT only. Static NAT rules are automatically applied to both VPN Gateway instances. + +- Required: No +- Type: string + +### Parameter: `mode` + +The type of NAT rule for VPN NAT. IngressSnat mode (also known as Ingress Source NAT) is applicable to traffic entering the Azure hub's site-to-site VPN gateway. EgressSnat mode (also known as Egress Source NAT) is applicable to traffic leaving the Azure hub's Site-to-site VPN gateway. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'EgressSnat' + 'IngressSnat' + ] + ``` + +### Parameter: `type` + +The type of NAT rule for VPN NAT. Static one-to-one NAT establishes a one-to-one relationship between an internal address and an external address while Dynamic NAT assigns an IP and port based on availability. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Dynamic' + 'Static' + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the NAT rule. | +| `resourceGroupName` | string | The name of the resource group the NAT rule was deployed into. | +| `resourceId` | string | The resource ID of the NAT rule. | diff --git a/avm/1.1.0/res/network/vpn-gateway/nat-rule/main.bicep b/avm/1.1.0/res/network/vpn-gateway/nat-rule/main.bicep new file mode 100644 index 000000000..aa61727b2 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/nat-rule/main.bicep @@ -0,0 +1,56 @@ +metadata name = 'VPN Gateway NAT Rules' +metadata description = 'This module deploys a VPN Gateway NAT Rule.' + +@description('Required. The name of the NAT rule.') +param name string + +@description('Conditional. The name of the parent VPN gateway this NAT rule is associated with. Required if the template is used in a standalone deployment.') +param vpnGatewayName string + +@description('Optional. An address prefix range of destination IPs on the outside network that source IPs will be mapped to. In other words, your post-NAT address prefix range.') +param externalMappings array = [] + +@description('Optional. An address prefix range of source IPs on the inside network that will be mapped to a set of external IPs. In other words, your pre-NAT address prefix range.') +param internalMappings array = [] + +@description('Optional. A NAT rule must be configured to a specific VPN Gateway instance. This is applicable to Dynamic NAT only. Static NAT rules are automatically applied to both VPN Gateway instances.') +param ipConfigurationId string? + +@description('Optional. The type of NAT rule for VPN NAT. IngressSnat mode (also known as Ingress Source NAT) is applicable to traffic entering the Azure hub\'s site-to-site VPN gateway. EgressSnat mode (also known as Egress Source NAT) is applicable to traffic leaving the Azure hub\'s Site-to-site VPN gateway.') +@allowed([ + 'EgressSnat' + 'IngressSnat' +]) +param mode string? + +@description('Optional. The type of NAT rule for VPN NAT. Static one-to-one NAT establishes a one-to-one relationship between an internal address and an external address while Dynamic NAT assigns an IP and port based on availability.') +@allowed([ + 'Dynamic' + 'Static' +]) +param type string? + +resource vpnGateway 'Microsoft.Network/vpnGateways@2023-04-01' existing = { + name: vpnGatewayName +} + +resource natRule 'Microsoft.Network/vpnGateways/natRules@2023-04-01' = { + name: name + parent: vpnGateway + properties: { + externalMappings: externalMappings + internalMappings: internalMappings + ipConfigurationId: ipConfigurationId + mode: mode + type: type + } +} + +@description('The name of the NAT rule.') +output name string = natRule.name + +@description('The resource ID of the NAT rule.') +output resourceId string = natRule.id + +@description('The name of the resource group the NAT rule was deployed into.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/network/vpn-gateway/nat-rule/main.json b/avm/1.1.0/res/network/vpn-gateway/nat-rule/main.json new file mode 100644 index 000000000..dd5e884be --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/nat-rule/main.json @@ -0,0 +1,114 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "11380942489395706225" + }, + "name": "VPN Gateway NAT Rules", + "description": "This module deploys a VPN Gateway NAT Rule." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NAT rule." + } + }, + "vpnGatewayName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent VPN gateway this NAT rule is associated with. Required if the template is used in a standalone deployment." + } + }, + "externalMappings": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An address prefix range of destination IPs on the outside network that source IPs will be mapped to. In other words, your post-NAT address prefix range." + } + }, + "internalMappings": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An address prefix range of source IPs on the inside network that will be mapped to a set of external IPs. In other words, your pre-NAT address prefix range." + } + }, + "ipConfigurationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A NAT rule must be configured to a specific VPN Gateway instance. This is applicable to Dynamic NAT only. Static NAT rules are automatically applied to both VPN Gateway instances." + } + }, + "mode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "EgressSnat", + "IngressSnat" + ], + "metadata": { + "description": "Optional. The type of NAT rule for VPN NAT. IngressSnat mode (also known as Ingress Source NAT) is applicable to traffic entering the Azure hub's site-to-site VPN gateway. EgressSnat mode (also known as Egress Source NAT) is applicable to traffic leaving the Azure hub's Site-to-site VPN gateway." + } + }, + "type": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The type of NAT rule for VPN NAT. Static one-to-one NAT establishes a one-to-one relationship between an internal address and an external address while Dynamic NAT assigns an IP and port based on availability." + } + } + }, + "resources": { + "vpnGateway": { + "existing": true, + "type": "Microsoft.Network/vpnGateways", + "apiVersion": "2023-04-01", + "name": "[parameters('vpnGatewayName')]" + }, + "natRule": { + "type": "Microsoft.Network/vpnGateways/natRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('vpnGatewayName'), parameters('name'))]", + "properties": { + "externalMappings": "[parameters('externalMappings')]", + "internalMappings": "[parameters('internalMappings')]", + "ipConfigurationId": "[parameters('ipConfigurationId')]", + "mode": "[parameters('mode')]", + "type": "[parameters('type')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the NAT rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the NAT rule." + }, + "value": "[resourceId('Microsoft.Network/vpnGateways/natRules', parameters('vpnGatewayName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the NAT rule was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/vpn-gateway/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/vpn-gateway/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..3b2439f31 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,27 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Optional. The name of the Virtual Hub to create.') +param virtualHubName string + +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +resource virtualHub 'Microsoft.Network/virtualHubs@2022-01-01' = { + name: virtualHubName + location: location + properties: { + virtualWan: { + id: virtualWan.id + } + addressPrefix: '10.1.0.0/16' + } +} + +@description('The resource ID of the created Virtual Hub.') +output virtualHubResourceId string = virtualHub.id diff --git a/avm/1.1.0/res/network/vpn-gateway/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/vpn-gateway/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..1106c5eab --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,58 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.vpngateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'vpngmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualHubName: 'dep-${namePrefix}-vh-${serviceShort}' + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + virtualHubResourceId: nestedDependencies.outputs.virtualHubResourceId + } + } +] diff --git a/avm/1.1.0/res/network/vpn-gateway/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/vpn-gateway/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..a15b26838 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/tests/e2e/max/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Optional. The name of the Virtual Hub to create.') +param virtualHubName string + +@description('Optional. The name of the VPN Site to create.') +param vpnSiteName string + +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +resource virtualHub 'Microsoft.Network/virtualHubs@2022-01-01' = { + name: virtualHubName + location: location + properties: { + virtualWan: { + id: virtualWan.id + } + addressPrefix: '10.0.0.0/24' + } +} + +resource vpnSite 'Microsoft.Network/vpnSites@2023-04-01' = { + name: vpnSiteName + location: location + properties: { + virtualWan: { + id: virtualWan.id + } + addressSpace: { + addressPrefixes: [ + '10.1.0.0/16' + ] + } + ipAddress: '10.1.0.0' + } +} + +@description('The resource ID of the created Virtual Hub.') +output virtualHubResourceId string = virtualHub.id + +@description('The resource ID of the created VPN site.') +output vpnSiteResourceId string = vpnSite.id diff --git a/avm/1.1.0/res/network/vpn-gateway/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/vpn-gateway/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..5f0696cb0 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/tests/e2e/max/main.test.bicep @@ -0,0 +1,103 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.vpngateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'vpngmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualHubName: 'dep-${namePrefix}-vh-${serviceShort}' + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + vpnSiteName: 'dep-${namePrefix}-vs-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualHubResourceId: nestedDependencies.outputs.virtualHubResourceId + bgpSettings: { + asn: 65515 + peerWeight: 0 + } + vpnConnections: [ + { + connectionBandwidth: 100 + enableBgp: false + name: 'Connection-${last(split(nestedDependencies.outputs.vpnSiteResourceId, '/'))}' + remoteVpnSiteResourceId: nestedDependencies.outputs.vpnSiteResourceId + enableInternetSecurity: true + vpnConnectionProtocolType: 'IKEv2' + enableRateLimiting: false + useLocalAzureIpAddress: false + usePolicyBasedTrafficSelectors: false + routingWeight: 0 + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + natRules: [ + { + externalMappings: [ + { + addressSpace: '192.168.21.0/24' + } + ] + internalMappings: [ + { + addressSpace: '10.4.0.0/24' + } + ] + mode: 'EgressSnat' + name: 'natRule1' + type: 'Static' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/vpn-gateway/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/vpn-gateway/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..a15b26838 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Optional. The name of the Virtual Hub to create.') +param virtualHubName string + +@description('Optional. The name of the VPN Site to create.') +param vpnSiteName string + +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +resource virtualHub 'Microsoft.Network/virtualHubs@2022-01-01' = { + name: virtualHubName + location: location + properties: { + virtualWan: { + id: virtualWan.id + } + addressPrefix: '10.0.0.0/24' + } +} + +resource vpnSite 'Microsoft.Network/vpnSites@2023-04-01' = { + name: vpnSiteName + location: location + properties: { + virtualWan: { + id: virtualWan.id + } + addressSpace: { + addressPrefixes: [ + '10.1.0.0/16' + ] + } + ipAddress: '10.1.0.0' + } +} + +@description('The resource ID of the created Virtual Hub.') +output virtualHubResourceId string = virtualHub.id + +@description('The resource ID of the created VPN site.') +output vpnSiteResourceId string = vpnSite.id diff --git a/avm/1.1.0/res/network/vpn-gateway/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/vpn-gateway/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..db69482e5 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,99 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.vpngateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'vpngwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualHubName: 'dep-${namePrefix}-vh-${serviceShort}' + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + vpnSiteName: 'dep-${namePrefix}-vs-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualHubResourceId: nestedDependencies.outputs.virtualHubResourceId + bgpSettings: { + asn: 65515 + peerWeight: 0 + } + vpnConnections: [ + { + connectionBandwidth: 100 + enableBgp: false + name: 'Connection-${last(split(nestedDependencies.outputs.vpnSiteResourceId, '/'))}' + remoteVpnSiteResourceId: nestedDependencies.outputs.vpnSiteResourceId + enableInternetSecurity: true + vpnConnectionProtocolType: 'IKEv2' + enableRateLimiting: false + useLocalAzureIpAddress: false + usePolicyBasedTrafficSelectors: false + routingWeight: 0 + } + ] + natRules: [ + { + externalMappings: [ + { + addressSpace: '192.168.21.0/24' + } + ] + internalMappings: [ + { + addressSpace: '10.4.0.0/24' + } + ] + mode: 'EgressSnat' + name: 'natRule1' + type: 'Static' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/network/vpn-gateway/version.json b/avm/1.1.0/res/network/vpn-gateway/version.json new file mode 100644 index 000000000..8def869ed --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/res/network/vpn-gateway/vpn-connection/README.md b/avm/1.1.0/res/network/vpn-gateway/vpn-connection/README.md new file mode 100644 index 000000000..b11268ff3 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/vpn-connection/README.md @@ -0,0 +1,249 @@ +# VPN Gateway VPN Connections `[Microsoft.Network/vpnGateways/vpnConnections]` + +This module deploys a VPN Gateway VPN Connection. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Notes](#Notes) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/vpnGateways/vpnConnections` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/vpnGateways/vpnConnections) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the VPN connection. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`vpnGatewayName`](#parameter-vpngatewayname) | string | The name of the parent VPN gateway this VPN connection is associated with. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`connectionBandwidth`](#parameter-connectionbandwidth) | int | Expected bandwidth in MBPS. | +| [`enableBgp`](#parameter-enablebgp) | bool | Enable BGP flag. | +| [`enableInternetSecurity`](#parameter-enableinternetsecurity) | bool | Enable internet security. | +| [`enableRateLimiting`](#parameter-enableratelimiting) | bool | Enable rate limiting. | +| [`ipsecPolicies`](#parameter-ipsecpolicies) | array | The IPSec policies to be considered by this connection. | +| [`remoteVpnSiteResourceId`](#parameter-remotevpnsiteresourceid) | string | Reference to a VPN site to link to. | +| [`routingConfiguration`](#parameter-routingconfiguration) | object | Routing configuration indicating the associated and propagated route tables for this connection. | +| [`routingWeight`](#parameter-routingweight) | int | Routing weight for VPN connection. | +| [`sharedKey`](#parameter-sharedkey) | securestring | SharedKey for the VPN connection. | +| [`trafficSelectorPolicies`](#parameter-trafficselectorpolicies) | array | The traffic selector policies to be considered by this connection. | +| [`useLocalAzureIpAddress`](#parameter-uselocalazureipaddress) | bool | Use local Azure IP to initiate connection. | +| [`usePolicyBasedTrafficSelectors`](#parameter-usepolicybasedtrafficselectors) | bool | Enable policy-based traffic selectors. | +| [`vpnConnectionProtocolType`](#parameter-vpnconnectionprotocoltype) | string | Gateway connection protocol. | +| [`vpnLinkConnections`](#parameter-vpnlinkconnections) | array | List of all VPN site link connections to the gateway. | + +### Parameter: `name` + +The name of the VPN connection. + +- Required: Yes +- Type: string + +### Parameter: `vpnGatewayName` + +The name of the parent VPN gateway this VPN connection is associated with. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `connectionBandwidth` + +Expected bandwidth in MBPS. + +- Required: No +- Type: int +- Default: `10` + +### Parameter: `enableBgp` + +Enable BGP flag. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableInternetSecurity` + +Enable internet security. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableRateLimiting` + +Enable rate limiting. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `ipsecPolicies` + +The IPSec policies to be considered by this connection. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `remoteVpnSiteResourceId` + +Reference to a VPN site to link to. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `routingConfiguration` + +Routing configuration indicating the associated and propagated route tables for this connection. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `routingWeight` + +Routing weight for VPN connection. + +- Required: No +- Type: int +- Default: `0` + +### Parameter: `sharedKey` + +SharedKey for the VPN connection. + +- Required: No +- Type: securestring +- Default: `''` + +### Parameter: `trafficSelectorPolicies` + +The traffic selector policies to be considered by this connection. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `useLocalAzureIpAddress` + +Use local Azure IP to initiate connection. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `usePolicyBasedTrafficSelectors` + +Enable policy-based traffic selectors. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `vpnConnectionProtocolType` + +Gateway connection protocol. + +- Required: No +- Type: string +- Default: `'IKEv2'` +- Allowed: + ```Bicep + [ + 'IKEv1' + 'IKEv2' + ] + ``` + +### Parameter: `vpnLinkConnections` + +List of all VPN site link connections to the gateway. + +- Required: No +- Type: array +- Default: `[]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the VPN connection. | +| `resourceGroupName` | string | The name of the resource group the VPN connection was deployed into. | +| `resourceId` | string | The resource ID of the VPN connection. | + +## Notes + +### Parameter Usage: `routingConfiguration` + +

+ +Parameter JSON format + +```json +"routingConfiguration": { + "associatedRouteTable": { + "id": "/subscriptions/[[subscriptionId]]/resourceGroups/validation-rg/providers/Microsoft.Network/virtualHubs/SampleVirtualHub/hubRouteTables/defaultRouteTable" + }, + "propagatedRouteTables": { + "labels": [ + "default" + ], + "ids": [ + { + "id": "/subscriptions/[[subscriptionId]]/resourceGroups/validation-rg/providers/Microsoft.Network/virtualHubs/SampleVirtualHub/hubRouteTables/defaultRouteTable" + } + ] + }, + "vnetRoutes": { + "staticRoutes": [] + } +} +``` + +
+ +
+ +Bicep format + +```bicep +routingConfiguration: { + associatedRouteTable: { + id: '/subscriptions/[[subscriptionId]]/resourceGroups/validation-rg/providers/Microsoft.Network/virtualHubs/SampleVirtualHub/hubRouteTables/defaultRouteTable' + } + propagatedRouteTables: { + labels: [ + 'default' + ] + ids: [ + { + id: '/subscriptions/[[subscriptionId]]/resourceGroups/validation-rg/providers/Microsoft.Network/virtualHubs/SampleVirtualHub/hubRouteTables/defaultRouteTable' + } + ] + } + vnetRoutes: { + staticRoutes: [] + } +} +``` + +
+

diff --git a/avm/1.1.0/res/network/vpn-gateway/vpn-connection/main.bicep b/avm/1.1.0/res/network/vpn-gateway/vpn-connection/main.bicep new file mode 100644 index 000000000..bc1909661 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/vpn-connection/main.bicep @@ -0,0 +1,93 @@ +metadata name = 'VPN Gateway VPN Connections' +metadata description = 'This module deploys a VPN Gateway VPN Connection.' + +@description('Required. The name of the VPN connection.') +param name string + +@description('Conditional. The name of the parent VPN gateway this VPN connection is associated with. Required if the template is used in a standalone deployment.') +param vpnGatewayName string + +@description('Optional. The IPSec policies to be considered by this connection.') +param ipsecPolicies array = [] + +@description('Optional. The traffic selector policies to be considered by this connection.') +param trafficSelectorPolicies array = [] + +@description('Optional. List of all VPN site link connections to the gateway.') +param vpnLinkConnections array = [] + +@description('Optional. Routing configuration indicating the associated and propagated route tables for this connection.') +param routingConfiguration object = {} + +@description('Optional. Enable policy-based traffic selectors.') +param usePolicyBasedTrafficSelectors bool = false + +@description('Optional. Use local Azure IP to initiate connection.') +param useLocalAzureIpAddress bool = false + +@description('Optional. Enable rate limiting.') +param enableRateLimiting bool = false + +@description('Optional. Enable internet security.') +param enableInternetSecurity bool = false + +@description('Optional. Enable BGP flag.') +param enableBgp bool = false + +@description('Optional. Routing weight for VPN connection.') +param routingWeight int = 0 + +@description('Optional. Expected bandwidth in MBPS.') +param connectionBandwidth int = 10 + +@description('Optional. Gateway connection protocol.') +@allowed([ + 'IKEv1' + 'IKEv2' +]) +param vpnConnectionProtocolType string = 'IKEv2' + +@description('Optional. SharedKey for the VPN connection.') +@secure() +param sharedKey string = '' + +@description('Optional. Reference to a VPN site to link to.') +param remoteVpnSiteResourceId string = '' + +resource vpnGateway 'Microsoft.Network/vpnGateways@2023-04-01' existing = { + name: vpnGatewayName +} + +resource vpnConnection 'Microsoft.Network/vpnGateways/vpnConnections@2023-04-01' = { + name: name + parent: vpnGateway + properties: { + connectionBandwidth: connectionBandwidth + enableBgp: enableBgp + enableInternetSecurity: enableInternetSecurity + enableRateLimiting: enableRateLimiting + ipsecPolicies: ipsecPolicies + remoteVpnSite: !empty(remoteVpnSiteResourceId) + ? { + id: remoteVpnSiteResourceId + } + : null + routingConfiguration: routingConfiguration + routingWeight: routingWeight + sharedKey: sharedKey + trafficSelectorPolicies: trafficSelectorPolicies + useLocalAzureIpAddress: useLocalAzureIpAddress + usePolicyBasedTrafficSelectors: usePolicyBasedTrafficSelectors + vpnConnectionProtocolType: vpnConnectionProtocolType + vpnLinkConnections: vpnLinkConnections + } +} + +@description('The name of the VPN connection.') +output name string = vpnConnection.name + +@description('The resource ID of the VPN connection.') +output resourceId string = vpnConnection.id + +@description('The name of the resource group the VPN connection was deployed into.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/network/vpn-gateway/vpn-connection/main.json b/avm/1.1.0/res/network/vpn-gateway/vpn-connection/main.json new file mode 100644 index 000000000..f345f8e83 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-gateway/vpn-connection/main.json @@ -0,0 +1,175 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "6343342170986309278" + }, + "name": "VPN Gateway VPN Connections", + "description": "This module deploys a VPN Gateway VPN Connection." + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the VPN connection." + } + }, + "vpnGatewayName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent VPN gateway this VPN connection is associated with. Required if the template is used in a standalone deployment." + } + }, + "ipsecPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The IPSec policies to be considered by this connection." + } + }, + "trafficSelectorPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The traffic selector policies to be considered by this connection." + } + }, + "vpnLinkConnections": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of all VPN site link connections to the gateway." + } + }, + "routingConfiguration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Routing configuration indicating the associated and propagated route tables for this connection." + } + }, + "usePolicyBasedTrafficSelectors": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable policy-based traffic selectors." + } + }, + "useLocalAzureIpAddress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Use local Azure IP to initiate connection." + } + }, + "enableRateLimiting": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable rate limiting." + } + }, + "enableInternetSecurity": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable internet security." + } + }, + "enableBgp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable BGP flag." + } + }, + "routingWeight": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Routing weight for VPN connection." + } + }, + "connectionBandwidth": { + "type": "int", + "defaultValue": 10, + "metadata": { + "description": "Optional. Expected bandwidth in MBPS." + } + }, + "vpnConnectionProtocolType": { + "type": "string", + "defaultValue": "IKEv2", + "allowedValues": [ + "IKEv1", + "IKEv2" + ], + "metadata": { + "description": "Optional. Gateway connection protocol." + } + }, + "sharedKey": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. SharedKey for the VPN connection." + } + }, + "remoteVpnSiteResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Reference to a VPN site to link to." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/vpnGateways/vpnConnections", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('vpnGatewayName'), parameters('name'))]", + "properties": { + "connectionBandwidth": "[parameters('connectionBandwidth')]", + "enableBgp": "[parameters('enableBgp')]", + "enableInternetSecurity": "[parameters('enableInternetSecurity')]", + "enableRateLimiting": "[parameters('enableRateLimiting')]", + "ipsecPolicies": "[parameters('ipsecPolicies')]", + "remoteVpnSite": "[if(not(empty(parameters('remoteVpnSiteResourceId'))), createObject('id', parameters('remoteVpnSiteResourceId')), null())]", + "routingConfiguration": "[parameters('routingConfiguration')]", + "routingWeight": "[parameters('routingWeight')]", + "sharedKey": "[parameters('sharedKey')]", + "trafficSelectorPolicies": "[parameters('trafficSelectorPolicies')]", + "useLocalAzureIpAddress": "[parameters('useLocalAzureIpAddress')]", + "usePolicyBasedTrafficSelectors": "[parameters('usePolicyBasedTrafficSelectors')]", + "vpnConnectionProtocolType": "[parameters('vpnConnectionProtocolType')]", + "vpnLinkConnections": "[parameters('vpnLinkConnections')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the VPN connection." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the VPN connection." + }, + "value": "[resourceId('Microsoft.Network/vpnGateways/vpnConnections', parameters('vpnGatewayName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the VPN connection was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/vpn-server-configuration/README.md b/avm/1.1.0/res/network/vpn-server-configuration/README.md new file mode 100644 index 000000000..75a22b40b --- /dev/null +++ b/avm/1.1.0/res/network/vpn-server-configuration/README.md @@ -0,0 +1,1021 @@ +# VPN Server Configuration `[Microsoft.Network/vpnServerConfigurations]` + +This module deploys a VPN Server Configuration for a Virtual Hub P2S Gateway. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Network/vpnServerConfigurations` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/vpnServerConfigurations) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/vpn-server-configuration:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module vpnServerConfiguration 'br/public:avm/res/network/vpn-server-configuration:' = { + name: 'vpnServerConfigurationDeployment' + params: { + // Required parameters + name: 'vscminVPNConfig' + // Non-required parameters + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: '' + p2sConfigurationPolicyGroups: [ + { + isDefault: 'true' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + name: 'UserGroup1' + } + ] + priority: '0' + userVPNPolicyGroupName: 'DefaultGroup' + } + ] + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnProtocols: [ + 'OpenVPN' + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "vscminVPNConfig" + }, + // Non-required parameters + "aadAudience": { + "value": "11111111-1234-4321-1234-111111111111" + }, + "aadIssuer": { + "value": "https://sts.windows.net/11111111-1111-1111-1111-111111111111/" + }, + "aadTenant": { + "value": "" + }, + "p2sConfigurationPolicyGroups": { + "value": [ + { + "isDefault": "true", + "policymembers": [ + { + "attributeType": "AADGroupId", + "attributeValue": "11111111-1111-2222-3333-111111111111", + "name": "UserGroup1" + } + ], + "priority": "0", + "userVPNPolicyGroupName": "DefaultGroup" + } + ] + }, + "vpnAuthenticationTypes": { + "value": [ + "AAD" + ] + }, + "vpnProtocols": { + "value": [ + "OpenVPN" + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-server-configuration:' + +// Required parameters +param name = 'vscminVPNConfig' +// Non-required parameters +param aadAudience = '11111111-1234-4321-1234-111111111111' +param aadIssuer = 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' +param aadTenant = '' +p2sConfigurationPolicyGroups: [ + { + isDefault: 'true' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + name: 'UserGroup1' + } + ] + priority: '0' + userVPNPolicyGroupName: 'DefaultGroup' + } +] +param vpnAuthenticationTypes = [ + 'AAD' +] +param vpnProtocols = [ + 'OpenVPN' +] +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module vpnServerConfiguration 'br/public:avm/res/network/vpn-server-configuration:' = { + name: 'vpnServerConfigurationDeployment' + params: { + // Required parameters + name: 'vscmaxVPNConfig' + // Non-required parameters + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: '' + location: '' + p2sConfigurationPolicyGroups: [ + { + isDefault: 'true' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + name: 'UserGroup1' + } + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-3333-4444-111111111111' + name: 'UserGroup2' + } + ] + priority: '0' + userVPNPolicyGroupName: 'DefaultGroup' + } + { + isDefault: 'false' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-4444-5555-111111111111' + name: 'UserGroup3' + } + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-5555-6666-111111111111' + name: 'UserGroup4' + } + ] + priority: '1' + userVPNPolicyGroupName: 'AdditionalGroup' + } + ] + radiusClientRootCertificates: [ + { + name: 'TestRadiusClientRevokedCert' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b59aa' + } + ] + radiusServerRootCertificates: [ + { + name: 'TestRadiusRootCert' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + ] + radiusServers: [ + { + radiusServerAddress: '10.150.1.50' + radiusServerScore: '10' + radiusServerSecret: 'TestSecret' + } + { + radiusServerAddress: '10.150.1.150' + radiusServerScore: '20' + radiusServerSecret: 'TestSecret2' + } + ] + vpnAuthenticationTypes: [ + 'AAD' + 'Certificate' + 'Radius' + ] + vpnClientIpsecPolicies: [ + { + dhGroup: 'DHGroup14' + ikeEncryption: 'AES256' + ikeIntegrity: 'SHA256' + ipsecEncryption: 'AES256' + ipsecIntegrity: 'SHA256' + pfsGroup: 'PFS14' + saDataSizeKilobytes: 0 + saLifeTimeSeconds: 27000 + } + ] + vpnClientRevokedCertificates: [ + { + name: 'TestRevokedCert' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b69aa' + } + { + name: 'TestRevokedCert2' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b69bb' + } + ] + vpnClientRootCertificates: [ + { + name: 'TestRootCert' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + { + name: 'TestRootCert2' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcMARELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + ] + vpnProtocols: [ + 'OpenVPN' + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "vscmaxVPNConfig" + }, + // Non-required parameters + "aadAudience": { + "value": "11111111-1234-4321-1234-111111111111" + }, + "aadIssuer": { + "value": "https://sts.windows.net/11111111-1111-1111-1111-111111111111/" + }, + "aadTenant": { + "value": "" + }, + "location": { + "value": "" + }, + "p2sConfigurationPolicyGroups": { + "value": [ + { + "isDefault": "true", + "policymembers": [ + { + "attributeType": "AADGroupId", + "attributeValue": "11111111-1111-2222-3333-111111111111", + "name": "UserGroup1" + }, + { + "attributeType": "AADGroupId", + "attributeValue": "11111111-1111-3333-4444-111111111111", + "name": "UserGroup2" + } + ], + "priority": "0", + "userVPNPolicyGroupName": "DefaultGroup" + }, + { + "isDefault": "false", + "policymembers": [ + { + "attributeType": "AADGroupId", + "attributeValue": "11111111-1111-4444-5555-111111111111", + "name": "UserGroup3" + }, + { + "attributeType": "AADGroupId", + "attributeValue": "11111111-1111-5555-6666-111111111111", + "name": "UserGroup4" + } + ], + "priority": "1", + "userVPNPolicyGroupName": "AdditionalGroup" + } + ] + }, + "radiusClientRootCertificates": { + "value": [ + { + "name": "TestRadiusClientRevokedCert", + "thumbprint": "1f24c630cda418ef2069ffad4fdd5f463a1b59aa" + } + ] + }, + "radiusServerRootCertificates": { + "value": [ + { + "name": "TestRadiusRootCert", + "publicCertData": "MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f" + } + ] + }, + "radiusServers": { + "value": [ + { + "radiusServerAddress": "10.150.1.50", + "radiusServerScore": "10", + "radiusServerSecret": "TestSecret" + }, + { + "radiusServerAddress": "10.150.1.150", + "radiusServerScore": "20", + "radiusServerSecret": "TestSecret2" + } + ] + }, + "vpnAuthenticationTypes": { + "value": [ + "AAD", + "Certificate", + "Radius" + ] + }, + "vpnClientIpsecPolicies": { + "value": [ + { + "dhGroup": "DHGroup14", + "ikeEncryption": "AES256", + "ikeIntegrity": "SHA256", + "ipsecEncryption": "AES256", + "ipsecIntegrity": "SHA256", + "pfsGroup": "PFS14", + "saDataSizeKilobytes": 0, + "saLifeTimeSeconds": 27000 + } + ] + }, + "vpnClientRevokedCertificates": { + "value": [ + { + "name": "TestRevokedCert", + "thumbprint": "1f24c630cda418ef2069ffad4fdd5f463a1b69aa" + }, + { + "name": "TestRevokedCert2", + "thumbprint": "1f24c630cda418ef2069ffad4fdd5f463a1b69bb" + } + ] + }, + "vpnClientRootCertificates": { + "value": [ + { + "name": "TestRootCert", + "publicCertData": "MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f" + }, + { + "name": "TestRootCert2", + "publicCertData": "MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcMARELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f" + } + ] + }, + "vpnProtocols": { + "value": [ + "OpenVPN" + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-server-configuration:' + +// Required parameters +param name = 'vscmaxVPNConfig' +// Non-required parameters +param aadAudience = '11111111-1234-4321-1234-111111111111' +param aadIssuer = 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' +param aadTenant = '' +param location = '' +p2sConfigurationPolicyGroups: [ + { + isDefault: 'true' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + name: 'UserGroup1' + } + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-3333-4444-111111111111' + name: 'UserGroup2' + } + ] + priority: '0' + userVPNPolicyGroupName: 'DefaultGroup' + } + { + isDefault: 'false' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-4444-5555-111111111111' + name: 'UserGroup3' + } + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-5555-6666-111111111111' + name: 'UserGroup4' + } + ] + priority: '1' + userVPNPolicyGroupName: 'AdditionalGroup' + } +] +param radiusClientRootCertificates = [ + { + name: 'TestRadiusClientRevokedCert' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b59aa' + } +] +param radiusServerRootCertificates = [ + { + name: 'TestRadiusRootCert' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } +] +param radiusServers = [ + { + radiusServerAddress: '10.150.1.50' + radiusServerScore: '10' + radiusServerSecret: 'TestSecret' + } + { + radiusServerAddress: '10.150.1.150' + radiusServerScore: '20' + radiusServerSecret: 'TestSecret2' + } +] +param vpnAuthenticationTypes = [ + 'AAD' + 'Certificate' + 'Radius' +] +param vpnClientIpsecPolicies = [ + { + dhGroup: 'DHGroup14' + ikeEncryption: 'AES256' + ikeIntegrity: 'SHA256' + ipsecEncryption: 'AES256' + ipsecIntegrity: 'SHA256' + pfsGroup: 'PFS14' + saDataSizeKilobytes: 0 + saLifeTimeSeconds: 27000 + } +] +param vpnClientRevokedCertificates = [ + { + name: 'TestRevokedCert' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b69aa' + } + { + name: 'TestRevokedCert2' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b69bb' + } +] +param vpnClientRootCertificates = [ + { + name: 'TestRootCert' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + { + name: 'TestRootCert2' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcMARELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } +] +param vpnProtocols = [ + 'OpenVPN' +] +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module vpnServerConfiguration 'br/public:avm/res/network/vpn-server-configuration:' = { + name: 'vpnServerConfigurationDeployment' + params: { + // Required parameters + name: 'vscwafVPNConfig' + // Non-required parameters + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: '' + p2sConfigurationPolicyGroups: [ + { + isDefault: 'true' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + name: 'UserGroup1' + } + ] + priority: '0' + userVPNPolicyGroupName: 'DefaultGroup' + } + ] + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnProtocols: [ + 'OpenVPN' + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "vscwafVPNConfig" + }, + // Non-required parameters + "aadAudience": { + "value": "11111111-1234-4321-1234-111111111111" + }, + "aadIssuer": { + "value": "https://sts.windows.net/11111111-1111-1111-1111-111111111111/" + }, + "aadTenant": { + "value": "" + }, + "p2sConfigurationPolicyGroups": { + "value": [ + { + "isDefault": "true", + "policymembers": [ + { + "attributeType": "AADGroupId", + "attributeValue": "11111111-1111-2222-3333-111111111111", + "name": "UserGroup1" + } + ], + "priority": "0", + "userVPNPolicyGroupName": "DefaultGroup" + } + ] + }, + "vpnAuthenticationTypes": { + "value": [ + "AAD" + ] + }, + "vpnProtocols": { + "value": [ + "OpenVPN" + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-server-configuration:' + +// Required parameters +param name = 'vscwafVPNConfig' +// Non-required parameters +param aadAudience = '11111111-1234-4321-1234-111111111111' +param aadIssuer = 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' +param aadTenant = '' +p2sConfigurationPolicyGroups: [ + { + isDefault: 'true' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + name: 'UserGroup1' + } + ] + priority: '0' + userVPNPolicyGroupName: 'DefaultGroup' + } +] +param vpnAuthenticationTypes = [ + 'AAD' +] +param vpnProtocols = [ + 'OpenVPN' +] +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the user VPN configuration. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`aadAudience`](#parameter-aadaudience) | string | The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication. | +| [`aadIssuer`](#parameter-aadissuer) | string | The issuer for the AAD/Entra authentication. Required if configuring Entra ID authentication. | +| [`aadTenant`](#parameter-aadtenant) | string | The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication. | +| [`radiusServerAddress`](#parameter-radiusserveraddress) | string | The address of the RADIUS server. Required if configuring a single RADIUS. | +| [`radiusServerSecret`](#parameter-radiusserversecret) | securestring | The RADIUS server secret. Required if configuring a single RADIUS server. | +| [`vpnClientRootCertificates`](#parameter-vpnclientrootcertificates) | array | The VPN Client root certificate public keys for the configuration. Required if using certificate authentication. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location where all resources will be created. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`p2sConfigurationPolicyGroups`](#parameter-p2sconfigurationpolicygroups) | array | The P2S configuration policy groups for the configuration. | +| [`radiusClientRootCertificates`](#parameter-radiusclientrootcertificates) | array | The revoked RADIUS client certificates for the configuration. | +| [`radiusServerRootCertificates`](#parameter-radiusserverrootcertificates) | array | The root certificates of the RADIUS server. | +| [`radiusServers`](#parameter-radiusservers) | array | The list of RADIUS servers. Required if configuring multiple RADIUS servers. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`vpnAuthenticationTypes`](#parameter-vpnauthenticationtypes) | array | The authentication types for the VPN configuration. | +| [`vpnClientIpsecPolicies`](#parameter-vpnclientipsecpolicies) | array | The IPsec policies for the configuration. | +| [`vpnClientRevokedCertificates`](#parameter-vpnclientrevokedcertificates) | array | The revoked VPN Client certificate thumbprints for the configuration. | +| [`vpnProtocols`](#parameter-vpnprotocols) | array | The allowed VPN protocols for the configuration. | + +### Parameter: `name` + +The name of the user VPN configuration. + +- Required: Yes +- Type: string + +### Parameter: `aadAudience` + +The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication. + +- Required: No +- Type: string + +### Parameter: `aadIssuer` + +The issuer for the AAD/Entra authentication. Required if configuring Entra ID authentication. + +- Required: No +- Type: string + +### Parameter: `aadTenant` + +The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication. + +- Required: No +- Type: string + +### Parameter: `radiusServerAddress` + +The address of the RADIUS server. Required if configuring a single RADIUS. + +- Required: No +- Type: string + +### Parameter: `radiusServerSecret` + +The RADIUS server secret. Required if configuring a single RADIUS server. + +- Required: No +- Type: securestring + +### Parameter: `vpnClientRootCertificates` + +The VPN Client root certificate public keys for the configuration. Required if using certificate authentication. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location where all resources will be created. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `p2sConfigurationPolicyGroups` + +The P2S configuration policy groups for the configuration. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `radiusClientRootCertificates` + +The revoked RADIUS client certificates for the configuration. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `radiusServerRootCertificates` + +The root certificates of the RADIUS server. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `radiusServers` + +The list of RADIUS servers. Required if configuring multiple RADIUS servers. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `vpnAuthenticationTypes` + +The authentication types for the VPN configuration. + +- Required: No +- Type: array +- Default: `[]` +- Allowed: + ```Bicep + [ + 'AAD' + 'Certificate' + 'Radius' + ] + ``` + +### Parameter: `vpnClientIpsecPolicies` + +The IPsec policies for the configuration. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dhGroup`](#parameter-vpnclientipsecpoliciesdhgroup) | string | The Diffie-Hellman group used in IKE phase 1. Required if using IKEv2. | +| [`ikeEncryption`](#parameter-vpnclientipsecpoliciesikeencryption) | string | The encryption algorithm used in IKE phase 1. Required if using IKEv2. | +| [`ikeIntegrity`](#parameter-vpnclientipsecpoliciesikeintegrity) | string | The integrity algorithm used in IKE phase 1. Required if using IKEv2. | +| [`ipsecEncryption`](#parameter-vpnclientipsecpoliciesipsecencryption) | string | The encryption algorithm used in IKE phase 2. Required if using IKEv2. | +| [`ipsecIntegrity`](#parameter-vpnclientipsecpoliciesipsecintegrity) | string | The integrity algorithm used in IKE phase 2. Required if using IKEv2. | +| [`pfsGroup`](#parameter-vpnclientipsecpoliciespfsgroup) | string | The Perfect Forward Secrecy (PFS) group used in IKE phase 2. Required if using IKEv2. | +| [`saDataSizeKilobytes`](#parameter-vpnclientipsecpoliciessadatasizekilobytes) | int | The size of the SA data in kilobytes. Required if using IKEv2. | +| [`salfetimeSeconds`](#parameter-vpnclientipsecpoliciessalfetimeseconds) | int | The lifetime of the SA in seconds. Required if using IKEv2. | + +### Parameter: `vpnClientIpsecPolicies.dhGroup` + +The Diffie-Hellman group used in IKE phase 1. Required if using IKEv2. + +- Required: No +- Type: string + +### Parameter: `vpnClientIpsecPolicies.ikeEncryption` + +The encryption algorithm used in IKE phase 1. Required if using IKEv2. + +- Required: No +- Type: string + +### Parameter: `vpnClientIpsecPolicies.ikeIntegrity` + +The integrity algorithm used in IKE phase 1. Required if using IKEv2. + +- Required: No +- Type: string + +### Parameter: `vpnClientIpsecPolicies.ipsecEncryption` + +The encryption algorithm used in IKE phase 2. Required if using IKEv2. + +- Required: No +- Type: string + +### Parameter: `vpnClientIpsecPolicies.ipsecIntegrity` + +The integrity algorithm used in IKE phase 2. Required if using IKEv2. + +- Required: No +- Type: string + +### Parameter: `vpnClientIpsecPolicies.pfsGroup` + +The Perfect Forward Secrecy (PFS) group used in IKE phase 2. Required if using IKEv2. + +- Required: No +- Type: string + +### Parameter: `vpnClientIpsecPolicies.saDataSizeKilobytes` + +The size of the SA data in kilobytes. Required if using IKEv2. + +- Required: No +- Type: int + +### Parameter: `vpnClientIpsecPolicies.salfetimeSeconds` + +The lifetime of the SA in seconds. Required if using IKEv2. + +- Required: No +- Type: int + +### Parameter: `vpnClientRevokedCertificates` + +The revoked VPN Client certificate thumbprints for the configuration. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `vpnProtocols` + +The allowed VPN protocols for the configuration. + +- Required: No +- Type: array +- Default: `[]` +- Allowed: + ```Bicep + [ + 'IkeV2' + 'OpenVPN' + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the user VPN configuration. | +| `resourceGroupName` | string | The name of the resource group the user VPN configuration was deployed into. | +| `resourceId` | string | The resource ID of the user VPN configuration. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/vpn-server-configuration/main.bicep b/avm/1.1.0/res/network/vpn-server-configuration/main.bicep new file mode 100644 index 000000000..6e8fb4ad5 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-server-configuration/main.bicep @@ -0,0 +1,216 @@ +metadata name = 'VPN Server Configuration' +metadata description = 'This module deploys a VPN Server Configuration for a Virtual Hub P2S Gateway.' + +@description('Required. The name of the user VPN configuration.') +param name string + +@description('Optional. Location where all resources will be created.') +param location string = resourceGroup().location + +@description('Conditional. The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication.') +param aadAudience string? + +@description('Conditional. The issuer for the AAD/Entra authentication. Required if configuring Entra ID authentication.') +param aadIssuer string? + +@description('Conditional. The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication.') +param aadTenant string? + +@description('Optional. The P2S configuration policy groups for the configuration.') +param p2sConfigurationPolicyGroups array = [] + +@description('Optional. The revoked RADIUS client certificates for the configuration.') +param radiusClientRootCertificates array = [] + +@description('Conditional. The address of the RADIUS server. Required if configuring a single RADIUS.') +param radiusServerAddress string? + +@description('Optional. The root certificates of the RADIUS server.') +param radiusServerRootCertificates array = [] + +@description('Optional. The list of RADIUS servers. Required if configuring multiple RADIUS servers.') +param radiusServers array = [] + +@description('Conditional. The RADIUS server secret. Required if configuring a single RADIUS server.') +@secure() +param radiusServerSecret string? + +@description('Optional. The authentication types for the VPN configuration.') +@allowed([ + 'AAD' + 'Certificate' + 'Radius' +]) +param vpnAuthenticationTypes array = [] + +@description('Optional. The IPsec policies for the configuration.') +param vpnClientIpsecPolicies vpnClientIpsecPoliciesType[]? + +@description('Optional. The revoked VPN Client certificate thumbprints for the configuration.') +param vpnClientRevokedCertificates array = [] + +@description('Conditional. The VPN Client root certificate public keys for the configuration. Required if using certificate authentication.') +param vpnClientRootCertificates array = [] + +@description('Optional. The allowed VPN protocols for the configuration.') +@allowed([ + 'IkeV2' + 'OpenVPN' +]) +param vpnProtocols array = [] + +@description('Optional. Tags of the resource.') +param tags object? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.res.network-vpnserverconfiguration.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource vpnServerConfig 'Microsoft.Network/vpnServerConfigurations@2023-11-01' = { + name: name + location: location + tags: tags + properties: { + aadAuthenticationParameters: { + aadAudience: aadAudience + aadIssuer: aadIssuer + aadTenant: aadTenant + } + configurationPolicyGroups: [ + for group in (p2sConfigurationPolicyGroups) ?? []: { + name: group.userVPNPolicyGroupName + properties: { + isDefault: group.isDefault + policyMembers: group.policyMembers + priority: group.priority + } + } + ] + radiusClientRootCertificates: [ + for clientRootroot in (radiusClientRootCertificates) ?? []: { + name: clientRootroot.name + thumbprint: clientRootroot.thumbprint + } + ] + radiusServerAddress: radiusServerAddress + radiusServerRootCertificates: [ + for serverRoot in (radiusServerRootCertificates) ?? []: { + name: serverRoot.name + publicCertData: serverRoot.publicCertData + } + ] + radiusServers: [ + for server in (radiusServers) ?? []: { + radiusServerAddress: server.radiusServerAddress + radiusServerScore: server.radiusServerScore + radiusServerSecret: server.radiusServerSecret + } + ] + radiusServerSecret: radiusServerSecret + vpnAuthenticationTypes: vpnAuthenticationTypes + vpnClientIpsecPolicies: [ + for policy in (vpnClientIpsecPolicies) ?? []: { + dhGroup: policy.dhGroup + ikeEncryption: policy.ikeEncryption + ikeIntegrity: policy.ikeIntegrity + ipsecEncryption: policy.ipsecEncryption + ipsecIntegrity: policy.ipsecIntegrity + pfsGroup: policy.pfsGroup + saDataSizeKilobytes: policy.saDataSizeKilobytes + saLifeTimeSeconds: policy.saLifeTimeSeconds + } + ] + vpnClientRevokedCertificates: [ + for cert in (vpnClientRevokedCertificates) ?? []: { + name: cert.name + thumbprint: cert.thumbprint + } + ] + vpnClientRootCertificates: [ + for cert in (vpnClientRootCertificates) ?? []: { + name: cert.name + publicCertData: cert.publicCertData + } + ] + vpnProtocols: vpnProtocols + } +} + +resource vpnGateway_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: vpnServerConfig +} + +@description('The name of the user VPN configuration.') +output name string = vpnServerConfig.name + +@description('The resource ID of the user VPN configuration.') +output resourceId string = vpnServerConfig.id + +@description('The name of the resource group the user VPN configuration was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = vpnServerConfig.location + +// =============== // +// Definitions // +// =============== // + +@export() +type vpnClientIpsecPoliciesType = { + @description('Optional. The Diffie-Hellman group used in IKE phase 1. Required if using IKEv2.') + dhGroup: string? + + @description('Optional. The encryption algorithm used in IKE phase 1. Required if using IKEv2.') + ikeEncryption: string? + + @description('Optional. The integrity algorithm used in IKE phase 1. Required if using IKEv2.') + ikeIntegrity: string? + + @description('Optional. The encryption algorithm used in IKE phase 2. Required if using IKEv2.') + ipsecEncryption: string? + + @description('Optional. The integrity algorithm used in IKE phase 2. Required if using IKEv2.') + ipsecIntegrity: string? + + @description('Optional. The Perfect Forward Secrecy (PFS) group used in IKE phase 2. Required if using IKEv2.') + pfsGroup: string? + + @description('Optional. The size of the SA data in kilobytes. Required if using IKEv2.') + saDataSizeKilobytes: int? + + @description('Optional. The lifetime of the SA in seconds. Required if using IKEv2.') + salfetimeSeconds: int? +} diff --git a/avm/1.1.0/res/network/vpn-server-configuration/main.json b/avm/1.1.0/res/network/vpn-server-configuration/main.json new file mode 100644 index 000000000..fb5b4646b --- /dev/null +++ b/avm/1.1.0/res/network/vpn-server-configuration/main.json @@ -0,0 +1,409 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "14313600575703393398" + }, + "name": "VPN Server Configuration", + "description": "This module deploys a VPN Server Configuration for a Virtual Hub P2S Gateway." + }, + "definitions": { + "vpnClientIpsecPoliciesType": { + "type": "object", + "properties": { + "dhGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Diffie-Hellman group used in IKE phase 1. Required if using IKEv2." + } + }, + "ikeEncryption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The encryption algorithm used in IKE phase 1. Required if using IKEv2." + } + }, + "ikeIntegrity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The integrity algorithm used in IKE phase 1. Required if using IKEv2." + } + }, + "ipsecEncryption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The encryption algorithm used in IKE phase 2. Required if using IKEv2." + } + }, + "ipsecIntegrity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The integrity algorithm used in IKE phase 2. Required if using IKEv2." + } + }, + "pfsGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Perfect Forward Secrecy (PFS) group used in IKE phase 2. Required if using IKEv2." + } + }, + "saDataSizeKilobytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The size of the SA data in kilobytes. Required if using IKEv2." + } + }, + "salfetimeSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The lifetime of the SA in seconds. Required if using IKEv2." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the user VPN configuration." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location where all resources will be created." + } + }, + "aadAudience": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication." + } + }, + "aadIssuer": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The issuer for the AAD/Entra authentication. Required if configuring Entra ID authentication." + } + }, + "aadTenant": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication." + } + }, + "p2sConfigurationPolicyGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The P2S configuration policy groups for the configuration." + } + }, + "radiusClientRootCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The revoked RADIUS client certificates for the configuration." + } + }, + "radiusServerAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address of the RADIUS server. Required if configuring a single RADIUS." + } + }, + "radiusServerRootCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The root certificates of the RADIUS server." + } + }, + "radiusServers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The list of RADIUS servers. Required if configuring multiple RADIUS servers." + } + }, + "radiusServerSecret": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The RADIUS server secret. Required if configuring a single RADIUS server." + } + }, + "vpnAuthenticationTypes": { + "type": "array", + "defaultValue": [], + "allowedValues": [ + "AAD", + "Certificate", + "Radius" + ], + "metadata": { + "description": "Optional. The authentication types for the VPN configuration." + } + }, + "vpnClientIpsecPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/vpnClientIpsecPoliciesType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The IPsec policies for the configuration." + } + }, + "vpnClientRevokedCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The revoked VPN Client certificate thumbprints for the configuration." + } + }, + "vpnClientRootCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Conditional. The VPN Client root certificate public keys for the configuration. Required if using certificate authentication." + } + }, + "vpnProtocols": { + "type": "array", + "defaultValue": [], + "allowedValues": [ + "IkeV2", + "OpenVPN" + ], + "metadata": { + "description": "Optional. The allowed VPN protocols for the configuration." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.res.network-vpnserverconfiguration.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "vpnServerConfig": { + "type": "Microsoft.Network/vpnServerConfigurations", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "configurationPolicyGroups", + "count": "[length(coalesce(parameters('p2sConfigurationPolicyGroups'), createArray()))]", + "input": { + "name": "[coalesce(parameters('p2sConfigurationPolicyGroups'), createArray())[copyIndex('configurationPolicyGroups')].userVPNPolicyGroupName]", + "properties": { + "isDefault": "[coalesce(parameters('p2sConfigurationPolicyGroups'), createArray())[copyIndex('configurationPolicyGroups')].isDefault]", + "policyMembers": "[coalesce(parameters('p2sConfigurationPolicyGroups'), createArray())[copyIndex('configurationPolicyGroups')].policyMembers]", + "priority": "[coalesce(parameters('p2sConfigurationPolicyGroups'), createArray())[copyIndex('configurationPolicyGroups')].priority]" + } + } + }, + { + "name": "radiusClientRootCertificates", + "count": "[length(coalesce(parameters('radiusClientRootCertificates'), createArray()))]", + "input": { + "name": "[coalesce(parameters('radiusClientRootCertificates'), createArray())[copyIndex('radiusClientRootCertificates')].name]", + "thumbprint": "[coalesce(parameters('radiusClientRootCertificates'), createArray())[copyIndex('radiusClientRootCertificates')].thumbprint]" + } + }, + { + "name": "radiusServerRootCertificates", + "count": "[length(coalesce(parameters('radiusServerRootCertificates'), createArray()))]", + "input": { + "name": "[coalesce(parameters('radiusServerRootCertificates'), createArray())[copyIndex('radiusServerRootCertificates')].name]", + "publicCertData": "[coalesce(parameters('radiusServerRootCertificates'), createArray())[copyIndex('radiusServerRootCertificates')].publicCertData]" + } + }, + { + "name": "radiusServers", + "count": "[length(coalesce(parameters('radiusServers'), createArray()))]", + "input": { + "radiusServerAddress": "[coalesce(parameters('radiusServers'), createArray())[copyIndex('radiusServers')].radiusServerAddress]", + "radiusServerScore": "[coalesce(parameters('radiusServers'), createArray())[copyIndex('radiusServers')].radiusServerScore]", + "radiusServerSecret": "[coalesce(parameters('radiusServers'), createArray())[copyIndex('radiusServers')].radiusServerSecret]" + } + }, + { + "name": "vpnClientIpsecPolicies", + "count": "[length(coalesce(parameters('vpnClientIpsecPolicies'), createArray()))]", + "input": { + "dhGroup": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].dhGroup]", + "ikeEncryption": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].ikeEncryption]", + "ikeIntegrity": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].ikeIntegrity]", + "ipsecEncryption": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].ipsecEncryption]", + "ipsecIntegrity": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].ipsecIntegrity]", + "pfsGroup": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].pfsGroup]", + "saDataSizeKilobytes": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].saDataSizeKilobytes]", + "saLifeTimeSeconds": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].saLifeTimeSeconds]" + } + }, + { + "name": "vpnClientRevokedCertificates", + "count": "[length(coalesce(parameters('vpnClientRevokedCertificates'), createArray()))]", + "input": { + "name": "[coalesce(parameters('vpnClientRevokedCertificates'), createArray())[copyIndex('vpnClientRevokedCertificates')].name]", + "thumbprint": "[coalesce(parameters('vpnClientRevokedCertificates'), createArray())[copyIndex('vpnClientRevokedCertificates')].thumbprint]" + } + }, + { + "name": "vpnClientRootCertificates", + "count": "[length(coalesce(parameters('vpnClientRootCertificates'), createArray()))]", + "input": { + "name": "[coalesce(parameters('vpnClientRootCertificates'), createArray())[copyIndex('vpnClientRootCertificates')].name]", + "publicCertData": "[coalesce(parameters('vpnClientRootCertificates'), createArray())[copyIndex('vpnClientRootCertificates')].publicCertData]" + } + } + ], + "aadAuthenticationParameters": { + "aadAudience": "[parameters('aadAudience')]", + "aadIssuer": "[parameters('aadIssuer')]", + "aadTenant": "[parameters('aadTenant')]" + }, + "radiusServerAddress": "[parameters('radiusServerAddress')]", + "radiusServerSecret": "[parameters('radiusServerSecret')]", + "vpnAuthenticationTypes": "[parameters('vpnAuthenticationTypes')]", + "vpnProtocols": "[parameters('vpnProtocols')]" + } + }, + "vpnGateway_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/vpnServerConfigurations/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "vpnServerConfig" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user VPN configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user VPN configuration." + }, + "value": "[resourceId('Microsoft.Network/vpnServerConfigurations', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the user VPN configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vpnServerConfig', '2023-11-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..3e28ec067 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +@description('The resource ID of the created Virtual WAN.') +output virtualWANResourceId string = virtualWan.id diff --git a/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..d863bb0ad --- /dev/null +++ b/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,79 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.vpnserverconfiguration-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'vscmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}VPNConfig' + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: '${environment().authentication.loginEndpoint}11111111-1111-1111-1111-111111111111' + p2sConfigurationPolicyGroups: [ + { + userVPNPolicyGroupName: 'DefaultGroup' + policymembers: [ + { + name: 'UserGroup1' + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + } + ] + priority: '0' + isDefault: 'true' + } + ] + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnProtocols: [ + 'OpenVPN' + ] + } + } +] diff --git a/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..3e28ec067 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +@description('The resource ID of the created Virtual WAN.') +output virtualWANResourceId string = virtualWan.id diff --git a/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..7fb278123 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/max/main.test.bicep @@ -0,0 +1,162 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +// e.g., for a module 'network/private-endpoint' you could use 'dep-dev-network.privateendpoints-${serviceShort}-rg' +param resourceGroupName string = 'dep-${namePrefix}-network.vpnserverconfiguration-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +// e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test +param serviceShort string = 'vscmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}VPNConfig' + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: '${environment().authentication.loginEndpoint}11111111-1111-1111-1111-111111111111' + p2sConfigurationPolicyGroups: [ + { + userVPNPolicyGroupName: 'DefaultGroup' + policymembers: [ + { + name: 'UserGroup1' + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + } + { + name: 'UserGroup2' + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-3333-4444-111111111111' + } + ] + priority: '0' + isDefault: 'true' + } + { + userVPNPolicyGroupName: 'AdditionalGroup' + policymembers: [ + { + name: 'UserGroup3' + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-4444-5555-111111111111' + } + { + name: 'UserGroup4' + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-5555-6666-111111111111' + } + ] + priority: '1' + isDefault: 'false' + } + ] + radiusServers: [ + { + radiusServerAddress: '10.150.1.50' + radiusServerScore: '10' + radiusServerSecret: 'TestSecret' + } + { + radiusServerAddress: '10.150.1.150' + radiusServerScore: '20' + radiusServerSecret: 'TestSecret2' + } + ] + radiusServerRootCertificates: [ + { + name: 'TestRadiusRootCert' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + ] + radiusClientRootCertificates: [ + { + name: 'TestRadiusClientRevokedCert' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b59aa' + } + ] + vpnAuthenticationTypes: [ + 'AAD' + 'Certificate' + 'Radius' + ] + vpnClientIpsecPolicies: [ + { + saLifeTimeSeconds: 27000 + saDataSizeKilobytes: 0 + ipsecEncryption: 'AES256' + ipsecIntegrity: 'SHA256' + ikeEncryption: 'AES256' + ikeIntegrity: 'SHA256' + dhGroup: 'DHGroup14' + pfsGroup: 'PFS14' + } + ] + vpnClientRevokedCertificates: [ + { + name: 'TestRevokedCert' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b69aa' + } + { + name: 'TestRevokedCert2' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b69bb' + } + ] + vpnClientRootCertificates: [ + { + name: 'TestRootCert' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + { + name: 'TestRootCert2' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcMARELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + ] + vpnProtocols: [ + 'OpenVPN' + ] + } + } +] diff --git a/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..bb151ad9d --- /dev/null +++ b/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +@description('The resource ID of the created Virtual WAN.') +output virtualWWANResourceId string = virtualWan.id diff --git a/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..f771ad08b --- /dev/null +++ b/avm/1.1.0/res/network/vpn-server-configuration/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,81 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +// e.g., for a module 'network/private-endpoint' you could use 'dep-dev-network.privateendpoints-${serviceShort}-rg' +param resourceGroupName string = 'dep-${namePrefix}-network.vpnserverconfiguration-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +// e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test +param serviceShort string = 'vscwaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}VPNConfig' + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: '${environment().authentication.loginEndpoint}11111111-1111-1111-1111-111111111111' + p2sConfigurationPolicyGroups: [ + { + userVPNPolicyGroupName: 'DefaultGroup' + policymembers: [ + { + name: 'UserGroup1' + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + } + ] + priority: '0' + isDefault: 'true' + } + ] + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnProtocols: [ + 'OpenVPN' + ] + } + } +] diff --git a/avm/1.1.0/res/network/vpn-server-configuration/version.json b/avm/1.1.0/res/network/vpn-server-configuration/version.json new file mode 100644 index 000000000..8def869ed --- /dev/null +++ b/avm/1.1.0/res/network/vpn-server-configuration/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/res/network/vpn-site/README.md b/avm/1.1.0/res/network/vpn-site/README.md new file mode 100644 index 000000000..6d3a7c354 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-site/README.md @@ -0,0 +1,931 @@ +# VPN Sites `[Microsoft.Network/vpnSites]` + +This module deploys a VPN Site. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/vpnSites` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/vpnSites) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/vpn-site:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module vpnSite 'br/public:avm/res/network/vpn-site:' = { + name: 'vpnSiteDeployment' + params: { + // Required parameters + name: 'nvsmin' + virtualWanId: '' + // Non-required parameters + addressPrefixes: [ + '10.0.0.0/16' + ] + ipAddress: '1.2.3.4' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nvsmin" + }, + "virtualWanId": { + "value": "" + }, + // Non-required parameters + "addressPrefixes": { + "value": [ + "10.0.0.0/16" + ] + }, + "ipAddress": { + "value": "1.2.3.4" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-site:' + +// Required parameters +param name = 'nvsmin' +param virtualWanId = '' +// Non-required parameters +param addressPrefixes = [ + '10.0.0.0/16' +] +param ipAddress = '1.2.3.4' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module vpnSite 'br/public:avm/res/network/vpn-site:' = { + name: 'vpnSiteDeployment' + params: { + // Required parameters + name: 'nvsmax' + virtualWanId: '' + // Non-required parameters + deviceProperties: { + linkSpeedInMbps: 0 + } + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + o365Policy: { + breakOutCategories: { + allow: true + default: true + optimize: true + } + } + roleAssignments: [ + { + name: '1dcfa9c2-5e95-42d2-bf04-bdecad93abcf' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + tagA: 'valueA' + tagB: 'valueB' + } + vpnSiteLinks: [ + { + name: 'vSite-nvsmax' + properties: { + bgpProperties: { + asn: 65010 + bgpPeeringAddress: '1.1.1.1' + } + ipAddress: '1.2.3.4' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } + { + name: 'Link1' + properties: { + bgpProperties: { + asn: 65020 + bgpPeeringAddress: '192.168.1.0' + } + ipAddress: '2.2.2.2' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nvsmax" + }, + "virtualWanId": { + "value": "" + }, + // Non-required parameters + "deviceProperties": { + "value": { + "linkSpeedInMbps": 0 + } + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "o365Policy": { + "value": { + "breakOutCategories": { + "allow": true, + "default": true, + "optimize": true + } + } + }, + "roleAssignments": { + "value": [ + { + "name": "1dcfa9c2-5e95-42d2-bf04-bdecad93abcf", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name", + "tagA": "valueA", + "tagB": "valueB" + } + }, + "vpnSiteLinks": { + "value": [ + { + "name": "vSite-nvsmax", + "properties": { + "bgpProperties": { + "asn": 65010, + "bgpPeeringAddress": "1.1.1.1" + }, + "ipAddress": "1.2.3.4", + "linkProperties": { + "linkProviderName": "contoso", + "linkSpeedInMbps": 5 + } + } + }, + { + "name": "Link1", + "properties": { + "bgpProperties": { + "asn": 65020, + "bgpPeeringAddress": "192.168.1.0" + }, + "ipAddress": "2.2.2.2", + "linkProperties": { + "linkProviderName": "contoso", + "linkSpeedInMbps": 5 + } + } + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-site:' + +// Required parameters +param name = 'nvsmax' +param virtualWanId = '' +// Non-required parameters +param deviceProperties = { + linkSpeedInMbps: 0 +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +o365Policy: { + breakOutCategories: { + allow: true + default: true + optimize: true + } +} +param roleAssignments = [ + { + name: '1dcfa9c2-5e95-42d2-bf04-bdecad93abcf' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 'hidden-title': 'This is visible in the resource name' + tagA: 'valueA' + tagB: 'valueB' +} +param vpnSiteLinks = [ + { + name: 'vSite-nvsmax' + properties: { + bgpProperties: { + asn: 65010 + bgpPeeringAddress: '1.1.1.1' + } + ipAddress: '1.2.3.4' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } + { + name: 'Link1' + properties: { + bgpProperties: { + asn: 65020 + bgpPeeringAddress: '192.168.1.0' + } + ipAddress: '2.2.2.2' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } +] +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module vpnSite 'br/public:avm/res/network/vpn-site:' = { + name: 'vpnSiteDeployment' + params: { + // Required parameters + name: 'nvswaf' + virtualWanId: '' + // Non-required parameters + deviceProperties: { + linkSpeedInMbps: 0 + } + location: '' + o365Policy: { + breakOutCategories: { + allow: true + default: true + optimize: true + } + } + tags: { + 'hidden-title': 'This is visible in the resource name' + tagA: 'valueA' + tagB: 'valueB' + } + vpnSiteLinks: [ + { + name: 'vSite-nvswaf' + properties: { + bgpProperties: { + asn: 65010 + bgpPeeringAddress: '1.1.1.1' + } + ipAddress: '1.2.3.4' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } + { + name: 'Link1' + properties: { + bgpProperties: { + asn: 65020 + bgpPeeringAddress: '192.168.1.0' + } + ipAddress: '2.2.2.2' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nvswaf" + }, + "virtualWanId": { + "value": "" + }, + // Non-required parameters + "deviceProperties": { + "value": { + "linkSpeedInMbps": 0 + } + }, + "location": { + "value": "" + }, + "o365Policy": { + "value": { + "breakOutCategories": { + "allow": true, + "default": true, + "optimize": true + } + } + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name", + "tagA": "valueA", + "tagB": "valueB" + } + }, + "vpnSiteLinks": { + "value": [ + { + "name": "vSite-nvswaf", + "properties": { + "bgpProperties": { + "asn": 65010, + "bgpPeeringAddress": "1.1.1.1" + }, + "ipAddress": "1.2.3.4", + "linkProperties": { + "linkProviderName": "contoso", + "linkSpeedInMbps": 5 + } + } + }, + { + "name": "Link1", + "properties": { + "bgpProperties": { + "asn": 65020, + "bgpPeeringAddress": "192.168.1.0" + }, + "ipAddress": "2.2.2.2", + "linkProperties": { + "linkProviderName": "contoso", + "linkSpeedInMbps": 5 + } + } + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-site:' + +// Required parameters +param name = 'nvswaf' +param virtualWanId = '' +// Non-required parameters +param deviceProperties = { + linkSpeedInMbps: 0 +} +param location = '' +o365Policy: { + breakOutCategories: { + allow: true + default: true + optimize: true + } +} +param tags = { + 'hidden-title': 'This is visible in the resource name' + tagA: 'valueA' + tagB: 'valueB' +} +param vpnSiteLinks = [ + { + name: 'vSite-nvswaf' + properties: { + bgpProperties: { + asn: 65010 + bgpPeeringAddress: '1.1.1.1' + } + ipAddress: '1.2.3.4' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } + { + name: 'Link1' + properties: { + bgpProperties: { + asn: 65020 + bgpPeeringAddress: '192.168.1.0' + } + ipAddress: '2.2.2.2' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } +] +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the VPN Site. | +| [`virtualWanId`](#parameter-virtualwanid) | string | Resource ID of the virtual WAN to link to. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefixes`](#parameter-addressprefixes) | array | An array of IP address ranges that can be used by subnets of the virtual network. Required if no bgpProperties or VPNSiteLinks are configured. | +| [`bgpProperties`](#parameter-bgpproperties) | object | BGP settings details. Note: This is a deprecated property, please use the corresponding VpnSiteLinks property instead. Required if no addressPrefixes or VPNSiteLinks are configured. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`deviceProperties`](#parameter-deviceproperties) | object | List of properties of the device. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`ipAddress`](#parameter-ipaddress) | string | The IP-address for the VPN-site. Note: This is a deprecated property, please use the corresponding VpnSiteLinks property instead. | +| [`isSecuritySite`](#parameter-issecuritysite) | bool | IsSecuritySite flag. | +| [`location`](#parameter-location) | string | Location where all resources will be created. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`o365Policy`](#parameter-o365policy) | object | The Office365 breakout policy. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`vpnSiteLinks`](#parameter-vpnsitelinks) | array | List of all VPN site links. | + +### Parameter: `name` + +Name of the VPN Site. + +- Required: Yes +- Type: string + +### Parameter: `virtualWanId` + +Resource ID of the virtual WAN to link to. + +- Required: Yes +- Type: string + +### Parameter: `addressPrefixes` + +An array of IP address ranges that can be used by subnets of the virtual network. Required if no bgpProperties or VPNSiteLinks are configured. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `bgpProperties` + +BGP settings details. Note: This is a deprecated property, please use the corresponding VpnSiteLinks property instead. Required if no addressPrefixes or VPNSiteLinks are configured. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `deviceProperties` + +List of properties of the device. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `ipAddress` + +The IP-address for the VPN-site. Note: This is a deprecated property, please use the corresponding VpnSiteLinks property instead. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `isSecuritySite` + +IsSecuritySite flag. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `location` + +Location where all resources will be created. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `o365Policy` + +The Office365 breakout policy. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `vpnSiteLinks` + +List of all VPN site links. + +- Required: No +- Type: array +- Default: `[]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the VPN site. | +| `resourceGroupName` | string | The resource group the VPN site was deployed into. | +| `resourceId` | string | The resource ID of the VPN site. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Notes + +### Parameter Usage `deviceProperties` + +

+ +Parameter JSON format + +```json +"deviceProperties": { + "value": { + "deviceModel": "morty", + "deviceVendor": "contoso", + "linkSpeedInMbps": 0 + } +} +``` + +
+ + +
+ +Bicep format + +```bicep +deviceProperties: { + deviceModel: 'morty' + deviceVendor: 'contoso' + linkSpeedInMbps: 0 +} +``` + +
+

+ +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/network/vpn-site/main.bicep b/avm/1.1.0/res/network/vpn-site/main.bicep new file mode 100644 index 000000000..3e2cfa9d5 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-site/main.bicep @@ -0,0 +1,158 @@ +metadata name = 'VPN Sites' +metadata description = 'This module deploys a VPN Site.' + +@description('Required. Name of the VPN Site.') +param name string + +@description('Required. Resource ID of the virtual WAN to link to.') +param virtualWanId string + +@description('Optional. Location where all resources will be created.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Conditional. An array of IP address ranges that can be used by subnets of the virtual network. Required if no bgpProperties or VPNSiteLinks are configured.') +param addressPrefixes array = [] + +@description('Conditional. BGP settings details. Note: This is a deprecated property, please use the corresponding VpnSiteLinks property instead. Required if no addressPrefixes or VPNSiteLinks are configured.') +param bgpProperties object = {} + +@description('Optional. List of properties of the device.') +param deviceProperties object = {} + +@description('Optional. The IP-address for the VPN-site. Note: This is a deprecated property, please use the corresponding VpnSiteLinks property instead.') +param ipAddress string = '' + +@description('Optional. IsSecuritySite flag.') +param isSecuritySite bool = false + +@description('Optional. The Office365 breakout policy.') +param o365Policy object = {} + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. List of all VPN site links.') +param vpnSiteLinks array = [] + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.res.network-vpnsite.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource vpnSite 'Microsoft.Network/vpnSites@2023-04-01' = { + name: name + location: location + tags: tags + properties: { + addressSpace: !empty(addressPrefixes) + ? { + addressPrefixes: addressPrefixes + } + : null + bgpProperties: !empty(bgpProperties) ? bgpProperties : null + deviceProperties: !empty(deviceProperties) ? deviceProperties : null + ipAddress: !empty(ipAddress) ? ipAddress : null + isSecuritySite: isSecuritySite + o365Policy: !empty(o365Policy) ? o365Policy : null + virtualWan: { + id: virtualWanId + } + vpnSiteLinks: !empty(vpnSiteLinks) ? vpnSiteLinks : null + } +} + +resource vpnSite_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: vpnSite +} + +resource vpnSite_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(vpnSite.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: vpnSite + } +] + +@description('The name of the VPN site.') +output name string = vpnSite.name + +@description('The resource ID of the VPN site.') +output resourceId string = vpnSite.id + +@description('The resource group the VPN site was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = vpnSite.location diff --git a/avm/1.1.0/res/network/vpn-site/main.json b/avm/1.1.0/res/network/vpn-site/main.json new file mode 100644 index 000000000..bff519c79 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-site/main.json @@ -0,0 +1,346 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "18110577874087174381" + }, + "name": "VPN Sites", + "description": "This module deploys a VPN Site." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the VPN Site." + } + }, + "virtualWanId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the virtual WAN to link to." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location where all resources will be created." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "addressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Conditional. An array of IP address ranges that can be used by subnets of the virtual network. Required if no bgpProperties or VPNSiteLinks are configured." + } + }, + "bgpProperties": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Conditional. BGP settings details. Note: This is a deprecated property, please use the corresponding VpnSiteLinks property instead. Required if no addressPrefixes or VPNSiteLinks are configured." + } + }, + "deviceProperties": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. List of properties of the device." + } + }, + "ipAddress": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The IP-address for the VPN-site. Note: This is a deprecated property, please use the corresponding VpnSiteLinks property instead." + } + }, + "isSecuritySite": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. IsSecuritySite flag." + } + }, + "o365Policy": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The Office365 breakout policy." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "vpnSiteLinks": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of all VPN site links." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.res.network-vpnsite.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "vpnSite": { + "type": "Microsoft.Network/vpnSites", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressSpace": "[if(not(empty(parameters('addressPrefixes'))), createObject('addressPrefixes', parameters('addressPrefixes')), null())]", + "bgpProperties": "[if(not(empty(parameters('bgpProperties'))), parameters('bgpProperties'), null())]", + "deviceProperties": "[if(not(empty(parameters('deviceProperties'))), parameters('deviceProperties'), null())]", + "ipAddress": "[if(not(empty(parameters('ipAddress'))), parameters('ipAddress'), null())]", + "isSecuritySite": "[parameters('isSecuritySite')]", + "o365Policy": "[if(not(empty(parameters('o365Policy'))), parameters('o365Policy'), null())]", + "virtualWan": { + "id": "[parameters('virtualWanId')]" + }, + "vpnSiteLinks": "[if(not(empty(parameters('vpnSiteLinks'))), parameters('vpnSiteLinks'), null())]" + } + }, + "vpnSite_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/vpnSites/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "vpnSite" + ] + }, + "vpnSite_roleAssignments": { + "copy": { + "name": "vpnSite_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/vpnSites/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/vpnSites', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "vpnSite" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the VPN site." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the VPN site." + }, + "value": "[resourceId('Microsoft.Network/vpnSites', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the VPN site was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vpnSite', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/network/vpn-site/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/network/vpn-site/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..bb151ad9d --- /dev/null +++ b/avm/1.1.0/res/network/vpn-site/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +@description('The resource ID of the created Virtual WAN.') +output virtualWWANResourceId string = virtualWan.id diff --git a/avm/1.1.0/res/network/vpn-site/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/network/vpn-site/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..7a2b075e2 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-site/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,61 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.vpnSites-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvsmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}-${serviceShort}' + virtualWanId: nestedDependencies.outputs.virtualWWANResourceId + addressPrefixes: [ + '10.0.0.0/16' + ] + ipAddress: '1.2.3.4' + } + } +] diff --git a/avm/1.1.0/res/network/vpn-site/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/network/vpn-site/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..8e2694c27 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-site/tests/e2e/max/dependencies.bicep @@ -0,0 +1,24 @@ +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +@description('The principal ID of the created managed identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Virtual WAN.') +output virtualWWANResourceId string = virtualWan.id diff --git a/avm/1.1.0/res/network/vpn-site/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/network/vpn-site/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..00e33360e --- /dev/null +++ b/avm/1.1.0/res/network/vpn-site/tests/e2e/max/main.test.bicep @@ -0,0 +1,130 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.vpnSites-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvsmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}-${serviceShort}' + virtualWanId: nestedDependencies.outputs.virtualWWANResourceId + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + tagA: 'valueA' + tagB: 'valueB' + } + deviceProperties: { + linkSpeedInMbps: 0 + } + vpnSiteLinks: [ + { + name: '${namePrefix}-vSite-${serviceShort}' + properties: { + bgpProperties: { + asn: 65010 + bgpPeeringAddress: '1.1.1.1' + } + ipAddress: '1.2.3.4' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } + { + name: 'Link1' + properties: { + bgpProperties: { + asn: 65020 + bgpPeeringAddress: '192.168.1.0' + } + ipAddress: '2.2.2.2' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } + ] + o365Policy: { + breakOutCategories: { + optimize: true + allow: true + default: true + } + } + roleAssignments: [ + { + name: '1dcfa9c2-5e95-42d2-bf04-bdecad93abcf' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + } +] diff --git a/avm/1.1.0/res/network/vpn-site/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/network/vpn-site/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..8e2694c27 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-site/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,24 @@ +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +@description('The principal ID of the created managed identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Virtual WAN.') +output virtualWWANResourceId string = virtualWan.id diff --git a/avm/1.1.0/res/network/vpn-site/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/network/vpn-site/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..36d8fa73c --- /dev/null +++ b/avm/1.1.0/res/network/vpn-site/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,104 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.vpnSites-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvswaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}-${serviceShort}' + virtualWanId: nestedDependencies.outputs.virtualWWANResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + tagA: 'valueA' + tagB: 'valueB' + } + deviceProperties: { + linkSpeedInMbps: 0 + } + vpnSiteLinks: [ + { + name: '${namePrefix}-vSite-${serviceShort}' + properties: { + bgpProperties: { + asn: 65010 + bgpPeeringAddress: '1.1.1.1' + } + ipAddress: '1.2.3.4' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } + { + name: 'Link1' + properties: { + bgpProperties: { + asn: 65020 + bgpPeeringAddress: '192.168.1.0' + } + ipAddress: '2.2.2.2' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } + ] + o365Policy: { + breakOutCategories: { + optimize: true + allow: true + default: true + } + } + } + } +] diff --git a/avm/1.1.0/res/network/vpn-site/version.json b/avm/1.1.0/res/network/vpn-site/version.json new file mode 100644 index 000000000..76049e1c4 --- /dev/null +++ b/avm/1.1.0/res/network/vpn-site/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/operational-insights/workspace/README.md b/avm/1.1.0/res/operational-insights/workspace/README.md new file mode 100644 index 000000000..1d86fc74b --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/README.md @@ -0,0 +1,4216 @@ +# Log Analytics Workspaces `[Microsoft.OperationalInsights/workspaces]` + +This module deploys a Log Analytics Workspace. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.OperationalInsights/workspaces` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces) | +| `Microsoft.OperationalInsights/workspaces/dataExports` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/dataExports) | +| `Microsoft.OperationalInsights/workspaces/dataSources` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/dataSources) | +| `Microsoft.OperationalInsights/workspaces/linkedServices` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/linkedServices) | +| `Microsoft.OperationalInsights/workspaces/linkedStorageAccounts` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/linkedStorageAccounts) | +| `Microsoft.OperationalInsights/workspaces/savedSearches` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/savedSearches) | +| `Microsoft.OperationalInsights/workspaces/storageInsightConfigs` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/storageInsightConfigs) | +| `Microsoft.OperationalInsights/workspaces/tables` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/tables) | +| `Microsoft.OperationsManagement/solutions` | [2015-11-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationsManagement/2015-11-01-preview/solutions) | +| `Microsoft.SecurityInsights/onboardingStates` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.SecurityInsights/2024-03-01/onboardingStates) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/operational-insights/workspace:`. + +- [Advanced features](#example-1-advanced-features) +- [Using only defaults](#example-2-using-only-defaults) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [WAF-aligned](#example-4-waf-aligned) + +### Example 1: _Advanced features_ + +This instance deploys the module with advanced features like custom tables and data exports. + + +

+ +via Bicep module + +```bicep +module workspace 'br/public:avm/res/operational-insights/workspace:' = { + name: 'workspaceDeployment' + params: { + // Required parameters + name: 'oiwadv001' + // Non-required parameters + dailyQuotaGb: 10 + dataExports: [ + { + destination: { + metaData: { + eventHubName: '' + } + resourceId: '' + } + enable: true + name: 'eventHubExport' + tableNames: [ + 'Alert' + 'InsightsMetrics' + ] + } + { + destination: { + resourceId: '' + } + enable: true + name: 'storageAccountExport' + tableNames: [ + 'Operation' + ] + } + ] + dataSources: [ + { + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + { + kind: 'LinuxSyslog' + name: 'sampleSyslog1' + syslogName: 'kern' + syslogSeverities: [ + { + severity: 'emerg' + } + { + severity: 'alert' + } + { + severity: 'crit' + } + { + severity: 'err' + } + { + severity: 'warning' + } + ] + } + { + kind: 'LinuxSyslogCollection' + name: 'sampleSyslogCollection1' + state: 'Enabled' + } + { + instanceName: '*' + intervalSeconds: 10 + kind: 'LinuxPerformanceObject' + name: 'sampleLinuxPerf1' + objectName: 'Logical Disk' + syslogSeverities: [ + { + counterName: '% Used Inodes' + } + { + counterName: 'Free Megabytes' + } + { + counterName: '% Used Space' + } + { + counterName: 'Disk Transfers/sec' + } + { + counterName: 'Disk Reads/sec' + } + { + counterName: 'Disk Writes/sec' + } + ] + } + { + kind: 'LinuxPerformanceCollection' + name: 'sampleLinuxPerfCollection1' + state: 'Enabled' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + { + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'sendingDiagnosticSettingsToSelf' + useThisWorkspace: true + } + ] + features: { + enableLogAccessUsingOnlyResourcePermissions: true + } + gallerySolutions: [ + { + name: 'AzureAutomation(oiwadv001)' + plan: { + product: 'OMSGallery/AzureAutomation' + } + } + ] + linkedServices: [ + { + name: 'Automation' + resourceId: '' + } + ] + linkedStorageAccounts: [ + { + name: 'Query' + storageAccountIds: [ + '' + ] + } + ] + location: '' + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + publicNetworkAccessForIngestion: 'Disabled' + publicNetworkAccessForQuery: 'Disabled' + savedSearches: [ + { + category: 'VDC Saved Searches' + displayName: 'VMSS Instance Count2' + name: 'VMSSQueries' + query: 'Event | where Source == ServiceFabricNodeBootstrapAgent | summarize AggregatedValue = count() by Computer' + } + ] + storageInsightsConfigs: [ + { + storageAccountResourceId: '' + tables: [ + 'LinuxsyslogVer2v0' + 'WADETWEventTable' + 'WADServiceFabric*EventTable' + 'WADWindowsEventLogsTable' + ] + } + ] + tables: [ + { + name: 'CustomTableBasic_CL' + retentionInDays: 60 + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + schema: { + columns: [ + { + name: 'TimeGenerated' + type: 'dateTime' + } + { + name: 'RawData' + type: 'string' + } + ] + name: 'CustomTableBasic_CL' + } + totalRetentionInDays: 90 + } + { + name: 'CustomTableAdvanced_CL' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + schema: { + columns: [ + { + name: 'TimeGenerated' + type: 'dateTime' + } + { + name: 'EventTime' + type: 'dateTime' + } + { + name: 'EventLevel' + type: 'string' + } + { + name: 'EventCode' + type: 'int' + } + { + name: 'Message' + type: 'string' + } + { + name: 'RawData' + type: 'string' + } + ] + name: 'CustomTableAdvanced_CL' + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "oiwadv001" + }, + // Non-required parameters + "dailyQuotaGb": { + "value": 10 + }, + "dataExports": { + "value": [ + { + "destination": { + "metaData": { + "eventHubName": "" + }, + "resourceId": "" + }, + "enable": true, + "name": "eventHubExport", + "tableNames": [ + "Alert", + "InsightsMetrics" + ] + }, + { + "destination": { + "resourceId": "" + }, + "enable": true, + "name": "storageAccountExport", + "tableNames": [ + "Operation" + ] + } + ] + }, + "dataSources": { + "value": [ + { + "eventLogName": "Application", + "eventTypes": [ + { + "eventType": "Error" + }, + { + "eventType": "Warning" + }, + { + "eventType": "Information" + } + ], + "kind": "WindowsEvent", + "name": "applicationEvent" + }, + { + "counterName": "% Processor Time", + "instanceName": "*", + "intervalSeconds": 60, + "kind": "WindowsPerformanceCounter", + "name": "windowsPerfCounter1", + "objectName": "Processor" + }, + { + "kind": "IISLogs", + "name": "sampleIISLog1", + "state": "OnPremiseEnabled" + }, + { + "kind": "LinuxSyslog", + "name": "sampleSyslog1", + "syslogName": "kern", + "syslogSeverities": [ + { + "severity": "emerg" + }, + { + "severity": "alert" + }, + { + "severity": "crit" + }, + { + "severity": "err" + }, + { + "severity": "warning" + } + ] + }, + { + "kind": "LinuxSyslogCollection", + "name": "sampleSyslogCollection1", + "state": "Enabled" + }, + { + "instanceName": "*", + "intervalSeconds": 10, + "kind": "LinuxPerformanceObject", + "name": "sampleLinuxPerf1", + "objectName": "Logical Disk", + "syslogSeverities": [ + { + "counterName": "% Used Inodes" + }, + { + "counterName": "Free Megabytes" + }, + { + "counterName": "% Used Space" + }, + { + "counterName": "Disk Transfers/sec" + }, + { + "counterName": "Disk Reads/sec" + }, + { + "counterName": "Disk Writes/sec" + } + ] + }, + { + "kind": "LinuxPerformanceCollection", + "name": "sampleLinuxPerfCollection1", + "state": "Enabled" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + }, + { + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "sendingDiagnosticSettingsToSelf", + "useThisWorkspace": true + } + ] + }, + "features": { + "value": { + "enableLogAccessUsingOnlyResourcePermissions": true + } + }, + "gallerySolutions": { + "value": [ + { + "name": "AzureAutomation(oiwadv001)", + "plan": { + "product": "OMSGallery/AzureAutomation" + } + } + ] + }, + "linkedServices": { + "value": [ + { + "name": "Automation", + "resourceId": "" + } + ] + }, + "linkedStorageAccounts": { + "value": [ + { + "name": "Query", + "storageAccountIds": [ + "" + ] + } + ] + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "publicNetworkAccessForIngestion": { + "value": "Disabled" + }, + "publicNetworkAccessForQuery": { + "value": "Disabled" + }, + "savedSearches": { + "value": [ + { + "category": "VDC Saved Searches", + "displayName": "VMSS Instance Count2", + "name": "VMSSQueries", + "query": "Event | where Source == ServiceFabricNodeBootstrapAgent | summarize AggregatedValue = count() by Computer" + } + ] + }, + "storageInsightsConfigs": { + "value": [ + { + "storageAccountResourceId": "", + "tables": [ + "LinuxsyslogVer2v0", + "WADETWEventTable", + "WADServiceFabric*EventTable", + "WADWindowsEventLogsTable" + ] + } + ] + }, + "tables": { + "value": [ + { + "name": "CustomTableBasic_CL", + "retentionInDays": 60, + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "schema": { + "columns": [ + { + "name": "TimeGenerated", + "type": "dateTime" + }, + { + "name": "RawData", + "type": "string" + } + ], + "name": "CustomTableBasic_CL" + }, + "totalRetentionInDays": 90 + }, + { + "name": "CustomTableAdvanced_CL", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "schema": { + "columns": [ + { + "name": "TimeGenerated", + "type": "dateTime" + }, + { + "name": "EventTime", + "type": "dateTime" + }, + { + "name": "EventLevel", + "type": "string" + }, + { + "name": "EventCode", + "type": "int" + }, + { + "name": "Message", + "type": "string" + }, + { + "name": "RawData", + "type": "string" + } + ], + "name": "CustomTableAdvanced_CL" + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operational-insights/workspace:' + +// Required parameters +param name = 'oiwadv001' +// Non-required parameters +param dailyQuotaGb = 10 +param dataExports = [ + { + destination: { + metaData: { + eventHubName: '' + } + resourceId: '' + } + enable: true + name: 'eventHubExport' + tableNames: [ + 'Alert' + 'InsightsMetrics' + ] + } + { + destination: { + resourceId: '' + } + enable: true + name: 'storageAccountExport' + tableNames: [ + 'Operation' + ] + } +] +param dataSources = [ + { + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + { + kind: 'LinuxSyslog' + name: 'sampleSyslog1' + syslogName: 'kern' + syslogSeverities: [ + { + severity: 'emerg' + } + { + severity: 'alert' + } + { + severity: 'crit' + } + { + severity: 'err' + } + { + severity: 'warning' + } + ] + } + { + kind: 'LinuxSyslogCollection' + name: 'sampleSyslogCollection1' + state: 'Enabled' + } + { + instanceName: '*' + intervalSeconds: 10 + kind: 'LinuxPerformanceObject' + name: 'sampleLinuxPerf1' + objectName: 'Logical Disk' + syslogSeverities: [ + { + counterName: '% Used Inodes' + } + { + counterName: 'Free Megabytes' + } + { + counterName: '% Used Space' + } + { + counterName: 'Disk Transfers/sec' + } + { + counterName: 'Disk Reads/sec' + } + { + counterName: 'Disk Writes/sec' + } + ] + } + { + kind: 'LinuxPerformanceCollection' + name: 'sampleLinuxPerfCollection1' + state: 'Enabled' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + { + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'sendingDiagnosticSettingsToSelf' + useThisWorkspace: true + } +] +param features = { + enableLogAccessUsingOnlyResourcePermissions: true +} +param gallerySolutions = [ + { + name: 'AzureAutomation(oiwadv001)' + plan: { + product: 'OMSGallery/AzureAutomation' + } + } +] +param linkedServices = [ + { + name: 'Automation' + resourceId: '' + } +] +param linkedStorageAccounts = [ + { + name: 'Query' + storageAccountIds: [ + '' + ] + } +] +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param publicNetworkAccessForIngestion = 'Disabled' +param publicNetworkAccessForQuery = 'Disabled' +param savedSearches = [ + { + category: 'VDC Saved Searches' + displayName: 'VMSS Instance Count2' + name: 'VMSSQueries' + query: 'Event | where Source == ServiceFabricNodeBootstrapAgent | summarize AggregatedValue = count() by Computer' + } +] +param storageInsightsConfigs = [ + { + storageAccountResourceId: '' + tables: [ + 'LinuxsyslogVer2v0' + 'WADETWEventTable' + 'WADServiceFabric*EventTable' + 'WADWindowsEventLogsTable' + ] + } +] +param tables = [ + { + name: 'CustomTableBasic_CL' + retentionInDays: 60 + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + schema: { + columns: [ + { + name: 'TimeGenerated' + type: 'dateTime' + } + { + name: 'RawData' + type: 'string' + } + ] + name: 'CustomTableBasic_CL' + } + totalRetentionInDays: 90 + } + { + name: 'CustomTableAdvanced_CL' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + schema: { + columns: [ + { + name: 'TimeGenerated' + type: 'dateTime' + } + { + name: 'EventTime' + type: 'dateTime' + } + { + name: 'EventLevel' + type: 'string' + } + { + name: 'EventCode' + type: 'int' + } + { + name: 'Message' + type: 'string' + } + { + name: 'RawData' + type: 'string' + } + ] + name: 'CustomTableAdvanced_CL' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 2: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module workspace 'br/public:avm/res/operational-insights/workspace:' = { + name: 'workspaceDeployment' + params: { + // Required parameters + name: 'oiwmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "oiwmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operational-insights/workspace:' + +// Required parameters +param name = 'oiwmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 3: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module workspace 'br/public:avm/res/operational-insights/workspace:' = { + name: 'workspaceDeployment' + params: { + // Required parameters + name: 'oiwmax001' + // Non-required parameters + dailyQuotaGb: 10 + dataSources: [ + { + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + { + kind: 'LinuxSyslog' + name: 'sampleSyslog1' + syslogName: 'kern' + syslogSeverities: [ + { + severity: 'emerg' + } + { + severity: 'alert' + } + { + severity: 'crit' + } + { + severity: 'err' + } + { + severity: 'warning' + } + ] + } + { + kind: 'LinuxSyslogCollection' + name: 'sampleSyslogCollection1' + state: 'Enabled' + } + { + instanceName: '*' + intervalSeconds: 10 + kind: 'LinuxPerformanceObject' + name: 'sampleLinuxPerf1' + objectName: 'Logical Disk' + syslogSeverities: [ + { + counterName: '% Used Inodes' + } + { + counterName: 'Free Megabytes' + } + { + counterName: '% Used Space' + } + { + counterName: 'Disk Transfers/sec' + } + { + counterName: 'Disk Reads/sec' + } + { + counterName: 'Disk Writes/sec' + } + ] + } + { + kind: 'LinuxPerformanceCollection' + name: 'sampleLinuxPerfCollection1' + state: 'Enabled' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + features: { + disableLocalAuth: true + enableDataExport: true + enableLogAccessUsingOnlyResourcePermissions: true + immediatePurgeDataOn30Days: true + } + gallerySolutions: [ + { + name: 'AzureAutomation(oiwmax001)' + plan: { + product: 'OMSGallery/AzureAutomation' + } + } + { + name: 'SecurityInsights(oiwmax001)' + plan: { + product: 'OMSGallery/SecurityInsights' + publisher: 'Microsoft' + } + } + { + name: 'SQLAuditing(oiwmax001)' + plan: { + name: 'SQLAuditing(oiwmax001)' + product: 'SQLAuditing' + publisher: 'Microsoft' + } + } + ] + linkedServices: [ + { + name: 'Automation' + resourceId: '' + } + ] + linkedStorageAccounts: [ + { + name: 'Query' + storageAccountIds: [ + '' + ] + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: true + } + onboardWorkspaceToSentinel: true + publicNetworkAccessForIngestion: 'Disabled' + publicNetworkAccessForQuery: 'Disabled' + roleAssignments: [ + { + name: 'c3d53092-840c-4025-9c02-9bcb7895789c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + savedSearches: [ + { + category: 'VDC Saved Searches' + displayName: 'VMSS Instance Count2' + name: 'VMSSQueries' + query: 'Event | where Source == ServiceFabricNodeBootstrapAgent | summarize AggregatedValue = count() by Computer' + tags: [ + { + Name: 'Environment' + Value: 'Non-Prod' + } + { + Name: 'Role' + Value: 'DeploymentValidation' + } + ] + } + ] + storageInsightsConfigs: [ + { + storageAccountResourceId: '' + tables: [ + 'LinuxsyslogVer2v0' + 'WADETWEventTable' + 'WADServiceFabric*EventTable' + 'WADWindowsEventLogsTable' + ] + } + ] + tables: [ + { + name: 'CustomTableBasic_CL' + retentionInDays: 60 + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + schema: { + columns: [ + { + name: 'TimeGenerated' + type: 'dateTime' + } + { + name: 'RawData' + type: 'string' + } + ] + name: 'CustomTableBasic_CL' + } + totalRetentionInDays: 90 + } + { + name: 'CustomTableAdvanced_CL' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + schema: { + columns: [ + { + name: 'TimeGenerated' + type: 'dateTime' + } + { + name: 'EventTime' + type: 'dateTime' + } + { + name: 'EventLevel' + type: 'string' + } + { + name: 'EventCode' + type: 'int' + } + { + name: 'Message' + type: 'string' + } + { + name: 'RawData' + type: 'string' + } + ] + name: 'CustomTableAdvanced_CL' + } + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "oiwmax001" + }, + // Non-required parameters + "dailyQuotaGb": { + "value": 10 + }, + "dataSources": { + "value": [ + { + "eventLogName": "Application", + "eventTypes": [ + { + "eventType": "Error" + }, + { + "eventType": "Warning" + }, + { + "eventType": "Information" + } + ], + "kind": "WindowsEvent", + "name": "applicationEvent" + }, + { + "counterName": "% Processor Time", + "instanceName": "*", + "intervalSeconds": 60, + "kind": "WindowsPerformanceCounter", + "name": "windowsPerfCounter1", + "objectName": "Processor" + }, + { + "kind": "IISLogs", + "name": "sampleIISLog1", + "state": "OnPremiseEnabled" + }, + { + "kind": "LinuxSyslog", + "name": "sampleSyslog1", + "syslogName": "kern", + "syslogSeverities": [ + { + "severity": "emerg" + }, + { + "severity": "alert" + }, + { + "severity": "crit" + }, + { + "severity": "err" + }, + { + "severity": "warning" + } + ] + }, + { + "kind": "LinuxSyslogCollection", + "name": "sampleSyslogCollection1", + "state": "Enabled" + }, + { + "instanceName": "*", + "intervalSeconds": 10, + "kind": "LinuxPerformanceObject", + "name": "sampleLinuxPerf1", + "objectName": "Logical Disk", + "syslogSeverities": [ + { + "counterName": "% Used Inodes" + }, + { + "counterName": "Free Megabytes" + }, + { + "counterName": "% Used Space" + }, + { + "counterName": "Disk Transfers/sec" + }, + { + "counterName": "Disk Reads/sec" + }, + { + "counterName": "Disk Writes/sec" + } + ] + }, + { + "kind": "LinuxPerformanceCollection", + "name": "sampleLinuxPerfCollection1", + "state": "Enabled" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "features": { + "value": { + "disableLocalAuth": true, + "enableDataExport": true, + "enableLogAccessUsingOnlyResourcePermissions": true, + "immediatePurgeDataOn30Days": true + } + }, + "gallerySolutions": { + "value": [ + { + "name": "AzureAutomation(oiwmax001)", + "plan": { + "product": "OMSGallery/AzureAutomation" + } + }, + { + "name": "SecurityInsights(oiwmax001)", + "plan": { + "product": "OMSGallery/SecurityInsights", + "publisher": "Microsoft" + } + }, + { + "name": "SQLAuditing(oiwmax001)", + "plan": { + "name": "SQLAuditing(oiwmax001)", + "product": "SQLAuditing", + "publisher": "Microsoft" + } + } + ] + }, + "linkedServices": { + "value": [ + { + "name": "Automation", + "resourceId": "" + } + ] + }, + "linkedStorageAccounts": { + "value": [ + { + "name": "Query", + "storageAccountIds": [ + "" + ] + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "onboardWorkspaceToSentinel": { + "value": true + }, + "publicNetworkAccessForIngestion": { + "value": "Disabled" + }, + "publicNetworkAccessForQuery": { + "value": "Disabled" + }, + "roleAssignments": { + "value": [ + { + "name": "c3d53092-840c-4025-9c02-9bcb7895789c", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "savedSearches": { + "value": [ + { + "category": "VDC Saved Searches", + "displayName": "VMSS Instance Count2", + "name": "VMSSQueries", + "query": "Event | where Source == ServiceFabricNodeBootstrapAgent | summarize AggregatedValue = count() by Computer", + "tags": [ + { + "Name": "Environment", + "Value": "Non-Prod" + }, + { + "Name": "Role", + "Value": "DeploymentValidation" + } + ] + } + ] + }, + "storageInsightsConfigs": { + "value": [ + { + "storageAccountResourceId": "", + "tables": [ + "LinuxsyslogVer2v0", + "WADETWEventTable", + "WADServiceFabric*EventTable", + "WADWindowsEventLogsTable" + ] + } + ] + }, + "tables": { + "value": [ + { + "name": "CustomTableBasic_CL", + "retentionInDays": 60, + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "schema": { + "columns": [ + { + "name": "TimeGenerated", + "type": "dateTime" + }, + { + "name": "RawData", + "type": "string" + } + ], + "name": "CustomTableBasic_CL" + }, + "totalRetentionInDays": 90 + }, + { + "name": "CustomTableAdvanced_CL", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "schema": { + "columns": [ + { + "name": "TimeGenerated", + "type": "dateTime" + }, + { + "name": "EventTime", + "type": "dateTime" + }, + { + "name": "EventLevel", + "type": "string" + }, + { + "name": "EventCode", + "type": "int" + }, + { + "name": "Message", + "type": "string" + }, + { + "name": "RawData", + "type": "string" + } + ], + "name": "CustomTableAdvanced_CL" + } + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operational-insights/workspace:' + +// Required parameters +param name = 'oiwmax001' +// Non-required parameters +param dailyQuotaGb = 10 +param dataSources = [ + { + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + { + kind: 'LinuxSyslog' + name: 'sampleSyslog1' + syslogName: 'kern' + syslogSeverities: [ + { + severity: 'emerg' + } + { + severity: 'alert' + } + { + severity: 'crit' + } + { + severity: 'err' + } + { + severity: 'warning' + } + ] + } + { + kind: 'LinuxSyslogCollection' + name: 'sampleSyslogCollection1' + state: 'Enabled' + } + { + instanceName: '*' + intervalSeconds: 10 + kind: 'LinuxPerformanceObject' + name: 'sampleLinuxPerf1' + objectName: 'Logical Disk' + syslogSeverities: [ + { + counterName: '% Used Inodes' + } + { + counterName: 'Free Megabytes' + } + { + counterName: '% Used Space' + } + { + counterName: 'Disk Transfers/sec' + } + { + counterName: 'Disk Reads/sec' + } + { + counterName: 'Disk Writes/sec' + } + ] + } + { + kind: 'LinuxPerformanceCollection' + name: 'sampleLinuxPerfCollection1' + state: 'Enabled' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param features = { + disableLocalAuth: true + enableDataExport: true + enableLogAccessUsingOnlyResourcePermissions: true + immediatePurgeDataOn30Days: true +} +param gallerySolutions = [ + { + name: 'AzureAutomation(oiwmax001)' + plan: { + product: 'OMSGallery/AzureAutomation' + } + } + { + name: 'SecurityInsights(oiwmax001)' + plan: { + product: 'OMSGallery/SecurityInsights' + publisher: 'Microsoft' + } + } + { + name: 'SQLAuditing(oiwmax001)' + plan: { + name: 'SQLAuditing(oiwmax001)' + product: 'SQLAuditing' + publisher: 'Microsoft' + } + } +] +param linkedServices = [ + { + name: 'Automation' + resourceId: '' + } +] +param linkedStorageAccounts = [ + { + name: 'Query' + storageAccountIds: [ + '' + ] + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param onboardWorkspaceToSentinel = true +param publicNetworkAccessForIngestion = 'Disabled' +param publicNetworkAccessForQuery = 'Disabled' +param roleAssignments = [ + { + name: 'c3d53092-840c-4025-9c02-9bcb7895789c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param savedSearches = [ + { + category: 'VDC Saved Searches' + displayName: 'VMSS Instance Count2' + name: 'VMSSQueries' + query: 'Event | where Source == ServiceFabricNodeBootstrapAgent | summarize AggregatedValue = count() by Computer' + tags: [ + { + Name: 'Environment' + Value: 'Non-Prod' + } + { + Name: 'Role' + Value: 'DeploymentValidation' + } + ] + } +] +param storageInsightsConfigs = [ + { + storageAccountResourceId: '' + tables: [ + 'LinuxsyslogVer2v0' + 'WADETWEventTable' + 'WADServiceFabric*EventTable' + 'WADWindowsEventLogsTable' + ] + } +] +param tables = [ + { + name: 'CustomTableBasic_CL' + retentionInDays: 60 + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + schema: { + columns: [ + { + name: 'TimeGenerated' + type: 'dateTime' + } + { + name: 'RawData' + type: 'string' + } + ] + name: 'CustomTableBasic_CL' + } + totalRetentionInDays: 90 + } + { + name: 'CustomTableAdvanced_CL' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + schema: { + columns: [ + { + name: 'TimeGenerated' + type: 'dateTime' + } + { + name: 'EventTime' + type: 'dateTime' + } + { + name: 'EventLevel' + type: 'string' + } + { + name: 'EventCode' + type: 'int' + } + { + name: 'Message' + type: 'string' + } + { + name: 'RawData' + type: 'string' + } + ] + name: 'CustomTableAdvanced_CL' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 4: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module workspace 'br/public:avm/res/operational-insights/workspace:' = { + name: 'workspaceDeployment' + params: { + // Required parameters + name: 'oiwwaf001' + // Non-required parameters + dailyQuotaGb: 10 + dataSources: [ + { + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + { + kind: 'LinuxSyslog' + name: 'sampleSyslog1' + syslogName: 'kern' + syslogSeverities: [ + { + severity: 'emerg' + } + { + severity: 'alert' + } + { + severity: 'crit' + } + { + severity: 'err' + } + { + severity: 'warning' + } + ] + } + { + kind: 'LinuxSyslogCollection' + name: 'sampleSyslogCollection1' + state: 'Enabled' + } + { + instanceName: '*' + intervalSeconds: 10 + kind: 'LinuxPerformanceObject' + name: 'sampleLinuxPerf1' + objectName: 'Logical Disk' + syslogSeverities: [ + { + counterName: '% Used Inodes' + } + { + counterName: 'Free Megabytes' + } + { + counterName: '% Used Space' + } + { + counterName: 'Disk Transfers/sec' + } + { + counterName: 'Disk Reads/sec' + } + { + counterName: 'Disk Writes/sec' + } + ] + } + { + kind: 'LinuxPerformanceCollection' + name: 'sampleLinuxPerfCollection1' + state: 'Enabled' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + features: { + enableLogAccessUsingOnlyResourcePermissions: true + } + gallerySolutions: [ + { + name: 'AzureAutomation(oiwwaf001)' + plan: { + product: 'OMSGallery/AzureAutomation' + } + } + ] + linkedServices: [ + { + name: 'Automation' + resourceId: '' + } + ] + linkedStorageAccounts: [ + { + name: 'Query' + storageAccountIds: [ + '' + ] + } + ] + location: '' + managedIdentities: { + systemAssigned: true + } + publicNetworkAccessForIngestion: 'Disabled' + publicNetworkAccessForQuery: 'Disabled' + storageInsightsConfigs: [ + { + storageAccountResourceId: '' + tables: [ + 'LinuxsyslogVer2v0' + 'WADETWEventTable' + 'WADServiceFabric*EventTable' + 'WADWindowsEventLogsTable' + ] + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "oiwwaf001" + }, + // Non-required parameters + "dailyQuotaGb": { + "value": 10 + }, + "dataSources": { + "value": [ + { + "eventLogName": "Application", + "eventTypes": [ + { + "eventType": "Error" + }, + { + "eventType": "Warning" + }, + { + "eventType": "Information" + } + ], + "kind": "WindowsEvent", + "name": "applicationEvent" + }, + { + "counterName": "% Processor Time", + "instanceName": "*", + "intervalSeconds": 60, + "kind": "WindowsPerformanceCounter", + "name": "windowsPerfCounter1", + "objectName": "Processor" + }, + { + "kind": "IISLogs", + "name": "sampleIISLog1", + "state": "OnPremiseEnabled" + }, + { + "kind": "LinuxSyslog", + "name": "sampleSyslog1", + "syslogName": "kern", + "syslogSeverities": [ + { + "severity": "emerg" + }, + { + "severity": "alert" + }, + { + "severity": "crit" + }, + { + "severity": "err" + }, + { + "severity": "warning" + } + ] + }, + { + "kind": "LinuxSyslogCollection", + "name": "sampleSyslogCollection1", + "state": "Enabled" + }, + { + "instanceName": "*", + "intervalSeconds": 10, + "kind": "LinuxPerformanceObject", + "name": "sampleLinuxPerf1", + "objectName": "Logical Disk", + "syslogSeverities": [ + { + "counterName": "% Used Inodes" + }, + { + "counterName": "Free Megabytes" + }, + { + "counterName": "% Used Space" + }, + { + "counterName": "Disk Transfers/sec" + }, + { + "counterName": "Disk Reads/sec" + }, + { + "counterName": "Disk Writes/sec" + } + ] + }, + { + "kind": "LinuxPerformanceCollection", + "name": "sampleLinuxPerfCollection1", + "state": "Enabled" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "features": { + "value": { + "enableLogAccessUsingOnlyResourcePermissions": true + } + }, + "gallerySolutions": { + "value": [ + { + "name": "AzureAutomation(oiwwaf001)", + "plan": { + "product": "OMSGallery/AzureAutomation" + } + } + ] + }, + "linkedServices": { + "value": [ + { + "name": "Automation", + "resourceId": "" + } + ] + }, + "linkedStorageAccounts": { + "value": [ + { + "name": "Query", + "storageAccountIds": [ + "" + ] + } + ] + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "publicNetworkAccessForIngestion": { + "value": "Disabled" + }, + "publicNetworkAccessForQuery": { + "value": "Disabled" + }, + "storageInsightsConfigs": { + "value": [ + { + "storageAccountResourceId": "", + "tables": [ + "LinuxsyslogVer2v0", + "WADETWEventTable", + "WADServiceFabric*EventTable", + "WADWindowsEventLogsTable" + ] + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operational-insights/workspace:' + +// Required parameters +param name = 'oiwwaf001' +// Non-required parameters +param dailyQuotaGb = 10 +param dataSources = [ + { + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + { + kind: 'LinuxSyslog' + name: 'sampleSyslog1' + syslogName: 'kern' + syslogSeverities: [ + { + severity: 'emerg' + } + { + severity: 'alert' + } + { + severity: 'crit' + } + { + severity: 'err' + } + { + severity: 'warning' + } + ] + } + { + kind: 'LinuxSyslogCollection' + name: 'sampleSyslogCollection1' + state: 'Enabled' + } + { + instanceName: '*' + intervalSeconds: 10 + kind: 'LinuxPerformanceObject' + name: 'sampleLinuxPerf1' + objectName: 'Logical Disk' + syslogSeverities: [ + { + counterName: '% Used Inodes' + } + { + counterName: 'Free Megabytes' + } + { + counterName: '% Used Space' + } + { + counterName: 'Disk Transfers/sec' + } + { + counterName: 'Disk Reads/sec' + } + { + counterName: 'Disk Writes/sec' + } + ] + } + { + kind: 'LinuxPerformanceCollection' + name: 'sampleLinuxPerfCollection1' + state: 'Enabled' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param features = { + enableLogAccessUsingOnlyResourcePermissions: true +} +param gallerySolutions = [ + { + name: 'AzureAutomation(oiwwaf001)' + plan: { + product: 'OMSGallery/AzureAutomation' + } + } +] +param linkedServices = [ + { + name: 'Automation' + resourceId: '' + } +] +param linkedStorageAccounts = [ + { + name: 'Query' + storageAccountIds: [ + '' + ] + } +] +param location = '' +param managedIdentities = { + systemAssigned: true +} +param publicNetworkAccessForIngestion = 'Disabled' +param publicNetworkAccessForQuery = 'Disabled' +param storageInsightsConfigs = [ + { + storageAccountResourceId: '' + tables: [ + 'LinuxsyslogVer2v0' + 'WADETWEventTable' + 'WADServiceFabric*EventTable' + 'WADWindowsEventLogsTable' + ] + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Log Analytics workspace. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`linkedStorageAccounts`](#parameter-linkedstorageaccounts) | array | List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dailyQuotaGb`](#parameter-dailyquotagb) | int | The workspace daily quota for ingestion. | +| [`dataExports`](#parameter-dataexports) | array | LAW data export instances to be deployed. | +| [`dataRetention`](#parameter-dataretention) | int | Number of days data will be retained for. | +| [`dataSources`](#parameter-datasources) | array | LAW data sources to configure. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`features`](#parameter-features) | object | The workspace features. | +| [`forceCmkForQuery`](#parameter-forcecmkforquery) | bool | Indicates whether customer managed storage is mandatory for query management. | +| [`gallerySolutions`](#parameter-gallerysolutions) | array | List of gallerySolutions to be created in the log analytics workspace. | +| [`linkedServices`](#parameter-linkedservices) | array | List of services to be linked. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both. | +| [`onboardWorkspaceToSentinel`](#parameter-onboardworkspacetosentinel) | bool | Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions. | +| [`publicNetworkAccessForIngestion`](#parameter-publicnetworkaccessforingestion) | string | The network access type for accessing Log Analytics ingestion. | +| [`publicNetworkAccessForQuery`](#parameter-publicnetworkaccessforquery) | string | The network access type for accessing Log Analytics query. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`savedSearches`](#parameter-savedsearches) | array | Kusto Query Language searches to save. | +| [`skuCapacityReservationLevel`](#parameter-skucapacityreservationlevel) | int | The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000. | +| [`skuName`](#parameter-skuname) | string | The name of the SKU. | +| [`storageInsightsConfigs`](#parameter-storageinsightsconfigs) | array | List of storage accounts to be read by the workspace. | +| [`tables`](#parameter-tables) | array | LAW custom tables to be deployed. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `name` + +Name of the Log Analytics workspace. + +- Required: Yes +- Type: string + +### Parameter: `linkedStorageAccounts` + +List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-linkedstorageaccountsname) | string | Name of the link. | +| [`storageAccountIds`](#parameter-linkedstorageaccountsstorageaccountids) | array | Linked storage accounts resources Ids. | + +### Parameter: `linkedStorageAccounts.name` + +Name of the link. + +- Required: Yes +- Type: string + +### Parameter: `linkedStorageAccounts.storageAccountIds` + +Linked storage accounts resources Ids. + +- Required: Yes +- Type: array + +### Parameter: `dailyQuotaGb` + +The workspace daily quota for ingestion. + +- Required: No +- Type: int +- Default: `-1` +- MinValue: -1 + +### Parameter: `dataExports` + +LAW data export instances to be deployed. + +- Required: No +- Type: array +- MinValue: -1 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-dataexportsname) | string | Name of the data export. | +| [`tableNames`](#parameter-dataexportstablenames) | array | The list of table names to export. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`destination`](#parameter-dataexportsdestination) | object | The destination of the data export. | +| [`enable`](#parameter-dataexportsenable) | bool | Enable or disable the data export. | + +### Parameter: `dataExports.name` + +Name of the data export. + +- Required: Yes +- Type: string +- MinValue: -1 + +### Parameter: `dataExports.tableNames` + +The list of table names to export. + +- Required: Yes +- Type: array +- MinValue: -1 + +### Parameter: `dataExports.destination` + +The destination of the data export. + +- Required: No +- Type: object +- MinValue: -1 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`resourceId`](#parameter-dataexportsdestinationresourceid) | string | The destination resource ID. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metaData`](#parameter-dataexportsdestinationmetadata) | object | The destination metadata. | + +### Parameter: `dataExports.destination.resourceId` + +The destination resource ID. + +- Required: Yes +- Type: string +- MinValue: -1 + +### Parameter: `dataExports.destination.metaData` + +The destination metadata. + +- Required: No +- Type: object +- MinValue: -1 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubName`](#parameter-dataexportsdestinationmetadataeventhubname) | string | Allows to define an Event Hub name. Not applicable when destination is Storage Account. | + +### Parameter: `dataExports.destination.metaData.eventHubName` + +Allows to define an Event Hub name. Not applicable when destination is Storage Account. + +- Required: No +- Type: string +- MinValue: -1 + +### Parameter: `dataExports.enable` + +Enable or disable the data export. + +- Required: No +- Type: bool +- MinValue: -1 + +### Parameter: `dataRetention` + +Number of days data will be retained for. + +- Required: No +- Type: int +- Default: `365` +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources` + +LAW data sources to configure. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 730 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-datasourceskind) | string | The kind of data source. | +| [`name`](#parameter-datasourcesname) | string | Name of the data source. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`counterName`](#parameter-datasourcescountername) | string | Counter name to configure when kind is WindowsPerformanceCounter. | +| [`eventLogName`](#parameter-datasourceseventlogname) | string | The name of the event log to configure when kind is WindowsEvent. | +| [`eventTypes`](#parameter-datasourceseventtypes) | array | The event types to configure when kind is WindowsEvent. | +| [`instanceName`](#parameter-datasourcesinstancename) | string | Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject. | +| [`intervalSeconds`](#parameter-datasourcesintervalseconds) | int | Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject. | +| [`linkedResourceId`](#parameter-datasourceslinkedresourceid) | string | The resource id of the resource that will be linked to the workspace. | +| [`objectName`](#parameter-datasourcesobjectname) | string | Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject. | +| [`performanceCounters`](#parameter-datasourcesperformancecounters) | array | List of counters to configure when the kind is LinuxPerformanceObject. | +| [`state`](#parameter-datasourcesstate) | string | State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection. | +| [`syslogName`](#parameter-datasourcessyslogname) | string | System log to configure when kind is LinuxSyslog. | +| [`syslogSeverities`](#parameter-datasourcessyslogseverities) | array | Severities to configure when kind is LinuxSyslog. | +| [`tags`](#parameter-datasourcestags) | object | Tags to configure in the resource. | + +### Parameter: `dataSources.kind` + +The kind of data source. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources.name` + +Name of the data source. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources.counterName` + +Counter name to configure when kind is WindowsPerformanceCounter. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources.eventLogName` + +The name of the event log to configure when kind is WindowsEvent. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources.eventTypes` + +The event types to configure when kind is WindowsEvent. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources.instanceName` + +Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources.intervalSeconds` + +Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject. + +- Required: No +- Type: int +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources.linkedResourceId` + +The resource id of the resource that will be linked to the workspace. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources.objectName` + +Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources.performanceCounters` + +List of counters to configure when the kind is LinuxPerformanceObject. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources.state` + +State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources.syslogName` + +System log to configure when kind is LinuxSyslog. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources.syslogSeverities` + +Severities to configure when kind is LinuxSyslog. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `dataSources.tags` + +Tags to configure in the resource. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 730 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`useThisWorkspace`](#parameter-diagnosticsettingsusethisworkspace) | bool | Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 730 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 730 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `diagnosticSettings.useThisWorkspace` + +Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `features` + +The workspace features. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 730 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`disableLocalAuth`](#parameter-featuresdisablelocalauth) | bool | Disable Non-EntraID based Auth. Default is true. | +| [`enableDataExport`](#parameter-featuresenabledataexport) | bool | Flag that indicate if data should be exported. | +| [`enableLogAccessUsingOnlyResourcePermissions`](#parameter-featuresenablelogaccessusingonlyresourcepermissions) | bool | Enable log access using only resource permissions. Default is false. | +| [`immediatePurgeDataOn30Days`](#parameter-featuresimmediatepurgedataon30days) | bool | Flag that describes if we want to remove the data after 30 days. | + +### Parameter: `features.disableLocalAuth` + +Disable Non-EntraID based Auth. Default is true. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `features.enableDataExport` + +Flag that indicate if data should be exported. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `features.enableLogAccessUsingOnlyResourcePermissions` + +Enable log access using only resource permissions. Default is false. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `features.immediatePurgeDataOn30Days` + +Flag that describes if we want to remove the data after 30 days. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `forceCmkForQuery` + +Indicates whether customer managed storage is mandatory for query management. + +- Required: No +- Type: bool +- Default: `True` +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `gallerySolutions` + +List of gallerySolutions to be created in the log analytics workspace. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 730 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-gallerysolutionsname) | string | Name of the solution.

For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.

For solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.

The solution type is case-sensitive. | +| [`plan`](#parameter-gallerysolutionsplan) | object | Plan for solution object supported by the OperationsManagement resource provider. | + +### Parameter: `gallerySolutions.name` + +Name of the solution.

For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.

For solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.

The solution type is case-sensitive. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `gallerySolutions.plan` + +Plan for solution object supported by the OperationsManagement resource provider. + +- Required: Yes +- Type: object +- MinValue: 0 +- MaxValue: 730 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`product`](#parameter-gallerysolutionsplanproduct) | string | The product name of the deployed solution.

For Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.

For a third party solution, it can be anything.

This is case sensitive. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-gallerysolutionsplanname) | string | Name of the solution to be created.

For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.

For solutions authored by third parties, it can be anything.

The solution type is case-sensitive.

If not provided, the value of the `name` parameter will be used. | +| [`publisher`](#parameter-gallerysolutionsplanpublisher) | string | The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value. | + +### Parameter: `gallerySolutions.plan.product` + +The product name of the deployed solution.

For Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.

For a third party solution, it can be anything.

This is case sensitive. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `gallerySolutions.plan.name` + +Name of the solution to be created.

For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.

For solutions authored by third parties, it can be anything.

The solution type is case-sensitive.

If not provided, the value of the `name` parameter will be used. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `gallerySolutions.plan.publisher` + +The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `linkedServices` + +List of services to be linked. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 730 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-linkedservicesname) | string | Name of the linked service. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`resourceId`](#parameter-linkedservicesresourceid) | string | The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access. | +| [`writeAccessResourceId`](#parameter-linkedserviceswriteaccessresourceid) | string | The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access. | + +### Parameter: `linkedServices.name` + +Name of the linked service. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `linkedServices.resourceId` + +The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `linkedServices.writeAccessResourceId` + +The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 730 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 730 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `onboardWorkspaceToSentinel` + +Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `publicNetworkAccessForIngestion` + +The network access type for accessing Log Analytics ingestion. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `publicNetworkAccessForQuery` + +The network access type for accessing Log Analytics query. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 730 +- Roles configurable by name: + - `'Contributor'` + - `'Log Analytics Contributor'` + - `'Log Analytics Reader'` + - `'Monitoring Contributor'` + - `'Monitoring Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'Security Admin'` + - `'Security Reader'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `savedSearches` + +Kusto Query Language searches to save. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 730 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-savedsearchescategory) | string | The category of the saved search. This helps the user to find a saved search faster. | +| [`displayName`](#parameter-savedsearchesdisplayname) | string | Display name for the search. | +| [`name`](#parameter-savedsearchesname) | string | Name of the saved search. | +| [`query`](#parameter-savedsearchesquery) | string | The query expression for the saved search. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`etag`](#parameter-savedsearchesetag) | string | The ETag of the saved search. To override an existing saved search, use "*" or specify the current Etag. | +| [`functionAlias`](#parameter-savedsearchesfunctionalias) | string | The function alias if query serves as a function. | +| [`functionParameters`](#parameter-savedsearchesfunctionparameters) | string | The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions. | +| [`tags`](#parameter-savedsearchestags) | array | The tags attached to the saved search. | +| [`version`](#parameter-savedsearchesversion) | int | The version number of the query language. The current version is 2 and is the default. | + +### Parameter: `savedSearches.category` + +The category of the saved search. This helps the user to find a saved search faster. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `savedSearches.displayName` + +Display name for the search. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `savedSearches.name` + +Name of the saved search. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `savedSearches.query` + +The query expression for the saved search. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `savedSearches.etag` + +The ETag of the saved search. To override an existing saved search, use "*" or specify the current Etag. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `savedSearches.functionAlias` + +The function alias if query serves as a function. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `savedSearches.functionParameters` + +The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `savedSearches.tags` + +The tags attached to the saved search. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `savedSearches.version` + +The version number of the query language. The current version is 2 and is the default. + +- Required: No +- Type: int +- MinValue: 0 +- MaxValue: 730 + +### Parameter: `skuCapacityReservationLevel` + +The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000. + +- Required: No +- Type: int +- Default: `100` +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `skuName` + +The name of the SKU. + +- Required: No +- Type: string +- Default: `'PerGB2018'` +- Allowed: + ```Bicep + [ + 'CapacityReservation' + 'Free' + 'LACluster' + 'PerGB2018' + 'PerNode' + 'Premium' + 'Standalone' + 'Standard' + ] + ``` +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `storageInsightsConfigs` + +List of storage accounts to be read by the workspace. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 5000 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageAccountResourceId`](#parameter-storageinsightsconfigsstorageaccountresourceid) | string | Resource ID of the storage account to be linked. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`containers`](#parameter-storageinsightsconfigscontainers) | array | The names of the blob containers that the workspace should read. | +| [`tables`](#parameter-storageinsightsconfigstables) | array | List of tables to be read by the workspace. | + +### Parameter: `storageInsightsConfigs.storageAccountResourceId` + +Resource ID of the storage account to be linked. + +- Required: Yes +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `storageInsightsConfigs.containers` + +The names of the blob containers that the workspace should read. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `storageInsightsConfigs.tables` + +List of tables to be read by the workspace. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables` + +LAW custom tables to be deployed. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 5000 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-tablesname) | string | The name of the table. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`plan`](#parameter-tablesplan) | string | The plan for the table. | +| [`restoredLogs`](#parameter-tablesrestoredlogs) | object | The restored logs for the table. | +| [`retentionInDays`](#parameter-tablesretentionindays) | int | The retention in days for the table. | +| [`roleAssignments`](#parameter-tablesroleassignments) | array | The role assignments for the table. | +| [`schema`](#parameter-tablesschema) | object | The schema for the table. | +| [`searchResults`](#parameter-tablessearchresults) | object | The search results for the table. | +| [`totalRetentionInDays`](#parameter-tablestotalretentionindays) | int | The total retention in days for the table. | + +### Parameter: `tables.name` + +The name of the table. + +- Required: Yes +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.plan` + +The plan for the table. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.restoredLogs` + +The restored logs for the table. + +- Required: No +- Type: object +- MinValue: 100 +- MaxValue: 5000 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`endRestoreTime`](#parameter-tablesrestoredlogsendrestoretime) | string | The timestamp to end the restore by (UTC). | +| [`sourceTable`](#parameter-tablesrestoredlogssourcetable) | string | The table to restore data from. | +| [`startRestoreTime`](#parameter-tablesrestoredlogsstartrestoretime) | string | The timestamp to start the restore from (UTC). | + +### Parameter: `tables.restoredLogs.endRestoreTime` + +The timestamp to end the restore by (UTC). + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.restoredLogs.sourceTable` + +The table to restore data from. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.restoredLogs.startRestoreTime` + +The timestamp to start the restore from (UTC). + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.retentionInDays` + +The retention in days for the table. + +- Required: No +- Type: int +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.roleAssignments` + +The role assignments for the table. + +- Required: No +- Type: array +- MinValue: 100 +- MaxValue: 5000 +- Roles configurable by name: + - `'Contributor'` + - `'Log Analytics Contributor'` + - `'Log Analytics Reader'` + - `'Monitoring Contributor'` + - `'Monitoring Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-tablesroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-tablesroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-tablesroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-tablesroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-tablesroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-tablesroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-tablesroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-tablesroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `tables.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.roleAssignments.condition` + +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". + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.schema` + +The schema for the table. + +- Required: No +- Type: object +- MinValue: 100 +- MaxValue: 5000 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`columns`](#parameter-tablesschemacolumns) | array | A list of table custom columns. | +| [`name`](#parameter-tablesschemaname) | string | The table name. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-tablesschemadescription) | string | The table description. | +| [`displayName`](#parameter-tablesschemadisplayname) | string | The table display name. | + +### Parameter: `tables.schema.columns` + +A list of table custom columns. + +- Required: Yes +- Type: array +- MinValue: 100 +- MaxValue: 5000 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-tablesschemacolumnsname) | string | The column name. | +| [`type`](#parameter-tablesschemacolumnstype) | string | The column type. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dataTypeHint`](#parameter-tablesschemacolumnsdatatypehint) | string | The column data type logical hint. | +| [`description`](#parameter-tablesschemacolumnsdescription) | string | The column description. | +| [`displayName`](#parameter-tablesschemacolumnsdisplayname) | string | Column display name. | + +### Parameter: `tables.schema.columns.name` + +The column name. + +- Required: Yes +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.schema.columns.type` + +The column type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'boolean' + 'dateTime' + 'dynamic' + 'guid' + 'int' + 'long' + 'real' + 'string' + ] + ``` +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.schema.columns.dataTypeHint` + +The column data type logical hint. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'armPath' + 'guid' + 'ip' + 'uri' + ] + ``` +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.schema.columns.description` + +The column description. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.schema.columns.displayName` + +Column display name. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.schema.name` + +The table name. + +- Required: Yes +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.schema.description` + +The table description. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.schema.displayName` + +The table display name. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.searchResults` + +The search results for the table. + +- Required: No +- Type: object +- MinValue: 100 +- MaxValue: 5000 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`query`](#parameter-tablessearchresultsquery) | string | The search job query. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-tablessearchresultsdescription) | string | The search description. | +| [`endSearchTime`](#parameter-tablessearchresultsendsearchtime) | string | The timestamp to end the search by (UTC). | +| [`limit`](#parameter-tablessearchresultslimit) | int | Limit the search job to return up to specified number of rows. | +| [`startSearchTime`](#parameter-tablessearchresultsstartsearchtime) | string | The timestamp to start the search from (UTC). | + +### Parameter: `tables.searchResults.query` + +The search job query. + +- Required: Yes +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.searchResults.description` + +The search description. + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.searchResults.endSearchTime` + +The timestamp to end the search by (UTC). + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.searchResults.limit` + +Limit the search job to return up to specified number of rows. + +- Required: No +- Type: int +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.searchResults.startSearchTime` + +The timestamp to start the search from (UTC). + +- Required: No +- Type: string +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tables.totalRetentionInDays` + +The total retention in days for the table. + +- Required: No +- Type: int +- MinValue: 100 +- MaxValue: 5000 + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- MinValue: 100 +- MaxValue: 5000 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `logAnalyticsWorkspaceId` | string | The ID associated with the workspace. | +| `name` | string | The name of the deployed log analytics workspace. | +| `resourceGroupName` | string | The resource group of the deployed log analytics workspace. | +| `resourceId` | string | The resource ID of the deployed log analytics workspace. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/operations-management/solution:0.3.0` | Remote reference | +| `br/public:avm/utl/types/avm-common-types:0.2.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/operational-insights/workspace/data-export/README.md b/avm/1.1.0/res/operational-insights/workspace/data-export/README.md new file mode 100644 index 000000000..f6438994a --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/data-export/README.md @@ -0,0 +1,120 @@ +# Log Analytics Workspace Data Exports `[Microsoft.OperationalInsights/workspaces/dataExports]` + +This module deploys a Log Analytics Workspace Data Export. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.OperationalInsights/workspaces/dataExports` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/dataExports) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The data export rule name. | +| [`tableNames`](#parameter-tablenames) | array | An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`workspaceName`](#parameter-workspacename) | string | The name of the parent workspaces. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`destination`](#parameter-destination) | object | Destination properties. | +| [`enable`](#parameter-enable) | bool | Active when enabled. | + +### Parameter: `name` + +The data export rule name. + +- Required: Yes +- Type: string + +### Parameter: `tableNames` + +An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']. + +- Required: Yes +- Type: array + +### Parameter: `workspaceName` + +The name of the parent workspaces. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `destination` + +Destination properties. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`resourceId`](#parameter-destinationresourceid) | string | The destination resource ID. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metaData`](#parameter-destinationmetadata) | object | The destination metadata. | + +### Parameter: `destination.resourceId` + +The destination resource ID. + +- Required: Yes +- Type: string + +### Parameter: `destination.metaData` + +The destination metadata. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubName`](#parameter-destinationmetadataeventhubname) | string | Allows to define an Event Hub name. Not applicable when destination is Storage Account. | + +### Parameter: `destination.metaData.eventHubName` + +Allows to define an Event Hub name. Not applicable when destination is Storage Account. + +- Required: No +- Type: string + +### Parameter: `enable` + +Active when enabled. + +- Required: No +- Type: bool +- Default: `False` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the data export. | +| `resourceGroupName` | string | The name of the resource group the data export was created in. | +| `resourceId` | string | The resource ID of the data export. | diff --git a/avm/1.1.0/res/operational-insights/workspace/data-export/main.bicep b/avm/1.1.0/res/operational-insights/workspace/data-export/main.bicep new file mode 100644 index 000000000..9c0bfa742 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/data-export/main.bicep @@ -0,0 +1,71 @@ +metadata name = 'Log Analytics Workspace Data Exports' +metadata description = 'This module deploys a Log Analytics Workspace Data Export.' + +// ============== // +// Parameters // +// ============== // + +@description('Required. The data export rule name.') +@minLength(4) +@maxLength(63) +param name string + +@description('Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment.') +param workspaceName string + +@description('Optional. Destination properties.') +param destination destinationType? + +@description('Optional. Active when enabled.') +param enable bool = false + +@minLength(1) +@description('Required. An array of tables to export, for example: [\'Heartbeat\', \'SecurityEvent\'].') +param tableNames string[] + +// =============== // +// Deployments // +// =============== // + +resource workspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' existing = { + name: workspaceName +} + +resource dataExport 'Microsoft.OperationalInsights/workspaces/dataExports@2023-09-01' = { + parent: workspace + name: name + properties: { + destination: destination + enable: enable + tableNames: tableNames + } +} + +// =========== // +// Outputs // +// =========== // + +@description('The name of the data export.') +output name string = dataExport.name + +@description('The resource ID of the data export.') +output resourceId string = dataExport.id + +@description('The name of the resource group the data export was created in.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +@export() +@description('The data export destination properties.') +type destinationType = { + @description('Required. The destination resource ID.') + resourceId: string + @description('Optional. The destination metadata.') + metaData: { + @description('Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account.') + eventHubName: string? + }? +} diff --git a/avm/1.1.0/res/operational-insights/workspace/data-export/main.json b/avm/1.1.0/res/operational-insights/workspace/data-export/main.json new file mode 100644 index 000000000..4b77c8885 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/data-export/main.json @@ -0,0 +1,128 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "15082251740316718256" + }, + "name": "Log Analytics Workspace Data Exports", + "description": "This module deploys a Log Analytics Workspace Data Export." + }, + "definitions": { + "destinationType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The destination resource ID." + } + }, + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination metadata." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The data export destination properties." + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 4, + "maxLength": 63, + "metadata": { + "description": "Required. The data export rule name." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "nullable": true, + "metadata": { + "description": "Optional. Destination properties." + } + }, + "enable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Active when enabled." + } + }, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('workspaceName')]" + }, + "dataExport": { + "type": "Microsoft.OperationalInsights/workspaces/dataExports", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "destination": "[parameters('destination')]", + "enable": "[parameters('enable')]", + "tableNames": "[parameters('tableNames')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the data export." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the data export." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the data export was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/operational-insights/workspace/data-source/README.md b/avm/1.1.0/res/operational-insights/workspace/data-source/README.md new file mode 100644 index 000000000..5236dc5c9 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/data-source/README.md @@ -0,0 +1,179 @@ +# Log Analytics Workspace Datasources `[Microsoft.OperationalInsights/workspaces/dataSources]` + +This module deploys a Log Analytics Workspace Data Source. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.OperationalInsights/workspaces/dataSources` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/dataSources) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the data source. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`logAnalyticsWorkspaceName`](#parameter-loganalyticsworkspacename) | string | The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`counterName`](#parameter-countername) | string | Counter name to configure when kind is WindowsPerformanceCounter. | +| [`eventLogName`](#parameter-eventlogname) | string | Windows event log name to configure when kind is WindowsEvent. | +| [`eventTypes`](#parameter-eventtypes) | array | Windows event types to configure when kind is WindowsEvent. | +| [`instanceName`](#parameter-instancename) | string | Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject. | +| [`intervalSeconds`](#parameter-intervalseconds) | int | Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject. | +| [`kind`](#parameter-kind) | string | The kind of the data source. | +| [`linkedResourceId`](#parameter-linkedresourceid) | string | Resource ID of the resource to be linked. | +| [`objectName`](#parameter-objectname) | string | Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject. | +| [`performanceCounters`](#parameter-performancecounters) | array | List of counters to configure when the kind is LinuxPerformanceObject. | +| [`state`](#parameter-state) | string | State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection. | +| [`syslogName`](#parameter-syslogname) | string | System log to configure when kind is LinuxSyslog. | +| [`syslogSeverities`](#parameter-syslogseverities) | array | Severities to configure when kind is LinuxSyslog. | +| [`tags`](#parameter-tags) | object | Tags to configure in the resource. | + +### Parameter: `name` + +Name of the data source. + +- Required: Yes +- Type: string + +### Parameter: `logAnalyticsWorkspaceName` + +The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `counterName` + +Counter name to configure when kind is WindowsPerformanceCounter. + +- Required: No +- Type: string + +### Parameter: `eventLogName` + +Windows event log name to configure when kind is WindowsEvent. + +- Required: No +- Type: string + +### Parameter: `eventTypes` + +Windows event types to configure when kind is WindowsEvent. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `instanceName` + +Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject. + +- Required: No +- Type: string +- Default: `'*'` + +### Parameter: `intervalSeconds` + +Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject. + +- Required: No +- Type: int +- Default: `60` + +### Parameter: `kind` + +The kind of the data source. + +- Required: No +- Type: string +- Default: `'AzureActivityLog'` +- Allowed: + ```Bicep + [ + 'AzureActivityLog' + 'IISLogs' + 'LinuxPerformanceCollection' + 'LinuxPerformanceObject' + 'LinuxSyslog' + 'LinuxSyslogCollection' + 'WindowsEvent' + 'WindowsPerformanceCounter' + ] + ``` + +### Parameter: `linkedResourceId` + +Resource ID of the resource to be linked. + +- Required: No +- Type: string + +### Parameter: `objectName` + +Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject. + +- Required: No +- Type: string + +### Parameter: `performanceCounters` + +List of counters to configure when the kind is LinuxPerformanceObject. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `state` + +State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection. + +- Required: No +- Type: string + +### Parameter: `syslogName` + +System log to configure when kind is LinuxSyslog. + +- Required: No +- Type: string + +### Parameter: `syslogSeverities` + +Severities to configure when kind is LinuxSyslog. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `tags` + +Tags to configure in the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed data source. | +| `resourceGroupName` | string | The resource group where the data source is deployed. | +| `resourceId` | string | The resource ID of the deployed data source. | diff --git a/avm/1.1.0/res/operational-insights/workspace/data-source/main.bicep b/avm/1.1.0/res/operational-insights/workspace/data-source/main.bicep new file mode 100644 index 000000000..aa62d3505 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/data-source/main.bicep @@ -0,0 +1,100 @@ +metadata name = 'Log Analytics Workspace Datasources' +metadata description = 'This module deploys a Log Analytics Workspace Data Source.' + +@description('Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment.') +param logAnalyticsWorkspaceName string + +@description('Required. Name of the data source.') +param name string + +@description('Optional. The kind of the data source.') +@allowed([ + 'AzureActivityLog' + 'WindowsEvent' + 'WindowsPerformanceCounter' + 'IISLogs' + 'LinuxSyslog' + 'LinuxSyslogCollection' + 'LinuxPerformanceObject' + 'LinuxPerformanceCollection' +]) +param kind string = 'AzureActivityLog' + +@description('Optional. Tags to configure in the resource.') +param tags object? + +@description('Optional. Resource ID of the resource to be linked.') +param linkedResourceId string? + +@description('Optional. Windows event log name to configure when kind is WindowsEvent.') +param eventLogName string? + +@description('Optional. Windows event types to configure when kind is WindowsEvent.') +param eventTypes array = [] + +@description('Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject.') +param objectName string? + +@description('Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject.') +param instanceName string = '*' + +@description('Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject.') +param intervalSeconds int = 60 + +@description('Optional. List of counters to configure when the kind is LinuxPerformanceObject.') +param performanceCounters array = [] + +@description('Optional. Counter name to configure when kind is WindowsPerformanceCounter.') +param counterName string? + +@description('Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection.') +param state string? + +@description('Optional. System log to configure when kind is LinuxSyslog.') +param syslogName string? + +@description('Optional. Severities to configure when kind is LinuxSyslog.') +param syslogSeverities array = [] + +resource workspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' existing = { + name: logAnalyticsWorkspaceName +} + +resource dataSource 'Microsoft.OperationalInsights/workspaces/dataSources@2023-09-01' = { + name: name + parent: workspace + kind: kind + tags: tags + properties: { + linkedResourceId: !empty(kind) && kind == 'AzureActivityLog' ? linkedResourceId : null + eventLogName: !empty(kind) && kind == 'WindowsEvent' ? eventLogName : null + eventTypes: !empty(kind) && kind == 'WindowsEvent' ? eventTypes : null + objectName: !empty(kind) && (kind == 'WindowsPerformanceCounter' || kind == 'LinuxPerformanceObject') + ? objectName + : null + instanceName: !empty(kind) && (kind == 'WindowsPerformanceCounter' || kind == 'LinuxPerformanceObject') + ? instanceName + : null + intervalSeconds: !empty(kind) && (kind == 'WindowsPerformanceCounter' || kind == 'LinuxPerformanceObject') + ? intervalSeconds + : null + counterName: !empty(kind) && kind == 'WindowsPerformanceCounter' ? counterName : null + state: !empty(kind) && (kind == 'IISLogs' || kind == 'LinuxSyslogCollection' || kind == 'LinuxPerformanceCollection') + ? state + : null + syslogName: !empty(kind) && kind == 'LinuxSyslog' ? syslogName : null + syslogSeverities: !empty(kind) && (kind == 'LinuxSyslog' || kind == 'LinuxPerformanceObject') + ? syslogSeverities + : null + performanceCounters: !empty(kind) && kind == 'LinuxPerformanceObject' ? performanceCounters : null + } +} + +@description('The resource ID of the deployed data source.') +output resourceId string = dataSource.id + +@description('The resource group where the data source is deployed.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the deployed data source.') +output name string = dataSource.name diff --git a/avm/1.1.0/res/operational-insights/workspace/data-source/main.json b/avm/1.1.0/res/operational-insights/workspace/data-source/main.json new file mode 100644 index 000000000..1a6b16e91 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/data-source/main.json @@ -0,0 +1,180 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "3186325409788999053" + }, + "name": "Log Analytics Workspace Datasources", + "description": "This module deploys a Log Analytics Workspace Data Source." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data source." + } + }, + "kind": { + "type": "string", + "defaultValue": "AzureActivityLog", + "allowedValues": [ + "AzureActivityLog", + "WindowsEvent", + "WindowsPerformanceCounter", + "IISLogs", + "LinuxSyslog", + "LinuxSyslogCollection", + "LinuxPerformanceObject", + "LinuxPerformanceCollection" + ], + "metadata": { + "description": "Optional. The kind of the data source." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + }, + "linkedResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the resource to be linked." + } + }, + "eventLogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Windows event log name to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Windows event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "defaultValue": 60, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "dataSource": { + "type": "Microsoft.OperationalInsights/workspaces/dataSources", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "kind": "[parameters('kind')]", + "tags": "[parameters('tags')]", + "properties": { + "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", + "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", + "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", + "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", + "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", + "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", + "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", + "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", + "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", + "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", + "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed data source." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the data source is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed data source." + }, + "value": "[parameters('name')]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/operational-insights/workspace/linked-service/README.md b/avm/1.1.0/res/operational-insights/workspace/linked-service/README.md new file mode 100644 index 000000000..75c3ecb00 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/linked-service/README.md @@ -0,0 +1,80 @@ +# Log Analytics Workspace Linked Services `[Microsoft.OperationalInsights/workspaces/linkedServices]` + +This module deploys a Log Analytics Workspace Linked Service. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.OperationalInsights/workspaces/linkedServices` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/linkedServices) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the link. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`logAnalyticsWorkspaceName`](#parameter-loganalyticsworkspacename) | string | The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`resourceId`](#parameter-resourceid) | string | The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access. | +| [`tags`](#parameter-tags) | object | Tags to configure in the resource. | +| [`writeAccessResourceId`](#parameter-writeaccessresourceid) | string | The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access. | + +### Parameter: `name` + +Name of the link. + +- Required: Yes +- Type: string + +### Parameter: `logAnalyticsWorkspaceName` + +The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `resourceId` + +The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access. + +- Required: No +- Type: string + +### Parameter: `tags` + +Tags to configure in the resource. + +- Required: No +- Type: object + +### Parameter: `writeAccessResourceId` + +The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed linked service. | +| `resourceGroupName` | string | The resource group where the linked service is deployed. | +| `resourceId` | string | The resource ID of the deployed linked service. | diff --git a/avm/1.1.0/res/operational-insights/workspace/linked-service/main.bicep b/avm/1.1.0/res/operational-insights/workspace/linked-service/main.bicep new file mode 100644 index 000000000..4d2a2a86b --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/linked-service/main.bicep @@ -0,0 +1,40 @@ +metadata name = 'Log Analytics Workspace Linked Services' +metadata description = 'This module deploys a Log Analytics Workspace Linked Service.' + +@description('Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment.') +param logAnalyticsWorkspaceName string + +@description('Required. Name of the link.') +param name string + +@description('Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access.') +param resourceId string? + +@description('Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access.') +param writeAccessResourceId string? + +@description('Optional. Tags to configure in the resource.') +param tags object? + +resource workspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' existing = { + name: logAnalyticsWorkspaceName +} + +resource linkedService 'Microsoft.OperationalInsights/workspaces/linkedServices@2023-09-01' = { + name: name + parent: workspace + tags: tags + properties: { + resourceId: resourceId + writeAccessResourceId: writeAccessResourceId + } +} + +@description('The name of the deployed linked service.') +output name string = linkedService.name + +@description('The resource ID of the deployed linked service.') +output resourceId string = linkedService.id + +@description('The resource group where the linked service is deployed.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/operational-insights/workspace/linked-service/main.json b/avm/1.1.0/res/operational-insights/workspace/linked-service/main.json new file mode 100644 index 000000000..370cdfc4e --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/linked-service/main.json @@ -0,0 +1,90 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "15202444687633091947" + }, + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + } + }, + "writeAccessResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedService": { + "type": "Microsoft.OperationalInsights/workspaces/linkedServices", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resourceId": "[parameters('resourceId')]", + "writeAccessResourceId": "[parameters('writeAccessResourceId')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked service." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked service is deployed." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/operational-insights/workspace/linked-storage-account/README.md b/avm/1.1.0/res/operational-insights/workspace/linked-storage-account/README.md new file mode 100644 index 000000000..85e4ef7b5 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/linked-storage-account/README.md @@ -0,0 +1,68 @@ +# Log Analytics Workspace Linked Storage Accounts `[Microsoft.OperationalInsights/workspaces/linkedStorageAccounts]` + +This module deploys a Log Analytics Workspace Linked Storage Account. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.OperationalInsights/workspaces/linkedStorageAccounts` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/linkedStorageAccounts) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the link. | +| [`storageAccountIds`](#parameter-storageaccountids) | array | Linked storage accounts resources Ids. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`logAnalyticsWorkspaceName`](#parameter-loganalyticsworkspacename) | string | The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment. | + +### Parameter: `name` + +Name of the link. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Alerts' + 'AzureWatson' + 'CustomLogs' + 'Query' + ] + ``` + +### Parameter: `storageAccountIds` + +Linked storage accounts resources Ids. + +- Required: Yes +- Type: array + +### Parameter: `logAnalyticsWorkspaceName` + +The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed linked storage account. | +| `resourceGroupName` | string | The resource group where the linked storage account is deployed. | +| `resourceId` | string | The resource ID of the deployed linked storage account. | diff --git a/avm/1.1.0/res/operational-insights/workspace/linked-storage-account/main.bicep b/avm/1.1.0/res/operational-insights/workspace/linked-storage-account/main.bicep new file mode 100644 index 000000000..5fc0c473e --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/linked-storage-account/main.bicep @@ -0,0 +1,39 @@ +metadata name = 'Log Analytics Workspace Linked Storage Accounts' +metadata description = 'This module deploys a Log Analytics Workspace Linked Storage Account.' + +@description('Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment.') +param logAnalyticsWorkspaceName string + +@description('Required. Name of the link.') +@allowed([ + 'Query' + 'Alerts' + 'CustomLogs' + 'AzureWatson' +]) +param name string + +@minLength(1) +@description('Required. Linked storage accounts resources Ids.') +param storageAccountIds string[] + +resource workspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' existing = { + name: logAnalyticsWorkspaceName +} + +resource linkedStorageAccount 'Microsoft.OperationalInsights/workspaces/linkedStorageAccounts@2023-09-01' = { + name: name + parent: workspace + properties: { + storageAccountIds: storageAccountIds + } +} + +@description('The name of the deployed linked storage account.') +output name string = linkedStorageAccount.name + +@description('The resource ID of the deployed linked storage account.') +output resourceId string = linkedStorageAccount.id + +@description('The resource group where the linked storage account is deployed.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/operational-insights/workspace/linked-storage-account/main.json b/avm/1.1.0/res/operational-insights/workspace/linked-storage-account/main.json new file mode 100644 index 000000000..603f7b3d2 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/linked-storage-account/main.json @@ -0,0 +1,83 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "1489251440210164837" + }, + "name": "Log Analytics Workspace Linked Storage Accounts", + "description": "This module deploys a Log Analytics Workspace Linked Storage Account." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "allowedValues": [ + "Query", + "Alerts", + "CustomLogs", + "AzureWatson" + ], + "metadata": { + "description": "Required. Name of the link." + } + }, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. Linked storage accounts resources Ids." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedStorageAccount": { + "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "storageAccountIds": "[parameters('storageAccountIds')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked storage account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked storage account." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked storage account is deployed." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/operational-insights/workspace/main.bicep b/avm/1.1.0/res/operational-insights/workspace/main.bicep new file mode 100644 index 000000000..d5b2e65c1 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/main.bicep @@ -0,0 +1,669 @@ +metadata name = 'Log Analytics Workspaces' +metadata description = 'This module deploys a Log Analytics Workspace.' + +@description('Required. Name of the Log Analytics workspace.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The name of the SKU.') +@allowed([ + 'CapacityReservation' + 'Free' + 'LACluster' + 'PerGB2018' + 'PerNode' + 'Premium' + 'Standalone' + 'Standard' +]) +param skuName string = 'PerGB2018' + +@minValue(100) +@maxValue(5000) +@description('Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000.') +param skuCapacityReservationLevel int = 100 + +@description('Optional. List of storage accounts to be read by the workspace.') +param storageInsightsConfigs storageInsightsConfigType[]? + +@description('Optional. List of services to be linked.') +param linkedServices linkedServiceType[]? + +@description('Conditional. List of Storage Accounts to be linked. Required if \'forceCmkForQuery\' is set to \'true\' and \'savedSearches\' is not empty.') +param linkedStorageAccounts linkedStorageAccountType[]? + +@description('Optional. Kusto Query Language searches to save.') +param savedSearches savedSearchType[]? + +@description('Optional. LAW data export instances to be deployed.') +param dataExports dataExportType[]? + +@description('Optional. LAW data sources to configure.') +param dataSources dataSourceType[]? + +@description('Optional. LAW custom tables to be deployed.') +param tables tableType[]? + +@description('Optional. List of gallerySolutions to be created in the log analytics workspace.') +param gallerySolutions gallerySolutionType[]? + +@description('Optional. Onboard the Log Analytics Workspace to Sentinel. Requires \'SecurityInsights\' solution to be in gallerySolutions.') +param onboardWorkspaceToSentinel bool = false + +@description('Optional. Number of days data will be retained for.') +@minValue(0) +@maxValue(730) +param dataRetention int = 365 + +@description('Optional. The workspace daily quota for ingestion.') +@minValue(-1) +param dailyQuotaGb int = -1 + +@description('Optional. The network access type for accessing Log Analytics ingestion.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccessForIngestion string = 'Enabled' + +@description('Optional. The network access type for accessing Log Analytics query.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccessForQuery string = 'Enabled' + +import { managedIdentityAllType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both.') +param managedIdentities managedIdentityAllType? + +@description('Optional. The workspace features.') +param features workspaceFeaturesType? + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType[]? + +@description('Optional. Indicates whether customer managed storage is mandatory for query management.') +param forceCmkForQuery bool = true + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? 'SystemAssigned' + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +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' + ) + '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') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'Security Admin': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'fb1c8493-542b-48eb-b624-b4c8fea62acd' + ) + 'Security Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '39bc4728-0917-49c7-9d2c-d95423bc2eb4' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.operationalinsights-workspace.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + location: location + name: name + tags: tags + properties: { + features: { + searchVersion: 1 + enableLogAccessUsingOnlyResourcePermissions: features.?enableLogAccessUsingOnlyResourcePermissions ?? false + disableLocalAuth: features.?disableLocalAuth ?? true + enableDataExport: features.?enableDataExport + immediatePurgeDataOn30Days: features.?immediatePurgeDataOn30Days + } + sku: { + name: skuName + capacityReservationLevel: skuName == 'CapacityReservation' ? skuCapacityReservationLevel : null + } + retentionInDays: dataRetention + workspaceCapping: { + dailyQuotaGb: dailyQuotaGb + } + publicNetworkAccessForIngestion: publicNetworkAccessForIngestion + publicNetworkAccessForQuery: publicNetworkAccessForQuery + forceCmkForQuery: forceCmkForQuery + } + identity: identity +} + +resource logAnalyticsWorkspace_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: (diagnosticSetting.?useThisWorkspace ?? false) + ? logAnalyticsWorkspace.id + : diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: logAnalyticsWorkspace + } +] + +module logAnalyticsWorkspace_storageInsightConfigs 'storage-insight-config/main.bicep' = [ + for (storageInsightsConfig, index) in storageInsightsConfigs ?? []: { + name: '${uniqueString(deployment().name, location)}-LAW-StorageInsightsConfig-${index}' + params: { + logAnalyticsWorkspaceName: logAnalyticsWorkspace.name + containers: storageInsightsConfig.?containers + tables: storageInsightsConfig.?tables + storageAccountResourceId: storageInsightsConfig.storageAccountResourceId + } + } +] + +module logAnalyticsWorkspace_linkedServices 'linked-service/main.bicep' = [ + for (linkedService, index) in linkedServices ?? []: { + name: '${uniqueString(deployment().name, location)}-LAW-LinkedService-${index}' + params: { + logAnalyticsWorkspaceName: logAnalyticsWorkspace.name + name: linkedService.name + resourceId: linkedService.?resourceId + writeAccessResourceId: linkedService.?writeAccessResourceId + } + } +] + +module logAnalyticsWorkspace_linkedStorageAccounts 'linked-storage-account/main.bicep' = [ + for (linkedStorageAccount, index) in linkedStorageAccounts ?? []: { + name: '${uniqueString(deployment().name, location)}-LAW-LinkedStorageAccount-${index}' + params: { + logAnalyticsWorkspaceName: logAnalyticsWorkspace.name + name: linkedStorageAccount.name + storageAccountIds: linkedStorageAccount.storageAccountIds + } + } +] + +module logAnalyticsWorkspace_savedSearches 'saved-search/main.bicep' = [ + for (savedSearch, index) in savedSearches ?? []: { + name: '${uniqueString(deployment().name, location)}-LAW-SavedSearch-${index}' + params: { + logAnalyticsWorkspaceName: logAnalyticsWorkspace.name + name: '${savedSearch.name}${uniqueString(deployment().name)}' + etag: savedSearch.?etag + displayName: savedSearch.displayName + category: savedSearch.category + query: savedSearch.query + functionAlias: savedSearch.?functionAlias + functionParameters: savedSearch.?functionParameters + tags: savedSearch.?tags + version: savedSearch.?version + } + dependsOn: [ + logAnalyticsWorkspace_linkedStorageAccounts + ] + } +] + +module logAnalyticsWorkspace_dataExports 'data-export/main.bicep' = [ + for (dataExport, index) in dataExports ?? []: { + name: '${uniqueString(deployment().name, location)}-LAW-DataExport-${index}' + params: { + workspaceName: logAnalyticsWorkspace.name + name: dataExport.name + destination: dataExport.?destination + enable: dataExport.?enable + tableNames: dataExport.?tableNames + } + } +] + +module logAnalyticsWorkspace_dataSources 'data-source/main.bicep' = [ + for (dataSource, index) in dataSources ?? []: { + name: '${uniqueString(deployment().name, location)}-LAW-DataSource-${index}' + params: { + logAnalyticsWorkspaceName: logAnalyticsWorkspace.name + name: dataSource.name + kind: dataSource.kind + linkedResourceId: dataSource.?linkedResourceId + eventLogName: dataSource.?eventLogName + eventTypes: dataSource.?eventTypes + objectName: dataSource.?objectName + instanceName: dataSource.?instanceName + intervalSeconds: dataSource.?intervalSeconds + counterName: dataSource.?counterName + state: dataSource.?state + syslogName: dataSource.?syslogName + syslogSeverities: dataSource.?syslogSeverities + performanceCounters: dataSource.?performanceCounters + tags: dataSource.?tags + } + } +] + +module logAnalyticsWorkspace_tables 'table/main.bicep' = [ + for (table, index) in tables ?? []: { + name: '${uniqueString(deployment().name, location)}-LAW-Table-${index}' + params: { + workspaceName: logAnalyticsWorkspace.name + name: table.name + plan: table.?plan + schema: table.?schema + retentionInDays: table.?retentionInDays + totalRetentionInDays: table.?totalRetentionInDays + restoredLogs: table.?restoredLogs + searchResults: table.?searchResults + roleAssignments: table.?roleAssignments + } + } +] + +module logAnalyticsWorkspace_solutions 'br/public:avm/res/operations-management/solution:0.3.0' = [ + for (gallerySolution, index) in gallerySolutions ?? []: if (!empty(gallerySolutions)) { + name: '${uniqueString(deployment().name, location)}-LAW-Solution-${index}' + params: { + name: gallerySolution.name + location: location + logAnalyticsWorkspaceName: logAnalyticsWorkspace.name + plan: gallerySolution.plan + enableTelemetry: gallerySolution.?enableTelemetry ?? enableTelemetry + } + } +] + +// Onboard the Log Analytics Workspace to Sentinel if SecurityInsights is in gallerySolutions and onboardWorkspaceToSentinel is set to true +resource logAnalyticsWorkspace_sentinelOnboarding 'Microsoft.SecurityInsights/onboardingStates@2024-03-01' = if (!empty(filter( + gallerySolutions ?? [], + item => startsWith(item.name, 'SecurityInsights') +)) && onboardWorkspaceToSentinel) { + name: 'default' + scope: logAnalyticsWorkspace + properties: {} +} + +resource logAnalyticsWorkspace_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: logAnalyticsWorkspace +} + +resource logAnalyticsWorkspace_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + logAnalyticsWorkspace.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: logAnalyticsWorkspace + } +] + +@description('The resource ID of the deployed log analytics workspace.') +output resourceId string = logAnalyticsWorkspace.id + +@description('The resource group of the deployed log analytics workspace.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the deployed log analytics workspace.') +output name string = logAnalyticsWorkspace.name + +@description('The ID associated with the workspace.') +output logAnalyticsWorkspaceId string = logAnalyticsWorkspace.properties.customerId + +@description('The location the resource was deployed into.') +output location string = logAnalyticsWorkspace.location + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string? = logAnalyticsWorkspace.?identity.?principalId + +// =============== // +// Definitions // +// =============== // + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics' | null)? + + @description('Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored.') + useThisWorkspace: bool? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +} + +import { solutionPlanType } from 'br/public:avm/res/operations-management/solution:0.3.0' + +@export() +@description('Properties of the gallery solutions to be created in the log analytics workspace.') +type gallerySolutionType = { + @description('''Required. Name of the solution. + For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`. + For solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`. + The solution type is case-sensitive.''') + name: string + + @description('Required. Plan for solution object supported by the OperationsManagement resource provider.') + plan: solutionPlanType +} + +@export() +@description('Properties of the storage insights configuration.') +type storageInsightsConfigType = { + @description('Required. Resource ID of the storage account to be linked.') + storageAccountResourceId: string + + @description('Optional. The names of the blob containers that the workspace should read.') + containers: string[]? + + @description('Optional. List of tables to be read by the workspace.') + tables: string[]? +} + +@export() +@description('Properties of the linked service.') +type linkedServiceType = { + @description('Required. Name of the linked service.') + name: string + + @description('Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access.') + resourceId: string? + + @description('Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access.') + writeAccessResourceId: string? +} + +@export() +@description('Properties of the linked storage account.') +type linkedStorageAccountType = { + @description('Required. Name of the link.') + name: string + + @minLength(1) + @description('Required. Linked storage accounts resources Ids.') + storageAccountIds: string[] +} + +@export() +@description('Properties of the saved search.') +type savedSearchType = { + @description('Required. Name of the saved search.') + name: string + + @description('Optional. The ETag of the saved search. To override an existing saved search, use "*" or specify the current Etag.') + etag: string? + + @description('Required. The category of the saved search. This helps the user to find a saved search faster.') + category: string + + @description('Required. Display name for the search.') + displayName: string + + @description('Optional. The function alias if query serves as a function.') + functionAlias: string? + + @description('Optional. The optional function parameters if query serves as a function. Value should be in the following format: \'param-name1:type1 = default_value1, param-name2:type2 = default_value2\'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions.') + functionParameters: string? + + @description('Required. The query expression for the saved search.') + query: string + + @description('Optional. The tags attached to the saved search.') + tags: array? + + @description('Optional. The version number of the query language. The current version is 2 and is the default.') + version: int? +} + +import { destinationType } from 'data-export/main.bicep' + +@export() +@description('Properties of the data export.') +type dataExportType = { + @description('Required. Name of the data export.') + name: string + + @description('Optional. The destination of the data export.') + destination: destinationType? + + @description('Optional. Enable or disable the data export.') + enable: bool? + + @description('Required. The list of table names to export.') + tableNames: string[] +} + +@export() +@description('Properties of the data source.') +type dataSourceType = { + @description('Required. Name of the data source.') + name: string + + @description('Required. The kind of data source.') + kind: string + + @description('Optional. The resource id of the resource that will be linked to the workspace.') + linkedResourceId: string? + + @description('Optional. The name of the event log to configure when kind is WindowsEvent.') + eventLogName: string? + + @description('Optional. The event types to configure when kind is WindowsEvent.') + eventTypes: array? + + @description('Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject.') + objectName: string? + + @description('Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject.') + instanceName: string? + + @description('Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject.') + intervalSeconds: int? + + @description('Optional. List of counters to configure when the kind is LinuxPerformanceObject.') + performanceCounters: array? + + @description('Optional. Counter name to configure when kind is WindowsPerformanceCounter.') + counterName: string? + + @description('Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection.') + state: string? + + @description('Optional. System log to configure when kind is LinuxSyslog.') + syslogName: string? + + @description('Optional. Severities to configure when kind is LinuxSyslog.') + syslogSeverities: array? + + @description('Optional. Tags to configure in the resource.') + tags: object? +} + +import { schemaType, restoredLogsType, searchResultsType } from 'table/main.bicep' + +@export() +@description('Properties of the custom table.') +type tableType = { + @description('Required. The name of the table.') + name: string + + @description('Optional. The plan for the table.') + plan: string? + + @description('Optional. The restored logs for the table.') + restoredLogs: restoredLogsType? + + @description('Optional. The schema for the table.') + schema: schemaType? + + @description('Optional. The search results for the table.') + searchResults: searchResultsType? + + @description('Optional. The retention in days for the table.') + retentionInDays: int? + + @description('Optional. The total retention in days for the table.') + totalRetentionInDays: int? + + @description('Optional. The role assignments for the table.') + roleAssignments: roleAssignmentType[]? +} + +@export() +@description('Features of the workspace.') +type workspaceFeaturesType = { + @description('Optional. Disable Non-EntraID based Auth. Default is true.') + disableLocalAuth: bool? + + @description('Optional. Flag that indicate if data should be exported.') + enableDataExport: bool? + + @description('Optional. Enable log access using only resource permissions. Default is false.') + enableLogAccessUsingOnlyResourcePermissions: bool? + + @description('Optional. Flag that describes if we want to remove the data after 30 days.') + immediatePurgeDataOn30Days: bool? +} diff --git a/avm/1.1.0/res/operational-insights/workspace/main.json b/avm/1.1.0/res/operational-insights/workspace/main.json new file mode 100644 index 000000000..4debca7e8 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/main.json @@ -0,0 +1,2996 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "2355986442928910370" + }, + "name": "Log Analytics Workspaces", + "description": "This module deploys a Log Analytics Workspace." + }, + "definitions": { + "diagnosticSettingType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "useThisWorkspace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "gallerySolutionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the gallery solutions to be created in the log analytics workspace." + } + }, + "storageInsightsConfigType": { + "type": "object", + "properties": { + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the storage account to be linked." + } + }, + "containers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of tables to be read by the workspace." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the storage insights configuration." + } + }, + "linkedServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the linked service." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + } + }, + "writeAccessResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the linked service." + } + }, + "linkedStorageAccountType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. Linked storage accounts resources Ids." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the linked storage account." + } + }, + "savedSearchType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the saved search." + } + }, + "etag": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + }, + "category": { + "type": "string", + "metadata": { + "description": "Required. The category of the saved search. This helps the user to find a saved search faster." + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "Required. Display name for the search." + } + }, + "functionAlias": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. The query expression for the saved search." + } + }, + "tags": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The tags attached to the saved search." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language. The current version is 2 and is the default." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the saved search." + } + }, + "dataExportType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data export." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "nullable": true, + "metadata": { + "description": "Optional. The destination of the data export." + } + }, + "enable": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the data export." + } + }, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of table names to export." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the data export." + } + }, + "dataSourceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data source." + } + }, + "kind": { + "type": "string", + "metadata": { + "description": "Required. The kind of data source." + } + }, + "linkedResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the resource that will be linked to the workspace." + } + }, + "eventLogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the event log to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the data source." + } + }, + "tableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "plan": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The plan for the table." + } + }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", + "nullable": true, + "metadata": { + "description": "Optional. The restored logs for the table." + } + }, + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. The schema for the table." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. The search results for the table." + } + }, + "retentionInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The retention in days for the table." + } + }, + "totalRetentionInDays": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The total retention in days for the table." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The role assignments for the table." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Properties of the custom table." + } + }, + "workspaceFeaturesType": { + "type": "object", + "properties": { + "disableLocalAuth": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Disable Non-EntraID based Auth. Default is true." + } + }, + "enableDataExport": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag that indicate if data should be exported." + } + }, + "enableLogAccessUsingOnlyResourcePermissions": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable log access using only resource permissions. Default is false." + } + }, + "immediatePurgeDataOn30Days": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Flag that describes if we want to remove the data after 30 days." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "Features of the workspace." + } + }, + "_1.columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The column name." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" + ], + "metadata": { + "description": "Required. The column type." + } + }, + "dataTypeHint": { + "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], + "nullable": true, + "metadata": { + "description": "Optional. The column data type logical hint." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The column description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Column display name." + } + } + }, + "metadata": { + "description": "The parameters of the table column.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "destinationType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The destination resource ID." + } + }, + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination metadata." + } + } + }, + "metadata": { + "description": "The data export destination properties.", + "__bicep_imported_from!": { + "sourceTemplate": "data-export/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "description": "The parameters of the restore operation that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, + "metadata": { + "description": "The table schema.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, + "metadata": { + "description": "The parameters of the search job that initiated the table.", + "__bicep_imported_from!": { + "sourceTemplate": "table/main.bicep" + } + } + }, + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/operations-management/solution:0.3.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "skuName": { + "type": "string", + "defaultValue": "PerGB2018", + "allowedValues": [ + "CapacityReservation", + "Free", + "LACluster", + "PerGB2018", + "PerNode", + "Premium", + "Standalone", + "Standard" + ], + "metadata": { + "description": "Optional. The name of the SKU." + } + }, + "skuCapacityReservationLevel": { + "type": "int", + "defaultValue": 100, + "minValue": 100, + "maxValue": 5000, + "metadata": { + "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." + } + }, + "storageInsightsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/storageInsightsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of storage accounts to be read by the workspace." + } + }, + "linkedServices": { + "type": "array", + "items": { + "$ref": "#/definitions/linkedServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of services to be linked." + } + }, + "linkedStorageAccounts": { + "type": "array", + "items": { + "$ref": "#/definitions/linkedStorageAccountType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." + } + }, + "savedSearches": { + "type": "array", + "items": { + "$ref": "#/definitions/savedSearchType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Kusto Query Language searches to save." + } + }, + "dataExports": { + "type": "array", + "items": { + "$ref": "#/definitions/dataExportType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW data export instances to be deployed." + } + }, + "dataSources": { + "type": "array", + "items": { + "$ref": "#/definitions/dataSourceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW data sources to configure." + } + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/definitions/tableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. LAW custom tables to be deployed." + } + }, + "gallerySolutions": { + "type": "array", + "items": { + "$ref": "#/definitions/gallerySolutionType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." + } + }, + "onboardWorkspaceToSentinel": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions." + } + }, + "dataRetention": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 730, + "metadata": { + "description": "Optional. Number of days data will be retained for." + } + }, + "dailyQuotaGb": { + "type": "int", + "defaultValue": -1, + "minValue": -1, + "metadata": { + "description": "Optional. The workspace daily quota for ingestion." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics ingestion." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics query." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." + } + }, + "features": { + "$ref": "#/definitions/workspaceFeaturesType", + "nullable": true, + "metadata": { + "description": "Optional. The workspace features." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "forceCmkForQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether customer managed storage is mandatory for query management." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "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')]", + "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')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", + "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "features": { + "searchVersion": 1, + "enableLogAccessUsingOnlyResourcePermissions": "[coalesce(tryGet(parameters('features'), 'enableLogAccessUsingOnlyResourcePermissions'), false())]", + "disableLocalAuth": "[coalesce(tryGet(parameters('features'), 'disableLocalAuth'), true())]", + "enableDataExport": "[tryGet(parameters('features'), 'enableDataExport')]", + "immediatePurgeDataOn30Days": "[tryGet(parameters('features'), 'immediatePurgeDataOn30Days')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" + }, + "retentionInDays": "[parameters('dataRetention')]", + "workspaceCapping": { + "dailyQuotaGb": "[parameters('dailyQuotaGb')]" + }, + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "forceCmkForQuery": "[parameters('forceCmkForQuery')]" + }, + "identity": "[variables('identity')]" + }, + "logAnalyticsWorkspace_diagnosticSettings": { + "copy": { + "name": "logAnalyticsWorkspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_sentinelOnboarding": { + "condition": "[and(not(empty(filter(coalesce(parameters('gallerySolutions'), createArray()), lambda('item', startsWith(lambdaVariables('item').name, 'SecurityInsights'))))), parameters('onboardWorkspaceToSentinel'))]", + "type": "Microsoft.SecurityInsights/onboardingStates", + "apiVersion": "2024-03-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "default", + "properties": {}, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_roleAssignments": { + "copy": { + "name": "logAnalyticsWorkspace_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_storageInsightConfigs": { + "copy": { + "name": "logAnalyticsWorkspace_storageInsightConfigs", + "count": "[length(coalesce(parameters('storageInsightsConfigs'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'containers')]" + }, + "tables": { + "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'tables')]" + }, + "storageAccountResourceId": { + "value": "[coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()].storageAccountResourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "14024094214852981332" + }, + "name": "Log Analytics Workspace Storage Insight Configs", + "description": "This module deploys a Log Analytics Workspace Storage Insight Config." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the storage insights config." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource Manager ID of the storage account resource." + } + }, + "containers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the Azure tables that the workspace should read." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" + }, + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "storageinsightconfig": { + "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "containers": "[parameters('containers')]", + "tables": "[parameters('tables')]", + "storageAccount": { + "id": "[parameters('storageAccountResourceId')]", + "key": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', last(split(parameters('storageAccountResourceId'), '/'))), '2022-09-01').keys[0].value]" + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage insights configuration." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the storage insight configuration is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the storage insights configuration." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedServices": { + "copy": { + "name": "logAnalyticsWorkspace_linkedServices", + "count": "[length(coalesce(parameters('linkedServices'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('linkedServices'), createArray())[copyIndex()].name]" + }, + "resourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'resourceId')]" + }, + "writeAccessResourceId": { + "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'writeAccessResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "15202444687633091947" + }, + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + } + }, + "writeAccessResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedService": { + "type": "Microsoft.OperationalInsights/workspaces/linkedServices", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resourceId": "[parameters('resourceId')]", + "writeAccessResourceId": "[parameters('writeAccessResourceId')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked service." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked service is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedStorageAccounts": { + "copy": { + "name": "logAnalyticsWorkspace_linkedStorageAccounts", + "count": "[length(coalesce(parameters('linkedStorageAccounts'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].name]" + }, + "storageAccountIds": { + "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].storageAccountIds]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "1489251440210164837" + }, + "name": "Log Analytics Workspace Linked Storage Accounts", + "description": "This module deploys a Log Analytics Workspace Linked Storage Account." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "allowedValues": [ + "Query", + "Alerts", + "CustomLogs", + "AzureWatson" + ], + "metadata": { + "description": "Required. Name of the link." + } + }, + "storageAccountIds": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. Linked storage accounts resources Ids." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedStorageAccount": { + "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "storageAccountIds": "[parameters('storageAccountIds')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked storage account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked storage account." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked storage account is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_savedSearches": { + "copy": { + "name": "logAnalyticsWorkspace_savedSearches", + "count": "[length(coalesce(parameters('savedSearches'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[format('{0}{1}', coalesce(parameters('savedSearches'), createArray())[copyIndex()].name, uniqueString(deployment().name))]" + }, + "etag": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'etag')]" + }, + "displayName": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].displayName]" + }, + "category": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].category]" + }, + "query": { + "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].query]" + }, + "functionAlias": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionAlias')]" + }, + "functionParameters": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionParameters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'tags')]" + }, + "version": { + "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'version')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "14407663387414945082" + }, + "name": "Log Analytics Workspace Saved Searches", + "description": "This module deploys a Log Analytics Workspace Saved Search." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the saved search." + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "Required. Display name for the search." + } + }, + "category": { + "type": "string", + "metadata": { + "description": "Required. Query category." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. Kusto Query to be stored." + } + }, + "tags": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + }, + "functionAlias": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language." + } + }, + "etag": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "savedSearch": { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "etag": "[parameters('etag')]", + "tags": "[coalesce(parameters('tags'), createArray())]", + "displayName": "[parameters('displayName')]", + "category": "[parameters('category')]", + "query": "[parameters('query')]", + "functionAlias": "[parameters('functionAlias')]", + "functionParameters": "[parameters('functionParameters')]", + "version": "[parameters('version')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed saved search." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the saved search is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed saved search." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "logAnalyticsWorkspace_linkedStorageAccounts" + ] + }, + "logAnalyticsWorkspace_dataExports": { + "copy": { + "name": "logAnalyticsWorkspace_dataExports", + "count": "[length(coalesce(parameters('dataExports'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataExports'), createArray())[copyIndex()].name]" + }, + "destination": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'destination')]" + }, + "enable": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'enable')]" + }, + "tableNames": { + "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'tableNames')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "15082251740316718256" + }, + "name": "Log Analytics Workspace Data Exports", + "description": "This module deploys a Log Analytics Workspace Data Export." + }, + "definitions": { + "destinationType": { + "type": "object", + "properties": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The destination resource ID." + } + }, + "metaData": { + "type": "object", + "properties": { + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The destination metadata." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The data export destination properties." + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 4, + "maxLength": 63, + "metadata": { + "description": "Required. The data export rule name." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "destination": { + "$ref": "#/definitions/destinationType", + "nullable": true, + "metadata": { + "description": "Optional. Destination properties." + } + }, + "enable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Active when enabled." + } + }, + "tableNames": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "metadata": { + "description": "Required. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('workspaceName')]" + }, + "dataExport": { + "type": "Microsoft.OperationalInsights/workspaces/dataExports", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "destination": "[parameters('destination')]", + "enable": "[parameters('enable')]", + "tableNames": "[parameters('tableNames')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the data export." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the data export." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the data export was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_dataSources": { + "copy": { + "name": "logAnalyticsWorkspace_dataSources", + "count": "[length(coalesce(parameters('dataSources'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].name]" + }, + "kind": { + "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].kind]" + }, + "linkedResourceId": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'linkedResourceId')]" + }, + "eventLogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventLogName')]" + }, + "eventTypes": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventTypes')]" + }, + "objectName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'objectName')]" + }, + "instanceName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'instanceName')]" + }, + "intervalSeconds": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'intervalSeconds')]" + }, + "counterName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'counterName')]" + }, + "state": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'state')]" + }, + "syslogName": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogName')]" + }, + "syslogSeverities": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogSeverities')]" + }, + "performanceCounters": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'performanceCounters')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "3186325409788999053" + }, + "name": "Log Analytics Workspace Datasources", + "description": "This module deploys a Log Analytics Workspace Data Source." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the data source." + } + }, + "kind": { + "type": "string", + "defaultValue": "AzureActivityLog", + "allowedValues": [ + "AzureActivityLog", + "WindowsEvent", + "WindowsPerformanceCounter", + "IISLogs", + "LinuxSyslog", + "LinuxSyslogCollection", + "LinuxPerformanceObject", + "LinuxPerformanceCollection" + ], + "metadata": { + "description": "Optional. The kind of the data source." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + }, + "linkedResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the resource to be linked." + } + }, + "eventLogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Windows event log name to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Windows event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "defaultValue": 60, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "dataSource": { + "type": "Microsoft.OperationalInsights/workspaces/dataSources", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "kind": "[parameters('kind')]", + "tags": "[parameters('tags')]", + "properties": { + "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", + "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", + "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", + "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", + "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", + "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", + "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", + "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", + "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", + "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", + "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed data source." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the data source is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed data source." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_tables": { + "copy": { + "name": "logAnalyticsWorkspace_tables", + "count": "[length(coalesce(parameters('tables'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-Table-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" + }, + "plan": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'plan')]" + }, + "schema": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'schema')]" + }, + "retentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'retentionInDays')]" + }, + "totalRetentionInDays": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'totalRetentionInDays')]" + }, + "restoredLogs": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'restoredLogs')]" + }, + "searchResults": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'searchResults')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "4329017759962267155" + }, + "name": "Log Analytics Workspace Tables", + "description": "This module deploys a Log Analytics Workspace Table." + }, + "definitions": { + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the restore operation that initiated the table." + } + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The table schema." + } + }, + "columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The column name." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" + ], + "metadata": { + "description": "Required. The column type." + } + }, + "dataTypeHint": { + "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], + "nullable": true, + "metadata": { + "description": "Optional. The column data type logical hint." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The column description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Column display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the table column." + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the search job that initiated the table." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "plan": { + "type": "string", + "defaultValue": "Analytics", + "allowedValues": [ + "Basic", + "Analytics" + ], + "metadata": { + "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." + } + }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", + "nullable": true, + "metadata": { + "description": "Optional. Restore parameters." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": -1, + "minValue": -1, + "maxValue": 730, + "metadata": { + "description": "Optional. The table retention in days, between 4 and 730. Setting this property to -1 will default to the workspace retention." + } + }, + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. Table's schema." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. Parameters of the search job that initiated this table." + } + }, + "totalRetentionInDays": { + "type": "int", + "defaultValue": -1, + "minValue": -1, + "maxValue": 2555, + "metadata": { + "description": "Optional. The table total retention in days, between 4 and 2555. Setting this property to -1 will default to table retention." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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')]", + "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')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('workspaceName')]" + }, + "table": { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "plan": "[parameters('plan')]", + "restoredLogs": "[parameters('restoredLogs')]", + "retentionInDays": "[parameters('retentionInDays')]", + "schema": "[parameters('schema')]", + "searchResults": "[parameters('searchResults')]", + "totalRetentionInDays": "[parameters('totalRetentionInDays')]" + } + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_solutions": { + "copy": { + "name": "logAnalyticsWorkspace_solutions", + "count": "[length(coalesce(parameters('gallerySolutions'), createArray()))]" + }, + "condition": "[not(empty(parameters('gallerySolutions')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-Solution-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "plan": { + "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].plan]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('gallerySolutions'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "1867653058254938383" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.3.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2021-06-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "solution": { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", + "promotionCode": "", + "product": "[parameters('plan').product]", + "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the solution is deployed." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('solution', '2015-11-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed log analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed log analytics workspace." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed log analytics workspace." + }, + "value": "[parameters('name')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "The ID associated with the workspace." + }, + "value": "[reference('logAnalyticsWorkspace').customerId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('logAnalyticsWorkspace', '2023-09-01', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('logAnalyticsWorkspace', '2023-09-01', 'full'), 'identity'), 'principalId')]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/operational-insights/workspace/saved-search/README.md b/avm/1.1.0/res/operational-insights/workspace/saved-search/README.md new file mode 100644 index 000000000..697d8e95b --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/saved-search/README.md @@ -0,0 +1,123 @@ +# Log Analytics Workspace Saved Searches `[Microsoft.OperationalInsights/workspaces/savedSearches]` + +This module deploys a Log Analytics Workspace Saved Search. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.OperationalInsights/workspaces/savedSearches` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/savedSearches) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-category) | string | Query category. | +| [`displayName`](#parameter-displayname) | string | Display name for the search. | +| [`name`](#parameter-name) | string | Name of the saved search. | +| [`query`](#parameter-query) | string | Kusto Query to be stored. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`logAnalyticsWorkspaceName`](#parameter-loganalyticsworkspacename) | string | The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`etag`](#parameter-etag) | string | The ETag of the saved search. To override an existing saved search, use "*" or specify the current Etag. | +| [`functionAlias`](#parameter-functionalias) | string | The function alias if query serves as a function. | +| [`functionParameters`](#parameter-functionparameters) | string | The optional function parameters if query serves as a function. Value should be in the following format: "param-name1:type1 = default_value1, param-name2:type2 = default_value2". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions. | +| [`tags`](#parameter-tags) | array | Tags to configure in the resource. | +| [`version`](#parameter-version) | int | The version number of the query language. | + +### Parameter: `category` + +Query category. + +- Required: Yes +- Type: string + +### Parameter: `displayName` + +Display name for the search. + +- Required: Yes +- Type: string + +### Parameter: `name` + +Name of the saved search. + +- Required: Yes +- Type: string + +### Parameter: `query` + +Kusto Query to be stored. + +- Required: Yes +- Type: string + +### Parameter: `logAnalyticsWorkspaceName` + +The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `etag` + +The ETag of the saved search. To override an existing saved search, use "*" or specify the current Etag. + +- Required: No +- Type: string +- Default: `'*'` + +### Parameter: `functionAlias` + +The function alias if query serves as a function. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `functionParameters` + +The optional function parameters if query serves as a function. Value should be in the following format: "param-name1:type1 = default_value1, param-name2:type2 = default_value2". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `tags` + +Tags to configure in the resource. + +- Required: No +- Type: array + +### Parameter: `version` + +The version number of the query language. + +- Required: No +- Type: int + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed saved search. | +| `resourceGroupName` | string | The resource group where the saved search is deployed. | +| `resourceId` | string | The resource ID of the deployed saved search. | diff --git a/avm/1.1.0/res/operational-insights/workspace/saved-search/main.bicep b/avm/1.1.0/res/operational-insights/workspace/saved-search/main.bicep new file mode 100644 index 000000000..00a2de1f2 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/saved-search/main.bicep @@ -0,0 +1,62 @@ +metadata name = 'Log Analytics Workspace Saved Searches' +metadata description = 'This module deploys a Log Analytics Workspace Saved Search.' + +@description('Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment.') +param logAnalyticsWorkspaceName string + +@description('Required. Name of the saved search.') +param name string + +@description('Required. Display name for the search.') +param displayName string + +@description('Required. Query category.') +param category string + +@description('Required. Kusto Query to be stored.') +param query string + +@description('Optional. Tags to configure in the resource.') +param tags array? + +@description('Optional. The function alias if query serves as a function.') +param functionAlias string = '' + +@description('Optional. The optional function parameters if query serves as a function. Value should be in the following format: "param-name1:type1 = default_value1, param-name2:type2 = default_value2". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions.') +param functionParameters string = '' + +@description('Optional. The version number of the query language.') +param version int? + +@description('Optional. The ETag of the saved search. To override an existing saved search, use "*" or specify the current Etag.') +param etag string = '*' + +resource workspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' existing = { + name: logAnalyticsWorkspaceName +} + +resource savedSearch 'Microsoft.OperationalInsights/workspaces/savedSearches@2023-09-01' = { + name: name + parent: workspace + //etag: etag // According to API, the variable should be here, but it doesn't work here. + properties: { + #disable-next-line BCP037 // This is a false positive, the 'etag' property works here even if the documentation suggests that it sohuld be placed one leve higher. + etag: etag + tags: tags ?? [] + displayName: displayName + category: category + query: query + functionAlias: functionAlias + functionParameters: functionParameters + version: version + } +} + +@description('The resource ID of the deployed saved search.') +output resourceId string = savedSearch.id + +@description('The resource group where the saved search is deployed.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the deployed saved search.') +output name string = savedSearch.name diff --git a/avm/1.1.0/res/operational-insights/workspace/saved-search/main.json b/avm/1.1.0/res/operational-insights/workspace/saved-search/main.json new file mode 100644 index 000000000..8d1d1cae6 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/saved-search/main.json @@ -0,0 +1,127 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "14407663387414945082" + }, + "name": "Log Analytics Workspace Saved Searches", + "description": "This module deploys a Log Analytics Workspace Saved Search." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the saved search." + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "Required. Display name for the search." + } + }, + "category": { + "type": "string", + "metadata": { + "description": "Required. Query category." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. Kusto Query to be stored." + } + }, + "tags": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + }, + "functionAlias": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language." + } + }, + "etag": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "savedSearch": { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "etag": "[parameters('etag')]", + "tags": "[coalesce(parameters('tags'), createArray())]", + "displayName": "[parameters('displayName')]", + "category": "[parameters('category')]", + "query": "[parameters('query')]", + "functionAlias": "[parameters('functionAlias')]", + "functionParameters": "[parameters('functionParameters')]", + "version": "[parameters('version')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed saved search." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the saved search is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed saved search." + }, + "value": "[parameters('name')]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/operational-insights/workspace/storage-insight-config/README.md b/avm/1.1.0/res/operational-insights/workspace/storage-insight-config/README.md new file mode 100644 index 000000000..34afc4442 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/storage-insight-config/README.md @@ -0,0 +1,89 @@ +# Log Analytics Workspace Storage Insight Configs `[Microsoft.OperationalInsights/workspaces/storageInsightConfigs]` + +This module deploys a Log Analytics Workspace Storage Insight Config. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.OperationalInsights/workspaces/storageInsightConfigs` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/storageInsightConfigs) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageAccountResourceId`](#parameter-storageaccountresourceid) | string | The Azure Resource Manager ID of the storage account resource. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`logAnalyticsWorkspaceName`](#parameter-loganalyticsworkspacename) | string | The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`containers`](#parameter-containers) | array | The names of the blob containers that the workspace should read. | +| [`name`](#parameter-name) | string | The name of the storage insights config. | +| [`tables`](#parameter-tables) | array | The names of the Azure tables that the workspace should read. | +| [`tags`](#parameter-tags) | object | Tags to configure in the resource. | + +### Parameter: `storageAccountResourceId` + +The Azure Resource Manager ID of the storage account resource. + +- Required: Yes +- Type: string + +### Parameter: `logAnalyticsWorkspaceName` + +The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `containers` + +The names of the blob containers that the workspace should read. + +- Required: No +- Type: array + +### Parameter: `name` + +The name of the storage insights config. + +- Required: No +- Type: string +- Default: `[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]` + +### Parameter: `tables` + +The names of the Azure tables that the workspace should read. + +- Required: No +- Type: array + +### Parameter: `tags` + +Tags to configure in the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the storage insights configuration. | +| `resourceGroupName` | string | The resource group where the storage insight configuration is deployed. | +| `resourceId` | string | The resource ID of the deployed storage insights configuration. | diff --git a/avm/1.1.0/res/operational-insights/workspace/storage-insight-config/main.bicep b/avm/1.1.0/res/operational-insights/workspace/storage-insight-config/main.bicep new file mode 100644 index 000000000..8cb9aabb2 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/storage-insight-config/main.bicep @@ -0,0 +1,51 @@ +metadata name = 'Log Analytics Workspace Storage Insight Configs' +metadata description = 'This module deploys a Log Analytics Workspace Storage Insight Config.' + +@description('Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment.') +param logAnalyticsWorkspaceName string + +@description('Optional. The name of the storage insights config.') +param name string = '${last(split(storageAccountResourceId, '/'))}-stinsconfig' + +@description('Required. The Azure Resource Manager ID of the storage account resource.') +param storageAccountResourceId string + +@description('Optional. The names of the blob containers that the workspace should read.') +param containers string[]? + +@description('Optional. The names of the Azure tables that the workspace should read.') +param tables string[]? + +@description('Optional. Tags to configure in the resource.') +param tags object? + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' existing = { + name: last(split(storageAccountResourceId, '/'))! +} + +resource workspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' existing = { + name: logAnalyticsWorkspaceName +} + +resource storageinsightconfig 'Microsoft.OperationalInsights/workspaces/storageInsightConfigs@2023-09-01' = { + name: name + parent: workspace + tags: tags + properties: { + containers: containers + tables: tables + storageAccount: { + id: storageAccountResourceId + key: storageAccount.listKeys().keys[0].value + } + } +} + +@description('The resource ID of the deployed storage insights configuration.') +output resourceId string = storageinsightconfig.id + +@description('The resource group where the storage insight configuration is deployed.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the storage insights configuration.') +output name string = storageinsightconfig.name diff --git a/avm/1.1.0/res/operational-insights/workspace/storage-insight-config/main.json b/avm/1.1.0/res/operational-insights/workspace/storage-insight-config/main.json new file mode 100644 index 000000000..e80b09bf6 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/storage-insight-config/main.json @@ -0,0 +1,113 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "14024094214852981332" + }, + "name": "Log Analytics Workspace Storage Insight Configs", + "description": "This module deploys a Log Analytics Workspace Storage Insight Config." + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the storage insights config." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource Manager ID of the storage account resource." + } + }, + "containers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The names of the Azure tables that the workspace should read." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" + }, + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "storageinsightconfig": { + "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "containers": "[parameters('containers')]", + "tables": "[parameters('tables')]", + "storageAccount": { + "id": "[parameters('storageAccountResourceId')]", + "key": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', last(split(parameters('storageAccountResourceId'), '/'))), '2022-09-01').keys[0].value]" + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage insights configuration." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the storage insight configuration is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the storage insights configuration." + }, + "value": "[parameters('name')]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/operational-insights/workspace/table/README.md b/avm/1.1.0/res/operational-insights/workspace/table/README.md new file mode 100644 index 000000000..32a0f782c --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/table/README.md @@ -0,0 +1,479 @@ +# Log Analytics Workspace Tables `[Microsoft.OperationalInsights/workspaces/tables]` + +This module deploys a Log Analytics Workspace Table. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.OperationalInsights/workspaces/tables` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces/tables) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the table. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`workspaceName`](#parameter-workspacename) | string | The name of the parent workspaces. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`plan`](#parameter-plan) | string | Instruct the system how to handle and charge the logs ingested to this table. | +| [`restoredLogs`](#parameter-restoredlogs) | object | Restore parameters. | +| [`retentionInDays`](#parameter-retentionindays) | int | The table retention in days, between 4 and 730. Setting this property to -1 will default to the workspace retention. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`schema`](#parameter-schema) | object | Table's schema. | +| [`searchResults`](#parameter-searchresults) | object | Parameters of the search job that initiated this table. | +| [`totalRetentionInDays`](#parameter-totalretentionindays) | int | The table total retention in days, between 4 and 2555. Setting this property to -1 will default to table retention. | + +### Parameter: `name` + +The name of the table. + +- Required: Yes +- Type: string + +### Parameter: `workspaceName` + +The name of the parent workspaces. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `plan` + +Instruct the system how to handle and charge the logs ingested to this table. + +- Required: No +- Type: string +- Default: `'Analytics'` +- Allowed: + ```Bicep + [ + 'Analytics' + 'Basic' + ] + ``` + +### Parameter: `restoredLogs` + +Restore parameters. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`endRestoreTime`](#parameter-restoredlogsendrestoretime) | string | The timestamp to end the restore by (UTC). | +| [`sourceTable`](#parameter-restoredlogssourcetable) | string | The table to restore data from. | +| [`startRestoreTime`](#parameter-restoredlogsstartrestoretime) | string | The timestamp to start the restore from (UTC). | + +### Parameter: `restoredLogs.endRestoreTime` + +The timestamp to end the restore by (UTC). + +- Required: No +- Type: string + +### Parameter: `restoredLogs.sourceTable` + +The table to restore data from. + +- Required: No +- Type: string + +### Parameter: `restoredLogs.startRestoreTime` + +The timestamp to start the restore from (UTC). + +- Required: No +- Type: string + +### Parameter: `retentionInDays` + +The table retention in days, between 4 and 730. Setting this property to -1 will default to the workspace retention. + +- Required: No +- Type: int +- Default: `-1` +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- MinValue: -1 +- MaxValue: 730 +- Roles configurable by name: + - `'Contributor'` + - `'Log Analytics Contributor'` + - `'Log Analytics Reader'` + - `'Monitoring Contributor'` + - `'Monitoring Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `schema` + +Table's schema. + +- Required: No +- Type: object +- MinValue: -1 +- MaxValue: 730 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`columns`](#parameter-schemacolumns) | array | A list of table custom columns. | +| [`name`](#parameter-schemaname) | string | The table name. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-schemadescription) | string | The table description. | +| [`displayName`](#parameter-schemadisplayname) | string | The table display name. | + +### Parameter: `schema.columns` + +A list of table custom columns. + +- Required: Yes +- Type: array +- MinValue: -1 +- MaxValue: 730 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-schemacolumnsname) | string | The column name. | +| [`type`](#parameter-schemacolumnstype) | string | The column type. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dataTypeHint`](#parameter-schemacolumnsdatatypehint) | string | The column data type logical hint. | +| [`description`](#parameter-schemacolumnsdescription) | string | The column description. | +| [`displayName`](#parameter-schemacolumnsdisplayname) | string | Column display name. | + +### Parameter: `schema.columns.name` + +The column name. + +- Required: Yes +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `schema.columns.type` + +The column type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'boolean' + 'dateTime' + 'dynamic' + 'guid' + 'int' + 'long' + 'real' + 'string' + ] + ``` +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `schema.columns.dataTypeHint` + +The column data type logical hint. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'armPath' + 'guid' + 'ip' + 'uri' + ] + ``` +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `schema.columns.description` + +The column description. + +- Required: No +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `schema.columns.displayName` + +Column display name. + +- Required: No +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `schema.name` + +The table name. + +- Required: Yes +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `schema.description` + +The table description. + +- Required: No +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `schema.displayName` + +The table display name. + +- Required: No +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `searchResults` + +Parameters of the search job that initiated this table. + +- Required: No +- Type: object +- MinValue: -1 +- MaxValue: 730 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`query`](#parameter-searchresultsquery) | string | The search job query. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-searchresultsdescription) | string | The search description. | +| [`endSearchTime`](#parameter-searchresultsendsearchtime) | string | The timestamp to end the search by (UTC). | +| [`limit`](#parameter-searchresultslimit) | int | Limit the search job to return up to specified number of rows. | +| [`startSearchTime`](#parameter-searchresultsstartsearchtime) | string | The timestamp to start the search from (UTC). | + +### Parameter: `searchResults.query` + +The search job query. + +- Required: Yes +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `searchResults.description` + +The search description. + +- Required: No +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `searchResults.endSearchTime` + +The timestamp to end the search by (UTC). + +- Required: No +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `searchResults.limit` + +Limit the search job to return up to specified number of rows. + +- Required: No +- Type: int +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `searchResults.startSearchTime` + +The timestamp to start the search from (UTC). + +- Required: No +- Type: string +- MinValue: -1 +- MaxValue: 730 + +### Parameter: `totalRetentionInDays` + +The table total retention in days, between 4 and 2555. Setting this property to -1 will default to table retention. + +- Required: No +- Type: int +- Default: `-1` +- MinValue: -1 +- MaxValue: 2555 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the table. | +| `resourceGroupName` | string | The name of the resource group the table was created in. | +| `resourceId` | string | The resource ID of the table. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.2.1` | Remote reference | diff --git a/avm/1.1.0/res/operational-insights/workspace/table/main.bicep b/avm/1.1.0/res/operational-insights/workspace/table/main.bicep new file mode 100644 index 000000000..a886ffc8f --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/table/main.bicep @@ -0,0 +1,191 @@ +metadata name = 'Log Analytics Workspace Tables' +metadata description = 'This module deploys a Log Analytics Workspace Table.' + +// ============== // +// Parameters // +// ============== // + +@description('Required. The name of the table.') +param name string + +@description('Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment.') +param workspaceName string + +@description('Optional. Instruct the system how to handle and charge the logs ingested to this table.') +@allowed([ + 'Basic' + 'Analytics' +]) +param plan string = 'Analytics' + +@description('Optional. Restore parameters.') +param restoredLogs restoredLogsType? + +@description('Optional. The table retention in days, between 4 and 730. Setting this property to -1 will default to the workspace retention.') +@minValue(-1) +@maxValue(730) +param retentionInDays int = -1 + +@description('Optional. Table\'s schema.') +param schema schemaType? + +@description('Optional. Parameters of the search job that initiated this table.') +param searchResults searchResultsType? + +@description('Optional. The table total retention in days, between 4 and 2555. Setting this property to -1 will default to table retention.') +@minValue(-1) +@maxValue(2555) +param totalRetentionInDays int = -1 + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +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' + ) + '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') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +// =============== // +// Deployments // +// =============== // + +resource workspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' existing = { + name: workspaceName +} + +resource table 'Microsoft.OperationalInsights/workspaces/tables@2023-09-01' = { + parent: workspace + name: name + properties: { + plan: plan + restoredLogs: restoredLogs + retentionInDays: retentionInDays + schema: schema + searchResults: searchResults + totalRetentionInDays: totalRetentionInDays + } +} + +resource table_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(table.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: table + } +] + +// =========== // +// Outputs // +// =========== // + +@description('The name of the table.') +output name string = table.name + +@description('The resource ID of the table.') +output resourceId string = table.id + +@description('The name of the resource group the table was created in.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +@export() +@description('The parameters of the restore operation that initiated the table.') +type restoredLogsType = { + @description('Optional. The table to restore data from.') + sourceTable: string? + @description('Optional. The timestamp to start the restore from (UTC).') + startRestoreTime: string? + @description('Optional. The timestamp to end the restore by (UTC).') + endRestoreTime: string? +} + +@export() +@description('The table schema.') +type schemaType = { + @description('Required. The table name.') + name: string + @description('Required. A list of table custom columns.') + columns: columnType[] + @description('Optional. The table description.') + description: string? + @description('Optional. The table display name.') + displayName: string? +} + +@export() +@description('The parameters of the table column.') +type columnType = { + @description('Required. The column name.') + name: string + @description('Required. The column type.') + type: 'boolean' | 'dateTime' | 'dynamic' | 'guid' | 'int' | 'long' | 'real' | 'string' + @description('Optional. The column data type logical hint.') + dataTypeHint: 'armPath' | 'guid' | 'ip' | 'uri'? + @description('Optional. The column description.') + description: string? + @description('Optional. Column display name.') + displayName: string? +} + +@export() +@description('The parameters of the search job that initiated the table.') +type searchResultsType = { + @description('Required. The search job query.') + query: string + @description('Optional. The search description.') + description: string? + @description('Optional. Limit the search job to return up to specified number of rows.') + limit: int? + @description('Optional. The timestamp to start the search from (UTC).') + startSearchTime: string? + @description('Optional. The timestamp to end the search by (UTC).') + endSearchTime: string? +} diff --git a/avm/1.1.0/res/operational-insights/workspace/table/main.json b/avm/1.1.0/res/operational-insights/workspace/table/main.json new file mode 100644 index 000000000..fdf48788f --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/table/main.json @@ -0,0 +1,420 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "4329017759962267155" + }, + "name": "Log Analytics Workspace Tables", + "description": "This module deploys a Log Analytics Workspace Table." + }, + "definitions": { + "restoredLogsType": { + "type": "object", + "properties": { + "sourceTable": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table to restore data from." + } + }, + "startRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the restore from (UTC)." + } + }, + "endRestoreTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the restore by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the restore operation that initiated the table." + } + }, + "schemaType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The table name." + } + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/definitions/columnType" + }, + "metadata": { + "description": "Required. A list of table custom columns." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The table display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The table schema." + } + }, + "columnType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The column name." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "boolean", + "dateTime", + "dynamic", + "guid", + "int", + "long", + "real", + "string" + ], + "metadata": { + "description": "Required. The column type." + } + }, + "dataTypeHint": { + "type": "string", + "allowedValues": [ + "armPath", + "guid", + "ip", + "uri" + ], + "nullable": true, + "metadata": { + "description": "Optional. The column data type logical hint." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The column description." + } + }, + "displayName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Column display name." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the table column." + } + }, + "searchResultsType": { + "type": "object", + "properties": { + "query": { + "type": "string", + "metadata": { + "description": "Required. The search job query." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The search description." + } + }, + "limit": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Limit the search job to return up to specified number of rows." + } + }, + "startSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to start the search from (UTC)." + } + }, + "endSearchTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The timestamp to end the search by (UTC)." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The parameters of the search job that initiated the table." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "plan": { + "type": "string", + "defaultValue": "Analytics", + "allowedValues": [ + "Basic", + "Analytics" + ], + "metadata": { + "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." + } + }, + "restoredLogs": { + "$ref": "#/definitions/restoredLogsType", + "nullable": true, + "metadata": { + "description": "Optional. Restore parameters." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": -1, + "minValue": -1, + "maxValue": 730, + "metadata": { + "description": "Optional. The table retention in days, between 4 and 730. Setting this property to -1 will default to the workspace retention." + } + }, + "schema": { + "$ref": "#/definitions/schemaType", + "nullable": true, + "metadata": { + "description": "Optional. Table's schema." + } + }, + "searchResults": { + "$ref": "#/definitions/searchResultsType", + "nullable": true, + "metadata": { + "description": "Optional. Parameters of the search job that initiated this table." + } + }, + "totalRetentionInDays": { + "type": "int", + "defaultValue": -1, + "minValue": -1, + "maxValue": 2555, + "metadata": { + "description": "Optional. The table total retention in days, between 4 and 2555. Setting this property to -1 will default to table retention." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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')]", + "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')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('workspaceName')]" + }, + "table": { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "plan": "[parameters('plan')]", + "restoredLogs": "[parameters('restoredLogs')]", + "retentionInDays": "[parameters('retentionInDays')]", + "schema": "[parameters('schema')]", + "searchResults": "[parameters('searchResults')]", + "totalRetentionInDays": "[parameters('totalRetentionInDays')]" + } + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/operational-insights/workspace/tests/e2e/adv/dependencies.bicep b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/adv/dependencies.bicep new file mode 100644 index 000000000..2b49787e6 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/adv/dependencies.bicep @@ -0,0 +1,85 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Automation Account to create.') +param automationAccountName string + +@description('Required. The name of the Event Hub Namespace to create.') +param eventHubNamespaceName string + +@description('Required. The name of the Event Hub to create.') +param eventHubName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' +} + +resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' = { + name: automationAccountName + location: location + properties: { + sku: { + name: 'Basic' + } + } +} + +resource eventHubNamespace 'Microsoft.EventHub/namespaces@2022-10-01-preview' = { + name: eventHubNamespaceName + location: location + sku: { + name: 'Basic' + tier: 'Basic' + capacity: 1 + } + properties: { + minimumTlsVersion: '1.2' + publicNetworkAccess: 'Enabled' + disableLocalAuth: false + isAutoInflateEnabled: false + maximumThroughputUnits: 0 + kafkaEnabled: false + zoneRedundant: true + } + + resource eventHub 'eventhubs@2022-10-01-preview' = { + name: eventHubName + properties: { + messageRetentionInDays: 1 + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id + +@description('The resource ID of the created Automation Account.') +output automationAccountResourceId string = automationAccount.id + +@description('The resource ID of the created Eventhub Namespace.') +output eventHubNamespaceResourceId string = eventHubNamespace.id + +@description('The name of the created Eventhub.') +output eventHubName string = eventHubNamespace::eventHub.name + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/avm/1.1.0/res/operational-insights/workspace/tests/e2e/adv/main.test.bicep b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/adv/main.test.bicep new file mode 100644 index 000000000..b16ae0b3b --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/adv/main.test.bicep @@ -0,0 +1,367 @@ +targetScope = 'subscription' + +metadata name = 'Advanced features' +metadata description = 'This instance deploys the module with advanced features like custom tables and data exports.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-operationalinsights.workspaces-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'oiwadv' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + storageAccountName: 'dep${namePrefix}sa${serviceShort}' + automationAccountName: 'dep-${namePrefix}-auto-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-ehn-${serviceShort}' + eventHubName: 'dep-${namePrefix}-eh-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dailyQuotaGb: 10 + dataSources: [ + { + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + { + kind: 'LinuxSyslog' + name: 'sampleSyslog1' + syslogName: 'kern' + syslogSeverities: [ + { + severity: 'emerg' + } + { + severity: 'alert' + } + { + severity: 'crit' + } + { + severity: 'err' + } + { + severity: 'warning' + } + ] + } + { + kind: 'LinuxSyslogCollection' + name: 'sampleSyslogCollection1' + state: 'Enabled' + } + { + instanceName: '*' + intervalSeconds: 10 + kind: 'LinuxPerformanceObject' + name: 'sampleLinuxPerf1' + objectName: 'Logical Disk' + syslogSeverities: [ + { + counterName: '% Used Inodes' + } + { + counterName: 'Free Megabytes' + } + { + counterName: '% Used Space' + } + { + counterName: 'Disk Transfers/sec' + } + { + counterName: 'Disk Reads/sec' + } + { + counterName: 'Disk Writes/sec' + } + ] + } + { + kind: 'LinuxPerformanceCollection' + name: 'sampleLinuxPerfCollection1' + state: 'Enabled' + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + { + name: 'sendingDiagnosticSettingsToSelf' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + useThisWorkspace: true + } + ] + gallerySolutions: [ + { + name: 'AzureAutomation(${namePrefix}${serviceShort}001)' + plan: { + product: 'OMSGallery/AzureAutomation' + } + } + ] + linkedServices: [ + { + name: 'Automation' + resourceId: nestedDependencies.outputs.automationAccountResourceId + } + ] + linkedStorageAccounts: [ + { + name: 'Query' + storageAccountIds: [ + nestedDependencies.outputs.storageAccountResourceId + ] + } + ] + publicNetworkAccessForIngestion: 'Disabled' + publicNetworkAccessForQuery: 'Disabled' + savedSearches: [ + { + category: 'VDC Saved Searches' + displayName: 'VMSS Instance Count2' + name: 'VMSSQueries' + query: 'Event | where Source == ServiceFabricNodeBootstrapAgent | summarize AggregatedValue = count() by Computer' + } + ] + storageInsightsConfigs: [ + { + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + tables: [ + 'LinuxsyslogVer2v0' + 'WADETWEventTable' + 'WADServiceFabric*EventTable' + 'WADWindowsEventLogsTable' + ] + } + ] + features: { + enableLogAccessUsingOnlyResourcePermissions: true + } + tables: [ + { + name: 'CustomTableBasic_CL' + schema: { + name: 'CustomTableBasic_CL' + columns: [ + { + name: 'TimeGenerated' + type: 'dateTime' + } + { + name: 'RawData' + type: 'string' + } + ] + } + totalRetentionInDays: 90 + retentionInDays: 60 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + { + name: 'CustomTableAdvanced_CL' + schema: { + name: 'CustomTableAdvanced_CL' + columns: [ + { + name: 'TimeGenerated' + type: 'dateTime' + } + { + name: 'EventTime' + type: 'dateTime' + } + { + name: 'EventLevel' + type: 'string' + } + { + name: 'EventCode' + type: 'int' + } + { + name: 'Message' + type: 'string' + } + { + name: 'RawData' + type: 'string' + } + ] + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + ] + dataExports: [ + { + name: 'eventHubExport' + enable: true + destination: { + resourceId: nestedDependencies.outputs.eventHubNamespaceResourceId + metaData: { + eventHubName: nestedDependencies.outputs.eventHubName + } + } + tableNames: [ + 'Alert' + 'InsightsMetrics' + ] + } + { + name: 'storageAccountExport' + enable: true + destination: { + resourceId: nestedDependencies.outputs.storageAccountResourceId + } + tableNames: [ + 'Operation' + ] + } + ] + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/1.1.0/res/operational-insights/workspace/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..be86d0d2e --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-operationalinsights.workspaces-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'oiwmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/1.1.0/res/operational-insights/workspace/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..8f83c0d9a --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/max/dependencies.bicep @@ -0,0 +1,47 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Automation Account to create.') +param automationAccountName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' +} + +resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' = { + name: automationAccountName + location: location + properties: { + sku: { + name: 'Basic' + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id + +@description('The resource ID of the created Automation Account.') +output automationAccountResourceId string = automationAccount.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/avm/1.1.0/res/operational-insights/workspace/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..e8f0c15a3 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/max/main.test.bicep @@ -0,0 +1,379 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-operationalinsights.workspaces-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'oiwmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + storageAccountName: 'dep${namePrefix}sa${serviceShort}' + automationAccountName: 'dep-${namePrefix}-auto-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dailyQuotaGb: 10 + dataSources: [ + { + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + { + kind: 'LinuxSyslog' + name: 'sampleSyslog1' + syslogName: 'kern' + syslogSeverities: [ + { + severity: 'emerg' + } + { + severity: 'alert' + } + { + severity: 'crit' + } + { + severity: 'err' + } + { + severity: 'warning' + } + ] + } + { + kind: 'LinuxSyslogCollection' + name: 'sampleSyslogCollection1' + state: 'Enabled' + } + { + instanceName: '*' + intervalSeconds: 10 + kind: 'LinuxPerformanceObject' + name: 'sampleLinuxPerf1' + objectName: 'Logical Disk' + syslogSeverities: [ + { + counterName: '% Used Inodes' + } + { + counterName: 'Free Megabytes' + } + { + counterName: '% Used Space' + } + { + counterName: 'Disk Transfers/sec' + } + { + counterName: 'Disk Reads/sec' + } + { + counterName: 'Disk Writes/sec' + } + ] + } + { + kind: 'LinuxPerformanceCollection' + name: 'sampleLinuxPerfCollection1' + state: 'Enabled' + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + features: { + enableLogAccessUsingOnlyResourcePermissions: true + disableLocalAuth: true + enableDataExport: true + immediatePurgeDataOn30Days: true + } + gallerySolutions: [ + { + name: 'AzureAutomation(${namePrefix}${serviceShort}001)' + plan: { + product: 'OMSGallery/AzureAutomation' + } + } + { + name: 'SecurityInsights(${namePrefix}${serviceShort}001)' + plan: { + product: 'OMSGallery/SecurityInsights' + publisher: 'Microsoft' + } + } + { + name: 'SQLAuditing(${namePrefix}${serviceShort}001)' + plan: { + name: 'SQLAuditing(${namePrefix}${serviceShort}001)' + product: 'SQLAuditing' + publisher: 'Microsoft' + } + } + ] + onboardWorkspaceToSentinel: true + linkedServices: [ + { + name: 'Automation' + resourceId: nestedDependencies.outputs.automationAccountResourceId + } + ] + linkedStorageAccounts: [ + { + name: 'Query' + storageAccountIds: [ + nestedDependencies.outputs.storageAccountResourceId + ] + } + ] + tables: [ + { + name: 'CustomTableBasic_CL' + schema: { + name: 'CustomTableBasic_CL' + columns: [ + { + name: 'TimeGenerated' + type: 'dateTime' + } + { + name: 'RawData' + type: 'string' + } + ] + } + totalRetentionInDays: 90 + retentionInDays: 60 + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + { + name: 'CustomTableAdvanced_CL' + schema: { + name: 'CustomTableAdvanced_CL' + columns: [ + { + name: 'TimeGenerated' + type: 'dateTime' + } + { + name: 'EventTime' + type: 'dateTime' + } + { + name: 'EventLevel' + type: 'string' + } + { + name: 'EventCode' + type: 'int' + } + { + name: 'Message' + type: 'string' + } + { + name: 'RawData' + type: 'string' + } + ] + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + publicNetworkAccessForIngestion: 'Disabled' + publicNetworkAccessForQuery: 'Disabled' + savedSearches: [ + { + category: 'VDC Saved Searches' + displayName: 'VMSS Instance Count2' + name: 'VMSSQueries' + query: 'Event | where Source == ServiceFabricNodeBootstrapAgent | summarize AggregatedValue = count() by Computer' + tags: [ + { + Name: 'Environment' + Value: 'Non-Prod' + } + { + Name: 'Role' + Value: 'DeploymentValidation' + } + ] + } + ] + storageInsightsConfigs: [ + { + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + tables: [ + 'LinuxsyslogVer2v0' + 'WADETWEventTable' + 'WADServiceFabric*EventTable' + 'WADWindowsEventLogsTable' + ] + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + managedIdentities: { + systemAssigned: true + } + roleAssignments: [ + { + name: 'c3d53092-840c-4025-9c02-9bcb7895789c' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + } +] diff --git a/avm/1.1.0/res/operational-insights/workspace/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..87ccefc9c --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,33 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Automation Account to create.') +param automationAccountName string + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' +} + +resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' = { + name: automationAccountName + location: location + properties: { + sku: { + name: 'Basic' + } + } +} + +@description('The resource ID of the created Storage Account.') +output storageAccountResourceId string = storageAccount.id + +@description('The resource ID of the created Automation Account.') +output automationAccountResourceId string = automationAccount.id diff --git a/avm/1.1.0/res/operational-insights/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..5fa264c25 --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,217 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-operationalinsights.workspaces-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'oiwwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + storageAccountName: 'dep${namePrefix}sa${serviceShort}' + automationAccountName: 'dep-${namePrefix}-auto-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + dailyQuotaGb: 10 + dataSources: [ + { + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + { + kind: 'LinuxSyslog' + name: 'sampleSyslog1' + syslogName: 'kern' + syslogSeverities: [ + { + severity: 'emerg' + } + { + severity: 'alert' + } + { + severity: 'crit' + } + { + severity: 'err' + } + { + severity: 'warning' + } + ] + } + { + kind: 'LinuxSyslogCollection' + name: 'sampleSyslogCollection1' + state: 'Enabled' + } + { + instanceName: '*' + intervalSeconds: 10 + kind: 'LinuxPerformanceObject' + name: 'sampleLinuxPerf1' + objectName: 'Logical Disk' + syslogSeverities: [ + { + counterName: '% Used Inodes' + } + { + counterName: 'Free Megabytes' + } + { + counterName: '% Used Space' + } + { + counterName: 'Disk Transfers/sec' + } + { + counterName: 'Disk Reads/sec' + } + { + counterName: 'Disk Writes/sec' + } + ] + } + { + kind: 'LinuxPerformanceCollection' + name: 'sampleLinuxPerfCollection1' + state: 'Enabled' + } + ] + diagnosticSettings: [ + { + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + gallerySolutions: [ + { + name: 'AzureAutomation(${namePrefix}${serviceShort}001)' + plan: { + product: 'OMSGallery/AzureAutomation' + } + } + ] + linkedServices: [ + { + name: 'Automation' + resourceId: nestedDependencies.outputs.automationAccountResourceId + } + ] + linkedStorageAccounts: [ + { + name: 'Query' + storageAccountIds: [ + nestedDependencies.outputs.storageAccountResourceId + ] + } + ] + publicNetworkAccessForIngestion: 'Disabled' + publicNetworkAccessForQuery: 'Disabled' + storageInsightsConfigs: [ + { + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + tables: [ + 'LinuxsyslogVer2v0' + 'WADETWEventTable' + 'WADServiceFabric*EventTable' + 'WADWindowsEventLogsTable' + ] + } + ] + features: { + enableLogAccessUsingOnlyResourcePermissions: true + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + managedIdentities: { + systemAssigned: true + } + } + } +] diff --git a/avm/1.1.0/res/operational-insights/workspace/version.json b/avm/1.1.0/res/operational-insights/workspace/version.json new file mode 100644 index 000000000..91ffa760b --- /dev/null +++ b/avm/1.1.0/res/operational-insights/workspace/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.11", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/operations-management/solution/README.md b/avm/1.1.0/res/operations-management/solution/README.md new file mode 100644 index 000000000..6d4b835b4 --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/README.md @@ -0,0 +1,547 @@ +# Operations Management Solutions `[Microsoft.OperationsManagement/solutions]` + +This module deploys an Operations Management Solution. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.OperationsManagement/solutions` | [2015-11-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationsManagement/2015-11-01-preview/solutions) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/operations-management/solution:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Microsoft solution](#example-2-microsoft-solution) +- [Non-Microsoft solution](#example-3-non-microsoft-solution) +- [SQLAuditing solution](#example-4-sqlauditing-solution) +- [WAF-aligned](#example-5-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module solution 'br/public:avm/res/operations-management/solution:' = { + name: 'solutionDeployment' + params: { + // Required parameters + logAnalyticsWorkspaceName: '' + name: '' + plan: { + product: 'OMSGallery/Updates' + } + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "logAnalyticsWorkspaceName": { + "value": "" + }, + "name": { + "value": "" + }, + "plan": { + "value": { + "product": "OMSGallery/Updates" + } + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operations-management/solution:' + +// Required parameters +param logAnalyticsWorkspaceName = '' +param name = '' +param plan = { + product: 'OMSGallery/Updates' +} +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Microsoft solution_ + +This instance deploys the module with a Microsoft solution. + + +

+ +via Bicep module + +```bicep +module solution 'br/public:avm/res/operations-management/solution:' = { + name: 'solutionDeployment' + params: { + // Required parameters + logAnalyticsWorkspaceName: '' + name: '' + plan: { + product: 'OMSGallery/AzureAutomation' + } + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "logAnalyticsWorkspaceName": { + "value": "" + }, + "name": { + "value": "" + }, + "plan": { + "value": { + "product": "OMSGallery/AzureAutomation" + } + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operations-management/solution:' + +// Required parameters +param logAnalyticsWorkspaceName = '' +param name = '' +param plan = { + product: 'OMSGallery/AzureAutomation' +} +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 3: _Non-Microsoft solution_ + +This instance deploys the module with a third party (Non-Microsoft) solution. + + +

+ +via Bicep module + +```bicep +module solution 'br/public:avm/res/operations-management/solution:' = { + name: 'solutionDeployment' + params: { + // Required parameters + logAnalyticsWorkspaceName: '' + name: 'omsnonms001' + plan: { + name: 'nonmsTestSolutionPlan' + product: 'nonmsTestSolutionProduct' + publisher: 'nonmsTestSolutionPublisher' + } + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "logAnalyticsWorkspaceName": { + "value": "" + }, + "name": { + "value": "omsnonms001" + }, + "plan": { + "value": { + "name": "nonmsTestSolutionPlan", + "product": "nonmsTestSolutionProduct", + "publisher": "nonmsTestSolutionPublisher" + } + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operations-management/solution:' + +// Required parameters +param logAnalyticsWorkspaceName = '' +param name = 'omsnonms001' +param plan = { + name: 'nonmsTestSolutionPlan' + product: 'nonmsTestSolutionProduct' + publisher: 'nonmsTestSolutionPublisher' +} +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 4: _SQLAuditing solution_ + +This instance deploys the module with the SQLAuditing solution. This solution is authored by Microsoft, but uses a non-standard value for the `product` parameter. + + +

+ +via Bicep module + +```bicep +module solution 'br/public:avm/res/operations-management/solution:' = { + name: 'solutionDeployment' + params: { + // Required parameters + logAnalyticsWorkspaceName: '' + name: '' + plan: { + product: 'SQLAuditing' + publisher: 'Microsoft' + } + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "logAnalyticsWorkspaceName": { + "value": "" + }, + "name": { + "value": "" + }, + "plan": { + "value": { + "product": "SQLAuditing", + "publisher": "Microsoft" + } + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operations-management/solution:' + +// Required parameters +param logAnalyticsWorkspaceName = '' +param name = '' +param plan = { + product: 'SQLAuditing' + publisher: 'Microsoft' +} +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 5: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module solution 'br/public:avm/res/operations-management/solution:' = { + name: 'solutionDeployment' + params: { + // Required parameters + logAnalyticsWorkspaceName: '' + name: '' + plan: { + name: '' + product: 'OMSGallery/AzureAutomation' + publisher: 'Microsoft' + } + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "logAnalyticsWorkspaceName": { + "value": "" + }, + "name": { + "value": "" + }, + "plan": { + "value": { + "name": "", + "product": "OMSGallery/AzureAutomation", + "publisher": "Microsoft" + } + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operations-management/solution:' + +// Required parameters +param logAnalyticsWorkspaceName = '' +param name = '' +param plan = { + name: '' + product: 'OMSGallery/AzureAutomation' + publisher: 'Microsoft' +} +// Non-required parameters +param location = '' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`logAnalyticsWorkspaceName`](#parameter-loganalyticsworkspacename) | string | Name of the Log Analytics workspace where the solution will be deployed/enabled. | +| [`name`](#parameter-name) | string | Name of the solution.

For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.

For solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.

The solution type is case-sensitive. | +| [`plan`](#parameter-plan) | object | Plan for solution object supported by the OperationsManagement resource provider. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all resources. | + +### Parameter: `logAnalyticsWorkspaceName` + +Name of the Log Analytics workspace where the solution will be deployed/enabled. + +- Required: Yes +- Type: string + +### Parameter: `name` + +Name of the solution.

For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.

For solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.

The solution type is case-sensitive. + +- Required: Yes +- Type: string + +### Parameter: `plan` + +Plan for solution object supported by the OperationsManagement resource provider. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`product`](#parameter-planproduct) | string | The product name of the deployed solution.

For Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.

For a third party solution, it can be anything.

This is case sensitive. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-planname) | string | Name of the solution to be created.

For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.

For solutions authored by third parties, it can be anything.

The solution type is case-sensitive.

If not provided, the value of the `name` parameter will be used. | +| [`publisher`](#parameter-planpublisher) | string | The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value. | + +### Parameter: `plan.product` + +The product name of the deployed solution.

For Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.

For a third party solution, it can be anything.

This is case sensitive. + +- Required: Yes +- Type: string + +### Parameter: `plan.name` + +Name of the solution to be created.

For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.

For solutions authored by third parties, it can be anything.

The solution type is case-sensitive.

If not provided, the value of the `name` parameter will be used. + +- Required: No +- Type: string + +### Parameter: `plan.publisher` + +The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed solution. | +| `resourceGroupName` | string | The resource group where the solution is deployed. | +| `resourceId` | string | The resource ID of the deployed solution. | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/operations-management/solution/main.bicep b/avm/1.1.0/res/operations-management/solution/main.bicep new file mode 100644 index 000000000..520a17627 --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/main.bicep @@ -0,0 +1,92 @@ +metadata name = 'Operations Management Solutions' +metadata description = 'This module deploys an Operations Management Solution.' + +@description('''Required. Name of the solution. +For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`. +For solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`. +The solution type is case-sensitive.''') +param name string + +@description('Required. Plan for solution object supported by the OperationsManagement resource provider.') +param plan solutionPlanType + +@description('Required. Name of the Log Analytics workspace where the solution will be deployed/enabled.') +param logAnalyticsWorkspaceName string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.operationsmanagement-solution.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' existing = { + name: logAnalyticsWorkspaceName +} + +resource solution 'Microsoft.OperationsManagement/solutions@2015-11-01-preview' = { + name: name + location: location + properties: { + workspaceResourceId: logAnalyticsWorkspace.id + } + plan: { + name: plan.?name ?? name + promotionCode: '' + product: plan.product + publisher: plan.?publisher ?? 'Microsoft' + } +} + +@description('The name of the deployed solution.') +output name string = solution.name + +@description('The resource ID of the deployed solution.') +output resourceId string = solution.id + +@description('The resource group where the solution is deployed.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = solution.location + +// =============== // +// Definitions // +// =============== // + +@export() +type solutionPlanType = { + @description('''Optional. Name of the solution to be created. + For solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`. + For solutions authored by third parties, it can be anything. + The solution type is case-sensitive. + If not provided, the value of the `name` parameter will be used.''') + name: string? + + @description('''Required. The product name of the deployed solution. + For Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`. + For a third party solution, it can be anything. + This is case sensitive.''') + product: string + + @description('Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value.') + publisher: string? +} diff --git a/avm/1.1.0/res/operations-management/solution/main.json b/avm/1.1.0/res/operations-management/solution/main.json new file mode 100644 index 000000000..4a1deced5 --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/main.json @@ -0,0 +1,151 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9594268678000013640" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution." + }, + "definitions": { + "solutionPlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." + } + }, + "publisher": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." + } + }, + "plan": { + "$ref": "#/definitions/solutionPlanType", + "metadata": { + "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2021-06-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "solution": { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", + "promotionCode": "", + "product": "[parameters('plan').product]", + "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the solution is deployed." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('solution', '2015-11-01-preview', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/operations-management/solution/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/operations-management/solution/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..ef3592fb5 --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The name of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceName string = logAnalytics.name diff --git a/avm/1.1.0/res/operations-management/solution/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/operations-management/solution/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..ce2cc0cec --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,58 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-operationsmanagement.solutions-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'omsmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: 'Updates(${nestedDependencies.outputs.logAnalyticsWorkspaceName})' + plan: { + product: 'OMSGallery/Updates' + } + location: resourceLocation + logAnalyticsWorkspaceName: nestedDependencies.outputs.logAnalyticsWorkspaceName + } +} diff --git a/avm/1.1.0/res/operations-management/solution/tests/e2e/ms/dependencies.bicep b/avm/1.1.0/res/operations-management/solution/tests/e2e/ms/dependencies.bicep new file mode 100644 index 000000000..ef3592fb5 --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/tests/e2e/ms/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The name of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceName string = logAnalytics.name diff --git a/avm/1.1.0/res/operations-management/solution/tests/e2e/ms/main.test.bicep b/avm/1.1.0/res/operations-management/solution/tests/e2e/ms/main.test.bicep new file mode 100644 index 000000000..66af8a8ab --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/tests/e2e/ms/main.test.bicep @@ -0,0 +1,58 @@ +targetScope = 'subscription' + +metadata name = 'Microsoft solution' +metadata description = 'This instance deploys the module with a Microsoft solution.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-operationsmanagement.solutions-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'omsms' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: 'AzureAutomation(${nestedDependencies.outputs.logAnalyticsWorkspaceName})' + location: resourceLocation + logAnalyticsWorkspaceName: nestedDependencies.outputs.logAnalyticsWorkspaceName + plan: { + product: 'OMSGallery/AzureAutomation' + } + } +} diff --git a/avm/1.1.0/res/operations-management/solution/tests/e2e/nonms/dependencies.bicep b/avm/1.1.0/res/operations-management/solution/tests/e2e/nonms/dependencies.bicep new file mode 100644 index 000000000..ef3592fb5 --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/tests/e2e/nonms/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The name of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceName string = logAnalytics.name diff --git a/avm/1.1.0/res/operations-management/solution/tests/e2e/nonms/main.test.bicep b/avm/1.1.0/res/operations-management/solution/tests/e2e/nonms/main.test.bicep new file mode 100644 index 000000000..97a79ad52 --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/tests/e2e/nonms/main.test.bicep @@ -0,0 +1,60 @@ +targetScope = 'subscription' + +metadata name = 'Non-Microsoft solution' +metadata description = 'This instance deploys the module with a third party (Non-Microsoft) solution.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-operationsmanagement.solutions-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'omsnonms' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + logAnalyticsWorkspaceName: nestedDependencies.outputs.logAnalyticsWorkspaceName + plan: { + name: 'nonmsTestSolutionPlan' + product: 'nonmsTestSolutionProduct' + publisher: 'nonmsTestSolutionPublisher' + } + } +} diff --git a/avm/1.1.0/res/operations-management/solution/tests/e2e/sql-auditing/dependencies.bicep b/avm/1.1.0/res/operations-management/solution/tests/e2e/sql-auditing/dependencies.bicep new file mode 100644 index 000000000..ef3592fb5 --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/tests/e2e/sql-auditing/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The name of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceName string = logAnalytics.name diff --git a/avm/1.1.0/res/operations-management/solution/tests/e2e/sql-auditing/main.test.bicep b/avm/1.1.0/res/operations-management/solution/tests/e2e/sql-auditing/main.test.bicep new file mode 100644 index 000000000..881e251f4 --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/tests/e2e/sql-auditing/main.test.bicep @@ -0,0 +1,59 @@ +targetScope = 'subscription' + +metadata name = 'SQLAuditing solution' +metadata description = 'This instance deploys the module with the SQLAuditing solution. This solution is authored by Microsoft, but uses a non-standard value for the `product` parameter.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-operationsmanagement.solutions-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'omssqa' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: 'SQLAuditing(${nestedDependencies.outputs.logAnalyticsWorkspaceName})' + location: resourceLocation + logAnalyticsWorkspaceName: nestedDependencies.outputs.logAnalyticsWorkspaceName + plan: { + product: 'SQLAuditing' + publisher: 'Microsoft' + } + } +} diff --git a/avm/1.1.0/res/operations-management/solution/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/operations-management/solution/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..ef3592fb5 --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +@description('The name of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceName string = logAnalytics.name diff --git a/avm/1.1.0/res/operations-management/solution/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/operations-management/solution/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..0d5167193 --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,63 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-operationsmanagement.solutions-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'omswaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: 'AzureAutomation(${nestedDependencies.outputs.logAnalyticsWorkspaceName})' + location: resourceLocation + logAnalyticsWorkspaceName: nestedDependencies.outputs.logAnalyticsWorkspaceName + plan: { + name: 'AzureAutomation(${nestedDependencies.outputs.logAnalyticsWorkspaceName})' + product: 'OMSGallery/AzureAutomation' + publisher: 'Microsoft' + } + } + } +] diff --git a/avm/1.1.0/res/operations-management/solution/version.json b/avm/1.1.0/res/operations-management/solution/version.json new file mode 100644 index 000000000..17dd49a0b --- /dev/null +++ b/avm/1.1.0/res/operations-management/solution/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.3", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/res/resources/deployment-script/README.md b/avm/1.1.0/res/resources/deployment-script/README.md new file mode 100644 index 000000000..cde40a684 --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/README.md @@ -0,0 +1,1450 @@ +# Deployment Scripts `[Microsoft.Resources/deploymentScripts]` + +This module deploys Deployment Scripts. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Resources/deploymentScripts` | [2023-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/2023-08-01/deploymentScripts) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/resources/deployment-script:`. + +- [Using Azure CLI](#example-1-using-azure-cli) +- [Using only defaults](#example-2-using-only-defaults) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [Using Private Endpoint](#example-4-using-private-endpoint) +- [Using Private Networking](#example-5-using-private-networking) +- [Using Azure PowerShell](#example-6-using-azure-powershell) +- [WAF-aligned](#example-7-waf-aligned) + +### Example 1: _Using Azure CLI_ + +This instance deploys the module with an Azure CLI script. + + +

+ +via Bicep module + +```bicep +module deploymentScript 'br/public:avm/res/resources/deployment-script:' = { + name: 'deploymentScriptDeployment' + params: { + // Required parameters + kind: 'AzureCLI' + name: 'rdscli001' + // Non-required parameters + azCliVersion: '2.52.0' + environmentVariables: [ + { + name: 'var1' + value: 'AVM Deployment Script test!' + } + ] + location: '' + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + retentionInterval: 'P1D' + scriptContent: 'echo \'Enviornment variable value is: \' $var1' + storageAccountResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "kind": { + "value": "AzureCLI" + }, + "name": { + "value": "rdscli001" + }, + // Non-required parameters + "azCliVersion": { + "value": "2.52.0" + }, + "environmentVariables": { + "value": [ + { + "name": "var1", + "value": "AVM Deployment Script test!" + } + ] + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "retentionInterval": { + "value": "P1D" + }, + "scriptContent": { + "value": "echo \"Enviornment variable value is: \" $var1" + }, + "storageAccountResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzureCLI' +param name = 'rdscli001' +// Non-required parameters +param azCliVersion = '2.52.0' +param environmentVariables = [ + { + name: 'var1' + value: 'AVM Deployment Script test!' + } +] +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param retentionInterval = 'P1D' +param scriptContent = 'echo \'Enviornment variable value is: \' $var1' +param storageAccountResourceId = '' +``` + +
+

+ +### Example 2: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module deploymentScript 'br/public:avm/res/resources/deployment-script:' = { + name: 'deploymentScriptDeployment' + params: { + // Required parameters + kind: 'AzurePowerShell' + name: 'rdsmin001' + // Non-required parameters + azPowerShellVersion: '12.3' + location: '' + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + scriptContent: 'Write-Host \'AVM Deployment Script test!\'' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "kind": { + "value": "AzurePowerShell" + }, + "name": { + "value": "rdsmin001" + }, + // Non-required parameters + "azPowerShellVersion": { + "value": "12.3" + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "scriptContent": { + "value": "Write-Host \"AVM Deployment Script test!\"" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzurePowerShell' +param name = 'rdsmin001' +// Non-required parameters +param azPowerShellVersion = '12.3' +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param scriptContent = 'Write-Host \'AVM Deployment Script test!\'' +``` + +
+

+ +### Example 3: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module deploymentScript 'br/public:avm/res/resources/deployment-script:' = { + name: 'deploymentScriptDeployment' + params: { + // Required parameters + kind: 'AzureCLI' + name: 'rdsmax001' + // Non-required parameters + arguments: '-argument1 \\\'test\\\'' + azCliVersion: '2.52.0' + cleanupPreference: 'Always' + containerGroupName: 'dep-cg-rdsmax' + environmentVariables: [ + { + name: 'var1' + value: 'test' + } + { + name: 'var2' + secureValue: '' + } + ] + location: '' + lock: { + kind: 'None' + } + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + retentionInterval: 'P1D' + roleAssignments: [ + { + name: 'd8eadbae-2c20-4e8f-9a48-4c6d739d0c4a' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + timeout: 'PT1H' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "kind": { + "value": "AzureCLI" + }, + "name": { + "value": "rdsmax001" + }, + // Non-required parameters + "arguments": { + "value": "-argument1 \\\"test\\\"" + }, + "azCliVersion": { + "value": "2.52.0" + }, + "cleanupPreference": { + "value": "Always" + }, + "containerGroupName": { + "value": "dep-cg-rdsmax" + }, + "environmentVariables": { + "value": [ + { + "name": "var1", + "value": "test" + }, + { + "name": "var2", + "secureValue": "" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "None" + } + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "retentionInterval": { + "value": "P1D" + }, + "roleAssignments": { + "value": [ + { + "name": "d8eadbae-2c20-4e8f-9a48-4c6d739d0c4a", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "runOnce": { + "value": true + }, + "scriptContent": { + "value": "echo \"AVM Deployment Script test!\"" + }, + "storageAccountResourceId": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "timeout": { + "value": "PT1H" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzureCLI' +param name = 'rdsmax001' +// Non-required parameters +param arguments = '-argument1 \\\'test\\\'' +param azCliVersion = '2.52.0' +param cleanupPreference = 'Always' +param containerGroupName = 'dep-cg-rdsmax' +param environmentVariables = [ + { + name: 'var1' + value: 'test' + } + { + name: 'var2' + secureValue: '' + } +] +param location = '' +param lock = { + kind: 'None' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param retentionInterval = 'P1D' +param roleAssignments = [ + { + name: 'd8eadbae-2c20-4e8f-9a48-4c6d739d0c4a' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param runOnce = true +param scriptContent = 'echo \'AVM Deployment Script test!\'' +param storageAccountResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param timeout = 'PT1H' +``` + +
+

+ +### Example 4: _Using Private Endpoint_ + +This instance deploys the module with access to a private endpoint. + + +

+ +via Bicep module + +```bicep +module deploymentScript 'br/public:avm/res/resources/deployment-script:' = { + name: 'deploymentScriptDeployment' + params: { + // Required parameters + kind: 'AzureCLI' + name: 'rdspe001' + // Non-required parameters + azCliVersion: '2.52.0' + cleanupPreference: 'Always' + location: '' + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + retentionInterval: 'P1D' + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: '' + subnetResourceIds: [ + '' + ] + timeout: 'PT1H' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "kind": { + "value": "AzureCLI" + }, + "name": { + "value": "rdspe001" + }, + // Non-required parameters + "azCliVersion": { + "value": "2.52.0" + }, + "cleanupPreference": { + "value": "Always" + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "retentionInterval": { + "value": "P1D" + }, + "runOnce": { + "value": true + }, + "scriptContent": { + "value": "echo \"AVM Deployment Script test!\"" + }, + "storageAccountResourceId": { + "value": "" + }, + "subnetResourceIds": { + "value": [ + "" + ] + }, + "timeout": { + "value": "PT1H" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzureCLI' +param name = 'rdspe001' +// Non-required parameters +param azCliVersion = '2.52.0' +param cleanupPreference = 'Always' +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param retentionInterval = 'P1D' +param runOnce = true +param scriptContent = 'echo \'AVM Deployment Script test!\'' +param storageAccountResourceId = '' +param subnetResourceIds = [ + '' +] +param timeout = 'PT1H' +``` + +
+

+ +### Example 5: _Using Private Networking_ + +This instance deploys the module with access to a private network. + + +

+ +via Bicep module + +```bicep +module deploymentScript 'br/public:avm/res/resources/deployment-script:' = { + name: 'deploymentScriptDeployment' + params: { + // Required parameters + kind: 'AzureCLI' + name: 'rdsnet001' + // Non-required parameters + azCliVersion: '2.52.0' + cleanupPreference: 'Always' + location: '' + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + retentionInterval: 'P1D' + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: '' + subnetResourceIds: [ + '' + ] + timeout: 'PT1H' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "kind": { + "value": "AzureCLI" + }, + "name": { + "value": "rdsnet001" + }, + // Non-required parameters + "azCliVersion": { + "value": "2.52.0" + }, + "cleanupPreference": { + "value": "Always" + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "retentionInterval": { + "value": "P1D" + }, + "runOnce": { + "value": true + }, + "scriptContent": { + "value": "echo \"AVM Deployment Script test!\"" + }, + "storageAccountResourceId": { + "value": "" + }, + "subnetResourceIds": { + "value": [ + "" + ] + }, + "timeout": { + "value": "PT1H" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzureCLI' +param name = 'rdsnet001' +// Non-required parameters +param azCliVersion = '2.52.0' +param cleanupPreference = 'Always' +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param retentionInterval = 'P1D' +param runOnce = true +param scriptContent = 'echo \'AVM Deployment Script test!\'' +param storageAccountResourceId = '' +param subnetResourceIds = [ + '' +] +param timeout = 'PT1H' +``` + +
+

+ +### Example 6: _Using Azure PowerShell_ + +This instance deploys the module with an Azure PowerShell script. + + +

+ +via Bicep module + +```bicep +module deploymentScript 'br/public:avm/res/resources/deployment-script:' = { + name: 'deploymentScriptDeployment' + params: { + // Required parameters + kind: 'AzurePowerShell' + name: 'rdsps001' + // Non-required parameters + arguments: '-var1 \\\'AVM Deployment Script test!\\\'' + azPowerShellVersion: '12.3' + location: '' + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + retentionInterval: 'P1D' + scriptContent: 'param([string] $var1);Write-Host \'Argument var1 value is:\' $var1' + storageAccountResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "kind": { + "value": "AzurePowerShell" + }, + "name": { + "value": "rdsps001" + }, + // Non-required parameters + "arguments": { + "value": "-var1 \\\"AVM Deployment Script test!\\\"" + }, + "azPowerShellVersion": { + "value": "12.3" + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "retentionInterval": { + "value": "P1D" + }, + "scriptContent": { + "value": "param([string] $var1);Write-Host \"Argument var1 value is:\" $var1" + }, + "storageAccountResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzurePowerShell' +param name = 'rdsps001' +// Non-required parameters +param arguments = '-var1 \\\'AVM Deployment Script test!\\\'' +param azPowerShellVersion = '12.3' +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param retentionInterval = 'P1D' +param scriptContent = 'param([string] $var1);Write-Host \'Argument var1 value is:\' $var1' +param storageAccountResourceId = '' +``` + +
+

+ +### Example 7: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module deploymentScript 'br/public:avm/res/resources/deployment-script:' = { + name: 'deploymentScriptDeployment' + params: { + // Required parameters + kind: 'AzureCLI' + name: 'rdswaf001' + // Non-required parameters + azCliVersion: '2.52.0' + cleanupPreference: 'Always' + location: '' + lock: { + kind: 'None' + } + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + retentionInterval: 'P1D' + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + timeout: 'PT1H' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "kind": { + "value": "AzureCLI" + }, + "name": { + "value": "rdswaf001" + }, + // Non-required parameters + "azCliVersion": { + "value": "2.52.0" + }, + "cleanupPreference": { + "value": "Always" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "None" + } + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "retentionInterval": { + "value": "P1D" + }, + "runOnce": { + "value": true + }, + "scriptContent": { + "value": "echo \"AVM Deployment Script test!\"" + }, + "storageAccountResourceId": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "timeout": { + "value": "PT1H" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzureCLI' +param name = 'rdswaf001' +// Non-required parameters +param azCliVersion = '2.52.0' +param cleanupPreference = 'Always' +param location = '' +param lock = { + kind: 'None' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param retentionInterval = 'P1D' +param runOnce = true +param scriptContent = 'echo \'AVM Deployment Script test!\'' +param storageAccountResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param timeout = 'PT1H' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-kind) | string | Specifies the Kind of the Deployment Script. | +| [`name`](#parameter-name) | string | Name of the Deployment Script. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`arguments`](#parameter-arguments) | string | Command-line arguments to pass to the script. Arguments are separated by spaces. | +| [`azCliVersion`](#parameter-azcliversion) | string | Azure CLI module version to be used. See a list of supported Azure CLI versions: https://mcr.microsoft.com/v2/azure-cli/tags/list. | +| [`azPowerShellVersion`](#parameter-azpowershellversion) | string | Azure PowerShell module version to be used. See a list of supported Azure PowerShell versions: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list. | +| [`cleanupPreference`](#parameter-cleanuppreference) | string | 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`](#parameter-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. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`environmentVariables`](#parameter-environmentvariables) | array | The environment variables to pass over to the script. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`primaryScriptUri`](#parameter-primaryscripturi) | string | Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent parameter instead. | +| [`retentionInterval`](#parameter-retentioninterval) | string | 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). | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`runOnce`](#parameter-runonce) | bool | When set to false, script will run every time the template is deployed. When set to true, the script will only run once. | +| [`scriptContent`](#parameter-scriptcontent) | string | Script body. Max length: 32000 characters. To run an external script, use primaryScriptURI instead. | +| [`storageAccountResourceId`](#parameter-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. | +| [`subnetResourceIds`](#parameter-subnetresourceids) | array | List of subnet IDs to use for the container group. This is required if you want to run the deployment script in a private network. When using a private network, the `Storage File Data Privileged Contributor` role needs to be assigned to the user-assigned managed identity and the deployment principal needs to have permissions to list the storage account keys. Also, Shared-Keys must not be disabled on the used storage account [ref](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deployment-script-vnet). | +| [`supportingScriptUris`](#parameter-supportingscripturis) | array | List of supporting files for the external script (defined in primaryScriptUri). Does not work with internal scripts (code defined in scriptContent). | +| [`tags`](#parameter-tags) | object | Resource tags. | +| [`timeout`](#parameter-timeout) | string | 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. | + +**Generated parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`baseTime`](#parameter-basetime) | string | Do not provide a value! This date value is used to make sure the script run every time the template is deployed. | + +### Parameter: `kind` + +Specifies the Kind of the Deployment Script. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'AzureCLI' + 'AzurePowerShell' + ] + ``` + +### Parameter: `name` + +Name of the Deployment Script. + +- Required: Yes +- Type: string + +### Parameter: `arguments` + +Command-line arguments to pass to the script. Arguments are separated by spaces. + +- Required: No +- Type: string + +### Parameter: `azCliVersion` + +Azure CLI module version to be used. See a list of supported Azure CLI versions: https://mcr.microsoft.com/v2/azure-cli/tags/list. + +- Required: No +- Type: string + +### Parameter: `azPowerShellVersion` + +Azure PowerShell module version to be used. See a list of supported Azure PowerShell versions: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list. + +- Required: No +- Type: string + +### Parameter: `cleanupPreference` + +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). + +- Required: No +- Type: string +- Default: `'Always'` +- Allowed: + ```Bicep + [ + 'Always' + 'OnExpiration' + 'OnSuccess' + ] + ``` + +### Parameter: `containerGroupName` + +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. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `environmentVariables` + +The environment variables to pass over to the script. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-environmentvariablesname) | string | The name of the environment variable. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`secureValue`](#parameter-environmentvariablessecurevalue) | securestring | The value of the secure environment variable. Required if `value` is null. | +| [`value`](#parameter-environmentvariablesvalue) | string | The value of the environment variable. Required if `secureValue` is null. | + +### Parameter: `environmentVariables.name` + +The name of the environment variable. + +- Required: Yes +- Type: string + +### Parameter: `environmentVariables.secureValue` + +The value of the secure environment variable. Required if `value` is null. + +- Required: No +- Type: securestring + +### Parameter: `environmentVariables.value` + +The value of the environment variable. Required if `secureValue` is null. + +- Required: No +- Type: string + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. | + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. + +- Required: No +- Type: array + +### Parameter: `primaryScriptUri` + +Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent parameter instead. + +- Required: No +- Type: string + +### Parameter: `retentionInterval` + +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). + +- Required: No +- Type: string +- Default: `'P1D'` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `runOnce` + +When set to false, script will run every time the template is deployed. When set to true, the script will only run once. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `scriptContent` + +Script body. Max length: 32000 characters. To run an external script, use primaryScriptURI instead. + +- Required: No +- Type: string + +### Parameter: `storageAccountResourceId` + +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. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `subnetResourceIds` + +List of subnet IDs to use for the container group. This is required if you want to run the deployment script in a private network. When using a private network, the `Storage File Data Privileged Contributor` role needs to be assigned to the user-assigned managed identity and the deployment principal needs to have permissions to list the storage account keys. Also, Shared-Keys must not be disabled on the used storage account [ref](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deployment-script-vnet). + +- Required: No +- Type: array + +### Parameter: `supportingScriptUris` + +List of supporting files for the external script (defined in primaryScriptUri). Does not work with internal scripts (code defined in scriptContent). + +- Required: No +- Type: array + +### Parameter: `tags` + +Resource tags. + +- Required: No +- Type: object + +### Parameter: `timeout` + +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. + +- Required: No +- Type: string + +### Parameter: `baseTime` + +Do not provide a value! This date value is used to make sure the script run every time the template is deployed. + +- Required: No +- Type: string +- Default: `[utcNow('yyyy-MM-dd-HH-mm-ss')]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `deploymentScriptLogs` | array | The logs of the deployment script. | +| `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. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.2.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/resources/deployment-script/main.bicep b/avm/1.1.0/res/resources/deployment-script/main.bicep new file mode 100644 index 000000000..3041398bc --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/main.bicep @@ -0,0 +1,271 @@ +metadata name = 'Deployment Scripts' +metadata description = 'This module deploys Deployment Scripts.' + +// ================ // +// Parameters // +// ================ // +@description('Required. Name of the Deployment Script.') +@maxLength(90) +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Required. Specifies the Kind of the Deployment Script.') +@allowed([ + 'AzureCLI' + 'AzurePowerShell' +]) +param kind string + +import { managedIdentityOnlyUserAssignedType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentityOnlyUserAssignedType? + +@description('Optional. Resource tags.') +param tags object? + +@description('Optional. Azure PowerShell module version to be used. See a list of supported Azure PowerShell versions: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list.') +param azPowerShellVersion string? + +@description('Optional. Azure CLI module version to be used. See a list of supported Azure CLI versions: https://mcr.microsoft.com/v2/azure-cli/tags/list.') +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 parameter instead.') +param primaryScriptUri string? + +@description('Optional. The environment variables to pass over to the script.') +param environmentVariables environmentVariableType[]? + +@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. List of subnet IDs to use for the container group. This is required if you want to run the deployment script in a private network. When using a private network, the `Storage File Data Privileged Contributor` role needs to be assigned to the user-assigned managed identity and the deployment principal needs to have permissions to list the storage account keys. Also, Shared-Keys must not be disabled on the used storage account [ref](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deployment-script-vnet).') +param subnetResourceIds string[]? + +@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('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') + +@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? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.2.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// =========== // +// Variables // +// =========== // + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +var subnetIds = [ + for subnetResourceId in (subnetResourceIds ?? []): { + id: subnetResourceId + } +] + +var containerSettings = { + containerGroupName: containerGroupName + subnetIds: !empty(subnetIds ?? []) ? subnetIds : null +} + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: !empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' existing = if (!empty(storageAccountResourceId)) { + name: last(split((!empty(storageAccountResourceId) ? storageAccountResourceId : 'dummyAccount'), '/'))! + scope: resourceGroup( + split((!empty(storageAccountResourceId) ? storageAccountResourceId : '//'), '/')[2], + split((!empty(storageAccountResourceId) ? storageAccountResourceId : '////'), '/')[4] + ) +} + +var storageAccountSettings = !empty(storageAccountResourceId) + ? { + storageAccountKey: empty(subnetResourceIds) ? listKeys(storageAccount.id, '2023-01-01').keys[0].value : null + storageAccountName: last(split(storageAccountResourceId, '/')) + } + : null + +// ================ // +// Resources // +// ================ // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.resources-deploymentscript.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource deploymentScript 'Microsoft.Resources/deploymentScripts@2023-08-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(containerSettings) ? containerSettings : null + storageAccountSettings: !empty(storageAccountResourceId) ? storageAccountSettings : null + arguments: arguments + environmentVariables: environmentVariables + 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 ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: deploymentScript +} + +resource deploymentScript_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(deploymentScript.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: deploymentScript + } +] + +resource deploymentScriptLogs 'Microsoft.Resources/deploymentScripts/logs@2023-08-01' existing = { + name: 'default' + parent: deploymentScript +} + +// ================ // +// Outputs // +// ================ // + +@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 = deploymentScript.properties.?outputs ?? {} + +@description('The logs of the deployment script.') +output deploymentScriptLogs string[] = split(deploymentScriptLogs.properties.log, '\n') + +// ================ // +// Definitions // +// ================ // + +type environmentVariableType = { + @description('Required. The name of the environment variable.') + name: string + + @description('Conditional. The value of the secure environment variable. Required if `value` is null.') + @secure() + secureValue: string? + + @description('Conditional. The value of the environment variable. Required if `secureValue` is null.') + value: string? +} diff --git a/avm/1.1.0/res/resources/deployment-script/main.json b/avm/1.1.0/res/resources/deployment-script/main.json new file mode 100644 index 000000000..8e36c536c --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/main.json @@ -0,0 +1,523 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "2982768208893141924" + }, + "name": "Deployment Scripts", + "description": "This module deploys Deployment Scripts." + }, + "definitions": { + "environmentVariableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the environment variable." + } + }, + "secureValue": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The value of the secure environment variable. Required if `value` is null." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The value of the environment variable. Required if `secureValue` is null." + } + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "managedIdentityOnlyUserAssignedType": { + "type": "object", + "properties": { + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 90, + "metadata": { + "description": "Required. Name of the Deployment Script." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "AzureCLI", + "AzurePowerShell" + ], + "metadata": { + "description": "Required. Specifies the Kind of the Deployment Script." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlyUserAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "azPowerShellVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Azure PowerShell module version to be used. See a list of supported Azure PowerShell versions: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list." + } + }, + "azCliVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Azure CLI module version to be used. See a list of supported Azure CLI versions: https://mcr.microsoft.com/v2/azure-cli/tags/list." + } + }, + "scriptContent": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Script body. Max length: 32000 characters. To run an external script, use primaryScriptURI instead." + } + }, + "primaryScriptUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent parameter instead." + } + }, + "environmentVariables": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentVariableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The environment variables to pass over to the script." + } + }, + "supportingScriptUris": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of supporting files for the external script (defined in primaryScriptUri). Does not work with internal scripts (code defined in scriptContent)." + } + }, + "subnetResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of subnet IDs to use for the container group. This is required if you want to run the deployment script in a private network. When using a private network, the `Storage File Data Privileged Contributor` role needs to be assigned to the user-assigned managed identity and the deployment principal needs to have permissions to list the storage account keys. Also, Shared-Keys must not be disabled on the used storage account [ref](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deployment-script-vnet)." + } + }, + "arguments": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Command-line arguments to pass to the script. Arguments are separated by spaces." + } + }, + "retentionInterval": { + "type": "string", + "defaultValue": "P1D", + "metadata": { + "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)." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('yyyy-MM-dd-HH-mm-ss')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to make sure the script run every time the template is deployed." + } + }, + "runOnce": { + "type": "bool", + "defaultValue": false, + "metadata": { + "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." + } + }, + "cleanupPreference": { + "type": "string", + "defaultValue": "Always", + "allowedValues": [ + "Always", + "OnSuccess", + "OnExpiration" + ], + "metadata": { + "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)." + } + }, + "containerGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "storageAccountResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "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." + } + }, + "timeout": { + "type": "string", + "nullable": true, + "metadata": { + "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." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + { + "name": "subnetIds", + "count": "[length(coalesce(parameters('subnetResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('subnetResourceIds'), createArray())[copyIndex('subnetIds')]]" + } + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "containerSettings": { + "containerGroupName": "[parameters('containerGroupName')]", + "subnetIds": "[if(not(empty(coalesce(variables('subnetIds'), createArray()))), variables('subnetIds'), null())]" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null()), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "storageAccount": { + "condition": "[not(empty(parameters('storageAccountResourceId')))]", + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-05-01", + "subscriptionId": "[split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '////'), '/')[4]]", + "name": "[last(split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), 'dummyAccount'), '/'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.resources-deploymentscript.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "deploymentScript": { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2023-08-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "kind": "[parameters('kind')]", + "properties": { + "azPowerShellVersion": "[if(equals(parameters('kind'), 'AzurePowerShell'), parameters('azPowerShellVersion'), null())]", + "azCliVersion": "[if(equals(parameters('kind'), 'AzureCLI'), parameters('azCliVersion'), null())]", + "containerSettings": "[if(not(empty(variables('containerSettings'))), variables('containerSettings'), null())]", + "storageAccountSettings": "[if(not(empty(parameters('storageAccountResourceId'))), if(not(empty(parameters('storageAccountResourceId'))), createObject('storageAccountKey', if(empty(parameters('subnetResourceIds')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '//'), '/')[2], split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), 'dummyAccount'), '/'))), '2023-01-01').keys[0].value, null()), 'storageAccountName', last(split(parameters('storageAccountResourceId'), '/'))), null()), null())]", + "arguments": "[parameters('arguments')]", + "environmentVariables": "[parameters('environmentVariables')]", + "scriptContent": "[if(not(empty(parameters('scriptContent'))), parameters('scriptContent'), null())]", + "primaryScriptUri": "[if(not(empty(parameters('primaryScriptUri'))), parameters('primaryScriptUri'), null())]", + "supportingScriptUris": "[if(not(empty(parameters('supportingScriptUris'))), parameters('supportingScriptUris'), null())]", + "cleanupPreference": "[parameters('cleanupPreference')]", + "forceUpdateTag": "[if(parameters('runOnce'), resourceGroup().name, parameters('baseTime'))]", + "retentionInterval": "[parameters('retentionInterval')]", + "timeout": "[parameters('timeout')]" + } + }, + "deploymentScript_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Resources/deploymentScripts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "deploymentScript" + ] + }, + "deploymentScript_roleAssignments": { + "copy": { + "name": "deploymentScript_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Resources/deploymentScripts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Resources/deploymentScripts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "deploymentScript" + ] + }, + "deploymentScriptLogs": { + "existing": true, + "type": "Microsoft.Resources/deploymentScripts/logs", + "apiVersion": "2023-08-01", + "name": "[format('{0}/{1}', parameters('name'), 'default')]", + "dependsOn": [ + "deploymentScript" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployment script." + }, + "value": "[resourceId('Microsoft.Resources/deploymentScripts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the deployment script was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployment script." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('deploymentScript', '2023-08-01', 'full').location]" + }, + "outputs": { + "type": "object", + "metadata": { + "description": "The output of the deployment script." + }, + "value": "[coalesce(tryGet(reference('deploymentScript'), 'outputs'), createObject())]" + }, + "deploymentScriptLogs": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The logs of the deployment script." + }, + "value": "[split(reference('deploymentScriptLogs').log, '\n')]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/cli/dependencies.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/cli/dependencies.bicep new file mode 100644 index 000000000..d49ed08f8 --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/cli/dependencies.bicep @@ -0,0 +1,31 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + } +} + +@description('The resource ID of the created managed identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created storage account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/cli/main.test.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/cli/main.test.bicep new file mode 100644 index 000000000..67725082a --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/cli/main.test.bicep @@ -0,0 +1,74 @@ +targetScope = 'subscription' + +metadata name = 'Using Azure CLI' +metadata description = 'This instance deploys the module with an Azure CLI script.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'rdscli' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + azCliVersion: '2.52.0' + kind: 'AzureCLI' + retentionInterval: 'P1D' + environmentVariables: [ + { + name: 'var1' + value: 'AVM Deployment Script test!' + } + ] + scriptContent: 'echo \'Enviornment variable value is: \' $var1' + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + } + dependsOn: [ + nestedDependencies + ] +} diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..eb82ada47 --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created managed identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..f6aa3d346 --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,65 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'rdsmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + azPowerShellVersion: '12.3' + kind: 'AzurePowerShell' + scriptContent: 'Write-Host \'AVM Deployment Script test!\'' + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + } + dependsOn: [ + nestedDependencies + ] +} diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..09a469b84 --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/max/dependencies.bicep @@ -0,0 +1,33 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + } +} +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created storage account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..09e967f3c --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/max/main.test.bicep @@ -0,0 +1,113 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'rdsmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + azCliVersion: '2.52.0' + kind: 'AzureCLI' + retentionInterval: 'P1D' + cleanupPreference: 'Always' + lock: { + kind: 'None' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + containerGroupName: 'dep-${namePrefix}-cg-${serviceShort}' + arguments: '-argument1 \\"test\\"' + environmentVariables: [ + { + name: 'var1' + value: 'test' + } + { + name: 'var2' + secureValue: guid(deployment().name) + } + ] + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + roleAssignments: [ + { + name: 'd8eadbae-2c20-4e8f-9a48-4c6d739d0c4a' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + timeout: 'PT1H' + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + } + dependsOn: [ + nestedDependencies + ] +} diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/private-endpoint/dependencies.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/private-endpoint/dependencies.bicep new file mode 100644 index 000000000..6f3158fdd --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/private-endpoint/dependencies.bicep @@ -0,0 +1,154 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the private endpoint to create.') +param privateEndpointName string + +var addressPrefix = '10.0.0.0/16' + +// Role required for deployment script to be able to use a storage account via private networking +resource storageFileDataPrivilegedContributor 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: '69566ab7-960f-475b-8e7c-b3118f30c6bd' + scope: tenant() +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +resource storageFileSharePermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('storageFileDataPrivilegedContributorRole', managedIdentity.id, storageAccount.id) + scope: storageAccount + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: storageFileDataPrivilegedContributor.id + principalType: 'ServicePrincipal' + } +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + publicNetworkAccess: 'Disabled' + allowSharedKeyAccess: true // Cannot be set to false when using a private network for the deployment script + networkAcls: { + defaultAction: 'Deny' + bypass: 'AzureServices' + } + } +} + +resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-11-01' = { + name: privateEndpointName + location: location + properties: { + subnet: { + id: virtualNetwork.properties.subnets[1].id + } + privateLinkServiceConnections: [ + { + name: '${privateEndpointName}-storageConnection' + properties: { + privateLinkServiceId: storageAccount.id + groupIds: [ + 'file' + ] + } + } + ] + } +} + +resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.file.${environment().suffixes.storage}' + location: 'global' + + resource virtualNetworkLink 'virtualNetworkLinks' = { + name: uniqueString(virtualNetwork.name) + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: virtualNetwork.id + } + } + } + + resource resRecord 'A' = { + name: storageAccount.name + properties: { + ttl: 10 + aRecords: [ + { + ipv4Address: first(first(privateEndpoint.properties.customDnsConfigs)!.ipAddresses) + } + ] + } + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + ] + delegations: [ + { + name: 'Microsoft.ContainerInstance.containerGroups' + properties: { + serviceName: 'Microsoft.ContainerInstance/containerGroups' + } + } + ] + } + } + { + name: 'peSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 1) + } + } + ] + } +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created storage account.') +output storageAccountResourceId string = storageAccount.id + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/private-endpoint/main.test.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/private-endpoint/main.test.bicep new file mode 100644 index 000000000..6805475cf --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/private-endpoint/main.test.bicep @@ -0,0 +1,73 @@ +targetScope = 'subscription' + +metadata name = 'Using Private Endpoint' +metadata description = 'This instance deploys the module with access to a private endpoint.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'rdspe' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}sa${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + privateEndpointName: 'dep-${namePrefix}-pe-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + azCliVersion: '2.52.0' + kind: 'AzureCLI' + retentionInterval: 'P1D' + cleanupPreference: 'Always' + subnetResourceIds: [ + nestedDependencies.outputs.subnetResourceId + ] + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + timeout: 'PT1H' + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + } +} diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/private-network/dependencies.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/private-network/dependencies.bicep new file mode 100644 index 000000000..a8dfbc60f --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/private-network/dependencies.bicep @@ -0,0 +1,103 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +var addressPrefix = '10.0.0.0/16' + +// Role required for deployment script to be able to use a storage account via private networking +resource storageFileDataPrivilegedContributor 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: '69566ab7-960f-475b-8e7c-b3118f30c6bd' + scope: tenant() +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageFileSharePermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('storageFileDataPrivilegedContributorRole', managedIdentity.id, storageAccount.id) + scope: storageAccount + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: storageFileDataPrivilegedContributor.id + principalType: 'ServicePrincipal' + } +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + allowSharedKeyAccess: true // Cannot be set to false when using a private network for the deployment script + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + virtualNetworkRules: [ + { + id: virtualNetwork.properties.subnets[0].id + action: 'Allow' + state: 'Succeeded' + } + ] + } + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + ] + delegations: [ + { + name: 'Microsoft.ContainerInstance.containerGroups' + properties: { + serviceName: 'Microsoft.ContainerInstance/containerGroups' + } + } + ] + } + } + ] + } +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created storage account.') +output storageAccountResourceId string = storageAccount.id + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/private-network/main.test.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/private-network/main.test.bicep new file mode 100644 index 000000000..1c568ec90 --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/private-network/main.test.bicep @@ -0,0 +1,75 @@ +targetScope = 'subscription' + +metadata name = 'Using Private Networking' +metadata description = 'This instance deploys the module with access to a private network.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'rdsnet' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + azCliVersion: '2.52.0' + kind: 'AzureCLI' + retentionInterval: 'P1D' + cleanupPreference: 'Always' + subnetResourceIds: [ + nestedDependencies.outputs.subnetResourceId + ] + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + timeout: 'PT1H' + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + } + dependsOn: [ + nestedDependencies + ] +} diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/ps/dependencies.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/ps/dependencies.bicep new file mode 100644 index 000000000..d49ed08f8 --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/ps/dependencies.bicep @@ -0,0 +1,31 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + } +} + +@description('The resource ID of the created managed identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created storage account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/ps/main.test.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/ps/main.test.bicep new file mode 100644 index 000000000..f30d89377 --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/ps/main.test.bicep @@ -0,0 +1,69 @@ +targetScope = 'subscription' + +metadata name = 'Using Azure PowerShell' +metadata description = 'This instance deploys the module with an Azure PowerShell script.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'rdsps' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + azPowerShellVersion: '12.3' + kind: 'AzurePowerShell' + retentionInterval: 'P1D' + arguments: '-var1 \\"AVM Deployment Script test!\\"' + scriptContent: 'param([string] $var1);Write-Host \'Argument var1 value is:\' $var1' + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + } + dependsOn: [ + nestedDependencies + ] +} diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..079914d47 --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,38 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + allowBlobPublicAccess: false + minimumTlsVersion: 'TLS1_2' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } +} + +@description('The resource ID of the created managed identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created storage account.') +output storageAccountResourceId string = storageAccount.id diff --git a/avm/1.1.0/res/resources/deployment-script/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/resources/deployment-script/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..69828fe1b --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,79 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'rdswaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + storageAccountName: 'dep${namePrefix}st${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + azCliVersion: '2.52.0' + kind: 'AzureCLI' + retentionInterval: 'P1D' + cleanupPreference: 'Always' + lock: { + kind: 'None' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + timeout: 'PT1H' + runOnce: true + scriptContent: 'echo \'AVM Deployment Script test!\'' + storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + } + dependsOn: [ + nestedDependencies + ] +} diff --git a/avm/1.1.0/res/resources/deployment-script/version.json b/avm/1.1.0/res/resources/deployment-script/version.json new file mode 100644 index 000000000..41fc8c654 --- /dev/null +++ b/avm/1.1.0/res/resources/deployment-script/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/res/resources/resource-group/README.md b/avm/1.1.0/res/resources/resource-group/README.md new file mode 100644 index 000000000..692f47484 --- /dev/null +++ b/avm/1.1.0/res/resources/resource-group/README.md @@ -0,0 +1,516 @@ +# Resource Groups `[Microsoft.Resources/resourceGroups]` + +This module deploys a Resource Group. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Resources/resourceGroups` | [2021-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/2021-04-01/resourceGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/resources/resource-group:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module resourceGroup 'br/public:avm/res/resources/resource-group:' = { + name: 'resourceGroupDeployment' + params: { + name: 'avm-resources.resourcegroups-rrgmin-rg' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "avm-resources.resourcegroups-rrgmin-rg" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/resource-group:' + +param name = 'avm-resources.resourcegroups-rrgmin-rg' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module resourceGroup 'br/public:avm/res/resources/resource-group:' = { + name: 'resourceGroupDeployment' + params: { + // Required parameters + name: 'avm-resources.resourcegroups-rrgmax-rg' + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '3566ddd3-870d-4618-bd22-3d50915a21ef' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "avm-resources.resourcegroups-rrgmax-rg" + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "3566ddd3-870d-4618-bd22-3d50915a21ef", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/resource-group:' + +// Required parameters +param name = 'avm-resources.resourcegroups-rrgmax-rg' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '3566ddd3-870d-4618-bd22-3d50915a21ef' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module resourceGroup 'br/public:avm/res/resources/resource-group:' = { + name: 'resourceGroupDeployment' + params: { + // Required parameters + name: 'avm-resources.resourcegroups-rrgwaf-rg' + // Non-required parameters + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "avm-resources.resourcegroups-rrgwaf-rg" + }, + // Non-required parameters + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/resource-group:' + +// Required parameters +param name = 'avm-resources.resourcegroups-rrgwaf-rg' +// Non-required parameters +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the Resource Group. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location of the Resource Group. It uses the deployment's location when not provided. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the storage account resource. | + +### Parameter: `name` + +The name of the Resource Group. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location of the Resource Group. It uses the deployment's location when not provided. + +- Required: No +- Type: string +- Default: `[deployment().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the storage account resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the resource group. | +| `resourceId` | string | The resource ID of the resource group. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.4.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/resources/resource-group/main.bicep b/avm/1.1.0/res/resources/resource-group/main.bicep new file mode 100644 index 000000000..cb2c5bfda --- /dev/null +++ b/avm/1.1.0/res/resources/resource-group/main.bicep @@ -0,0 +1,78 @@ +metadata name = 'Resource Groups' +metadata description = 'This module deploys a Resource Group.' + +targetScope = 'subscription' + +@description('Required. The name of the Resource Group.') +param name string + +@description('Optional. Location of the Resource Group. It uses the deployment\'s location when not provided.') +param location string = deployment().location + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.4.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.4.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the storage account resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.resources-resourcegroup.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + location: location + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + location: location + name: name + tags: tags + // managedBy: managedBy // removed due to immutable string, only used for managed resource groups + properties: {} +} + +module resourceGroup_lock 'modules/nested_lock.bicep' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: '${uniqueString(deployment().name, location)}-RG-Lock' + params: { + lock: lock + name: resourceGroup.name + } + scope: resourceGroup +} + +module resourceGroup_roleAssignments 'modules/nested_roleAssignments.bicep' = if (!empty(roleAssignments ?? [])) { + name: '${uniqueString(deployment().name, location)}-RG-RoleAssignments' + params: { + roleAssignments: roleAssignments + } + scope: resourceGroup +} + +@description('The name of the resource group.') +output name string = resourceGroup.name + +@description('The resource ID of the resource group.') +output resourceId string = resourceGroup.id + +@description('The location the resource was deployed into.') +output location string = resourceGroup.location diff --git a/avm/1.1.0/res/resources/resource-group/main.json b/avm/1.1.0/res/resources/resource-group/main.json new file mode 100644 index 000000000..d2dbf9f58 --- /dev/null +++ b/avm/1.1.0/res/resources/resource-group/main.json @@ -0,0 +1,467 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "6674073483996730844" + }, + "name": "Resource Groups", + "description": "This module deploys a Resource Group." + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Resource Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location of the Resource Group. It uses the deployment's location when not provided." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the storage account resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.resources-resourcegroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "location": "[parameters('location')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "resourceGroup": { + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2021-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + }, + "resourceGroup_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-RG-Lock', uniqueString(deployment().name, parameters('location')))]", + "resourceGroup": "[parameters('name')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "lock": { + "value": "[parameters('lock')]" + }, + "name": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "1203907446887412297" + } + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Resource Group." + } + } + }, + "resources": { + "resourceGroup_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + } + } + } + } + }, + "dependsOn": [ + "resourceGroup" + ] + }, + "resourceGroup_roleAssignments": { + "condition": "[not(empty(coalesce(parameters('roleAssignments'), createArray())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-RG-RoleAssignments', uniqueString(deployment().name, parameters('location')))]", + "resourceGroup": "[parameters('name')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "6029968255804453751" + } + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Quota Request Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e5f05e5-9ab9-446b-b98d-1e2157c94125')]", + "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": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Tag Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4a9ae827-6dc8-4573-8ac7-8239d42aa03f')]", + "Template Spec Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c9b6475-caf0-4164-b5a1-2142a7116f4b')]", + "Template Spec Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '392ae280-861d-42bd-9ea5-08ee6d83b80e')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "resourceGroup_roleAssignments": { + "copy": { + "name": "resourceGroup_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceGroup().id, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + } + } + } + }, + "dependsOn": [ + "resourceGroup" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the resource group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the resource group." + }, + "value": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('resourceGroup', '2021-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/resources/resource-group/modules/nested_lock.bicep b/avm/1.1.0/res/resources/resource-group/modules/nested_lock.bicep new file mode 100644 index 000000000..40ae51301 --- /dev/null +++ b/avm/1.1.0/res/resources/resource-group/modules/nested_lock.bicep @@ -0,0 +1,25 @@ +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Required. The name of the Resource Group.') +param name string + +resource resourceGroup_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot delete or modify the resource or child resources.' + } +} + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? diff --git a/avm/1.1.0/res/resources/resource-group/modules/nested_roleAssignments.bicep b/avm/1.1.0/res/resources/resource-group/modules/nested_roleAssignments.bicep new file mode 100644 index 000000000..9916ca803 --- /dev/null +++ b/avm/1.1.0/res/resources/resource-group/modules/nested_roleAssignments.bicep @@ -0,0 +1,88 @@ +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Quota Request Operator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0e5f05e5-9ab9-446b-b98d-1e2157c94125' + ) + 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': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'Tag Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4a9ae827-6dc8-4573-8ac7-8239d42aa03f' + ) + 'Template Spec Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '1c9b6475-caf0-4164-b5a1-2142a7116f4b' + ) + 'Template Spec Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '392ae280-861d-42bd-9ea5-08ee6d83b80e' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource resourceGroup_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(resourceGroup().id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + } +] + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/1.1.0/res/resources/resource-group/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/resources/resource-group/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..6aa3ede53 --- /dev/null +++ b/avm/1.1.0/res/resources/resource-group/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,31 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'rrgmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: 'avm-${namePrefix}-resources.resourcegroups-${serviceShort}-rg' + } + } +] diff --git a/avm/1.1.0/res/resources/resource-group/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/resources/resource-group/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..ca99771dc --- /dev/null +++ b/avm/1.1.0/res/resources/resource-group/tests/e2e/max/dependencies.bicep @@ -0,0 +1,17 @@ +@description('Optional. The location to deploy to.') +param location string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/1.1.0/res/resources/resource-group/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/resources/resource-group/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..2e45ad530 --- /dev/null +++ b/avm/1.1.0/res/resources/resource-group/tests/e2e/max/main.test.bicep @@ -0,0 +1,84 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-resources.resourcegroups-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'rrgmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + location: resourceLocation + name: 'avm-${namePrefix}-resources.resourcegroups-${serviceShort}-rg' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '3566ddd3-870d-4618-bd22-3d50915a21ef' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} diff --git a/avm/1.1.0/res/resources/resource-group/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/resources/resource-group/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..e5a1f58f7 --- /dev/null +++ b/avm/1.1.0/res/resources/resource-group/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,33 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'rrgwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: 'avm-${namePrefix}-resources.resourcegroups-${serviceShort}-rg' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} diff --git a/avm/1.1.0/res/resources/resource-group/version.json b/avm/1.1.0/res/resources/resource-group/version.json new file mode 100644 index 000000000..3f863a2be --- /dev/null +++ b/avm/1.1.0/res/resources/resource-group/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.4", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/1.1.0/res/storage/storage-account/README.md b/avm/1.1.0/res/storage/storage-account/README.md new file mode 100644 index 000000000..82b01bb57 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/README.md @@ -0,0 +1,4897 @@ +# Storage Accounts `[Microsoft.Storage/storageAccounts]` + +This module deploys a Storage Account. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.KeyVault/vaults/secrets` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2023-07-01/vaults/secrets) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | +| `Microsoft.Storage/storageAccounts` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-05-01/storageAccounts) | +| `Microsoft.Storage/storageAccounts/blobServices` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices) | +| `Microsoft.Storage/storageAccounts/blobServices/containers` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers) | +| `Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers/immutabilityPolicies) | +| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/fileServices) | +| `Microsoft.Storage/storageAccounts/fileServices/shares` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/fileServices/shares) | +| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/localUsers) | +| `Microsoft.Storage/storageAccounts/managementPolicies` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/managementPolicies) | +| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices) | +| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices/queues) | +| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices) | +| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices/tables) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/storage/storage-account:`. + +- [Deploying as a Blob Storage](#example-1-deploying-as-a-blob-storage) +- [Deploying as a Block Blob Storage](#example-2-deploying-as-a-block-blob-storage) +- [Using only changefeed configuration](#example-3-using-only-changefeed-configuration) +- [Using only defaults](#example-4-using-only-defaults) +- [Deploying with a key vault reference to save secrets](#example-5-deploying-with-a-key-vault-reference-to-save-secrets) +- [Using large parameter set](#example-6-using-large-parameter-set) +- [Deploying with a NFS File Share](#example-7-deploying-with-a-nfs-file-share) +- [Using Customer-Managed-Keys with System-Assigned identity](#example-8-using-customer-managed-keys-with-system-assigned-identity) +- [Using Customer-Managed-Keys with User-Assigned identity](#example-9-using-customer-managed-keys-with-user-assigned-identity) +- [Deploying as Storage Account version 1](#example-10-deploying-as-storage-account-version-1) +- [WAF-aligned](#example-11-waf-aligned) + +### Example 1: _Deploying as a Blob Storage_ + +This instance deploys the module as a Blob Storage account. + + +

+ +via Bicep module + +```bicep +module storageAccount 'br/public:avm/res/storage/storage-account:' = { + name: 'storageAccountDeployment' + params: { + // Required parameters + name: 'ssablob001' + // Non-required parameters + kind: 'BlobStorage' + location: '' + skuName: 'Standard_LRS' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ssablob001" + }, + // Non-required parameters + "kind": { + "value": "BlobStorage" + }, + "location": { + "value": "" + }, + "skuName": { + "value": "Standard_LRS" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssablob001' +// Non-required parameters +param kind = 'BlobStorage' +param location = '' +param skuName = 'Standard_LRS' +``` + +
+

+ +### Example 2: _Deploying as a Block Blob Storage_ + +This instance deploys the module as a Premium Block Blob Storage account. + + +

+ +via Bicep module + +```bicep +module storageAccount 'br/public:avm/res/storage/storage-account:' = { + name: 'storageAccountDeployment' + params: { + // Required parameters + name: 'ssablock001' + // Non-required parameters + kind: 'BlockBlobStorage' + location: '' + skuName: 'Premium_LRS' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ssablock001" + }, + // Non-required parameters + "kind": { + "value": "BlockBlobStorage" + }, + "location": { + "value": "" + }, + "skuName": { + "value": "Premium_LRS" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssablock001' +// Non-required parameters +param kind = 'BlockBlobStorage' +param location = '' +param skuName = 'Premium_LRS' +``` + +
+

+ +### Example 3: _Using only changefeed configuration_ + +This instance deploys the module with the minimum set of required parameters for the changefeed configuration. + + +

+ +via Bicep module + +```bicep +module storageAccount 'br/public:avm/res/storage/storage-account:' = { + name: 'storageAccountDeployment' + params: { + // Required parameters + name: 'ssachf001' + // Non-required parameters + allowBlobPublicAccess: false + blobServices: { + changeFeedEnabled: true + } + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ssachf001" + }, + // Non-required parameters + "allowBlobPublicAccess": { + "value": false + }, + "blobServices": { + "value": { + "changeFeedEnabled": true + } + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssachf001' +// Non-required parameters +param allowBlobPublicAccess = false +param blobServices = { + changeFeedEnabled: true +} +param location = '' +``` + +
+

+ +### Example 4: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module storageAccount 'br/public:avm/res/storage/storage-account:' = { + name: 'storageAccountDeployment' + params: { + // Required parameters + name: 'ssamin001' + // Non-required parameters + allowBlobPublicAccess: false + location: '' + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ssamin001" + }, + // Non-required parameters + "allowBlobPublicAccess": { + "value": false + }, + "location": { + "value": "" + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "Deny" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssamin001' +// Non-required parameters +param allowBlobPublicAccess = false +param location = '' +param networkAcls = { + bypass: 'AzureServices' + defaultAction: 'Deny' +} +``` + +
+

+ +### Example 5: _Deploying with a key vault reference to save secrets_ + +This instance deploys the module saving all its secrets in a key vault. + + +

+ +via Bicep module + +```bicep +module storageAccount 'br/public:avm/res/storage/storage-account:' = { + name: 'storageAccountDeployment' + params: { + // Required parameters + name: 'kvref' + // Non-required parameters + location: '' + secretsExportConfiguration: { + accessKey1Name: 'custom-key1-name' + accessKey2Name: 'custom-key2-name' + connectionString1Name: 'custom-connectionString1-name' + connectionString2Name: 'custom-connectionString2-name' + keyVaultResourceId: '' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "kvref" + }, + // Non-required parameters + "location": { + "value": "" + }, + "secretsExportConfiguration": { + "value": { + "accessKey1Name": "custom-key1-name", + "accessKey2Name": "custom-key2-name", + "connectionString1Name": "custom-connectionString1-name", + "connectionString2Name": "custom-connectionString2-name", + "keyVaultResourceId": "" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'kvref' +// Non-required parameters +param location = '' +param secretsExportConfiguration = { + accessKey1Name: 'custom-key1-name' + accessKey2Name: 'custom-key2-name' + connectionString1Name: 'custom-connectionString1-name' + connectionString2Name: 'custom-connectionString2-name' + keyVaultResourceId: '' +} +``` + +
+

+ +### Example 6: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module storageAccount 'br/public:avm/res/storage/storage-account:' = { + name: 'storageAccountDeployment' + params: { + // Required parameters + name: 'ssamax001' + // Non-required parameters + allowBlobPublicAccess: false + blobServices: { + automaticSnapshotPolicyEnabled: true + containerDeleteRetentionPolicyDays: 10 + containerDeleteRetentionPolicyEnabled: true + containers: [ + { + enableNfsV3AllSquash: true + enableNfsV3RootSquash: true + name: 'avdscripts' + publicAccess: 'None' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + { + allowProtectedAppendWrites: false + metadata: { + testKey: 'testValue' + } + name: 'archivecontainer' + publicAccess: 'None' + } + ] + corsRules: [ + { + allowedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + allowedMethods: [ + 'GET' + 'PUT' + ] + allowedOrigins: [ + 'http://*.contoso.com' + 'http://www.fabrikam.com' + ] + exposedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + maxAgeInSeconds: 200 + } + ] + deleteRetentionPolicyDays: 9 + deleteRetentionPolicyEnabled: true + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + lastAccessTimeTrackingPolicyEnabled: true + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + enableHierarchicalNamespace: true + enableNfsV3: true + enableSftp: true + fileServices: { + corsRules: [ + { + allowedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + allowedMethods: [ + 'GET' + 'PUT' + ] + allowedOrigins: [ + 'http://*.contoso.com' + 'http://www.fabrikam.com' + ] + exposedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + maxAgeInSeconds: 200 + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + shares: [ + { + accessTier: 'Hot' + name: 'avdprofiles' + roleAssignments: [ + { + name: 'cff1213b-7877-4425-b67c-bb1de8950dfb' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + shareQuota: 5120 + } + { + name: 'avdprofiles2' + shareQuota: 102400 + } + ] + } + largeFileSharesState: 'Enabled' + localUsers: [ + { + hasSharedKey: false + hasSshKey: true + hasSshPassword: false + homeDirectory: 'avdscripts' + name: 'testuser' + permissionScopes: [ + { + permissions: 'r' + resourceName: 'avdscripts' + service: 'blob' + } + ] + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] + } + managementPolicyRules: [ + { + definition: { + actions: { + baseBlob: { + delete: { + daysAfterModificationGreaterThan: 30 + } + tierToCool: { + daysAfterLastAccessTimeGreaterThan: 5 + } + } + } + filters: { + blobIndexMatch: [ + { + name: 'BlobIndex' + op: '==' + value: '1' + } + ] + blobTypes: [ + 'blockBlob' + ] + prefixMatch: [ + 'sample-container/log' + ] + } + } + enabled: true + name: 'FirstRule' + type: 'Lifecycle' + } + ] + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + value: '1.1.1.1' + } + ] + resourceAccessRules: [ + { + resourceId: '' + tenantId: '' + } + ] + virtualNetworkRules: [ + { + action: 'Allow' + id: '' + } + ] + } + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'table' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'queue' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'file' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'web' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'dfs' + subnetResourceId: '' + } + ] + queueServices: { + corsRules: [ + { + allowedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + allowedMethods: [ + 'GET' + 'PUT' + ] + allowedOrigins: [ + 'http://*.contoso.com' + 'http://www.fabrikam.com' + ] + exposedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + maxAgeInSeconds: 200 + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + queues: [ + { + metadata: { + key1: 'value1' + key2: 'value2' + } + name: 'queue1' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + { + metadata: {} + name: 'queue2' + } + ] + } + requireInfrastructureEncryption: true + roleAssignments: [ + { + name: '30b99723-a3d8-4e31-8872-b80c960d62bd' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + sasExpirationPeriod: '180.00:00:00' + skuName: 'Standard_LRS' + tableServices: { + corsRules: [ + { + allowedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + allowedMethods: [ + 'GET' + 'PUT' + ] + allowedOrigins: [ + 'http://*.contoso.com' + 'http://www.fabrikam.com' + ] + exposedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + maxAgeInSeconds: 200 + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + tables: [ + { + name: 'table1' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + { + name: 'table2' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + ] + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ssamax001" + }, + // Non-required parameters + "allowBlobPublicAccess": { + "value": false + }, + "blobServices": { + "value": { + "automaticSnapshotPolicyEnabled": true, + "containerDeleteRetentionPolicyDays": 10, + "containerDeleteRetentionPolicyEnabled": true, + "containers": [ + { + "enableNfsV3AllSquash": true, + "enableNfsV3RootSquash": true, + "name": "avdscripts", + "publicAccess": "None", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + { + "allowProtectedAppendWrites": false, + "metadata": { + "testKey": "testValue" + }, + "name": "archivecontainer", + "publicAccess": "None" + } + ], + "corsRules": [ + { + "allowedHeaders": [ + "x-ms-meta-data", + "x-ms-meta-source-path", + "x-ms-meta-target-path" + ], + "allowedMethods": [ + "GET", + "PUT" + ], + "allowedOrigins": [ + "http://*.contoso.com", + "http://www.fabrikam.com" + ], + "exposedHeaders": [ + "x-ms-meta-data", + "x-ms-meta-source-path", + "x-ms-meta-target-path" + ], + "maxAgeInSeconds": 200 + } + ], + "deleteRetentionPolicyDays": 9, + "deleteRetentionPolicyEnabled": true, + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "lastAccessTimeTrackingPolicyEnabled": true + } + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "enableHierarchicalNamespace": { + "value": true + }, + "enableNfsV3": { + "value": true + }, + "enableSftp": { + "value": true + }, + "fileServices": { + "value": { + "corsRules": [ + { + "allowedHeaders": [ + "x-ms-meta-data", + "x-ms-meta-source-path", + "x-ms-meta-target-path" + ], + "allowedMethods": [ + "GET", + "PUT" + ], + "allowedOrigins": [ + "http://*.contoso.com", + "http://www.fabrikam.com" + ], + "exposedHeaders": [ + "x-ms-meta-data", + "x-ms-meta-source-path", + "x-ms-meta-target-path" + ], + "maxAgeInSeconds": 200 + } + ], + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "shares": [ + { + "accessTier": "Hot", + "name": "avdprofiles", + "roleAssignments": [ + { + "name": "cff1213b-7877-4425-b67c-bb1de8950dfb", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ], + "shareQuota": 5120 + }, + { + "name": "avdprofiles2", + "shareQuota": 102400 + } + ] + } + }, + "largeFileSharesState": { + "value": "Enabled" + }, + "localUsers": { + "value": [ + { + "hasSharedKey": false, + "hasSshKey": true, + "hasSshPassword": false, + "homeDirectory": "avdscripts", + "name": "testuser", + "permissionScopes": [ + { + "permissions": "r", + "resourceName": "avdscripts", + "service": "blob" + } + ] + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "" + ] + } + }, + "managementPolicyRules": { + "value": [ + { + "definition": { + "actions": { + "baseBlob": { + "delete": { + "daysAfterModificationGreaterThan": 30 + }, + "tierToCool": { + "daysAfterLastAccessTimeGreaterThan": 5 + } + } + }, + "filters": { + "blobIndexMatch": [ + { + "name": "BlobIndex", + "op": "==", + "value": "1" + } + ], + "blobTypes": [ + "blockBlob" + ], + "prefixMatch": [ + "sample-container/log" + ] + } + }, + "enabled": true, + "name": "FirstRule", + "type": "Lifecycle" + } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "Deny", + "ipRules": [ + { + "action": "Allow", + "value": "1.1.1.1" + } + ], + "resourceAccessRules": [ + { + "resourceId": "", + "tenantId": "" + } + ], + "virtualNetworkRules": [ + { + "action": "Allow", + "id": "" + } + ] + } + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "blob", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "blob", + "subnetResourceId": "" + }, + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "table", + "subnetResourceId": "" + }, + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "queue", + "subnetResourceId": "" + }, + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "file", + "subnetResourceId": "" + }, + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "web", + "subnetResourceId": "" + }, + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "dfs", + "subnetResourceId": "" + } + ] + }, + "queueServices": { + "value": { + "corsRules": [ + { + "allowedHeaders": [ + "x-ms-meta-data", + "x-ms-meta-source-path", + "x-ms-meta-target-path" + ], + "allowedMethods": [ + "GET", + "PUT" + ], + "allowedOrigins": [ + "http://*.contoso.com", + "http://www.fabrikam.com" + ], + "exposedHeaders": [ + "x-ms-meta-data", + "x-ms-meta-source-path", + "x-ms-meta-target-path" + ], + "maxAgeInSeconds": 200 + } + ], + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "queues": [ + { + "metadata": { + "key1": "value1", + "key2": "value2" + }, + "name": "queue1", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + { + "metadata": {}, + "name": "queue2" + } + ] + } + }, + "requireInfrastructureEncryption": { + "value": true + }, + "roleAssignments": { + "value": [ + { + "name": "30b99723-a3d8-4e31-8872-b80c960d62bd", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "sasExpirationPeriod": { + "value": "180.00:00:00" + }, + "skuName": { + "value": "Standard_LRS" + }, + "tableServices": { + "value": { + "corsRules": [ + { + "allowedHeaders": [ + "x-ms-meta-data", + "x-ms-meta-source-path", + "x-ms-meta-target-path" + ], + "allowedMethods": [ + "GET", + "PUT" + ], + "allowedOrigins": [ + "http://*.contoso.com", + "http://www.fabrikam.com" + ], + "exposedHeaders": [ + "x-ms-meta-data", + "x-ms-meta-source-path", + "x-ms-meta-target-path" + ], + "maxAgeInSeconds": 200 + } + ], + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "tables": [ + { + "name": "table1", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + { + "name": "table2", + "roleAssignments": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + } + ] + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssamax001' +// Non-required parameters +param allowBlobPublicAccess = false +param blobServices = { + automaticSnapshotPolicyEnabled: true + containerDeleteRetentionPolicyDays: 10 + containerDeleteRetentionPolicyEnabled: true + containers: [ + { + enableNfsV3AllSquash: true + enableNfsV3RootSquash: true + name: 'avdscripts' + publicAccess: 'None' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + { + allowProtectedAppendWrites: false + metadata: { + testKey: 'testValue' + } + name: 'archivecontainer' + publicAccess: 'None' + } + ] + corsRules: [ + { + allowedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + allowedMethods: [ + 'GET' + 'PUT' + ] + allowedOrigins: [ + 'http://*.contoso.com' + 'http://www.fabrikam.com' + ] + exposedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + maxAgeInSeconds: 200 + } + ] + deleteRetentionPolicyDays: 9 + deleteRetentionPolicyEnabled: true + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + lastAccessTimeTrackingPolicyEnabled: true +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enableHierarchicalNamespace = true +enableNfsV3: true +param enableSftp = true +param fileServices = { + corsRules: [ + { + allowedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + allowedMethods: [ + 'GET' + 'PUT' + ] + allowedOrigins: [ + 'http://*.contoso.com' + 'http://www.fabrikam.com' + ] + exposedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + maxAgeInSeconds: 200 + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + shares: [ + { + accessTier: 'Hot' + name: 'avdprofiles' + roleAssignments: [ + { + name: 'cff1213b-7877-4425-b67c-bb1de8950dfb' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + shareQuota: 5120 + } + { + name: 'avdprofiles2' + shareQuota: 102400 + } + ] +} +param largeFileSharesState = 'Enabled' +param localUsers = [ + { + hasSharedKey: false + hasSshKey: true + hasSshPassword: false + homeDirectory: 'avdscripts' + name: 'testuser' + permissionScopes: [ + { + permissions: 'r' + resourceName: 'avdscripts' + service: 'blob' + } + ] + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param managementPolicyRules = [ + { + definition: { + actions: { + baseBlob: { + delete: { + daysAfterModificationGreaterThan: 30 + } + tierToCool: { + daysAfterLastAccessTimeGreaterThan: 5 + } + } + } + filters: { + blobIndexMatch: [ + { + name: 'BlobIndex' + op: '==' + value: '1' + } + ] + blobTypes: [ + 'blockBlob' + ] + prefixMatch: [ + 'sample-container/log' + ] + } + } + enabled: true + name: 'FirstRule' + type: 'Lifecycle' + } +] +param networkAcls = { + bypass: 'AzureServices' + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + value: '1.1.1.1' + } + ] + resourceAccessRules: [ + { + resourceId: '' + tenantId: '' + } + ] + virtualNetworkRules: [ + { + action: 'Allow' + id: '' + } + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'table' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'queue' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'file' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'web' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'dfs' + subnetResourceId: '' + } +] +param queueServices = { + corsRules: [ + { + allowedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + allowedMethods: [ + 'GET' + 'PUT' + ] + allowedOrigins: [ + 'http://*.contoso.com' + 'http://www.fabrikam.com' + ] + exposedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + maxAgeInSeconds: 200 + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + queues: [ + { + metadata: { + key1: 'value1' + key2: 'value2' + } + name: 'queue1' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + { + metadata: {} + name: 'queue2' + } + ] +} +param requireInfrastructureEncryption = true +param roleAssignments = [ + { + name: '30b99723-a3d8-4e31-8872-b80c960d62bd' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sasExpirationPeriod = '180.00:00:00' +param skuName = 'Standard_LRS' +param tableServices = { + corsRules: [ + { + allowedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + allowedMethods: [ + 'GET' + 'PUT' + ] + allowedOrigins: [ + 'http://*.contoso.com' + 'http://www.fabrikam.com' + ] + exposedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-source-path' + 'x-ms-meta-target-path' + ] + maxAgeInSeconds: 200 + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + tables: [ + { + name: 'table1' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + { + name: 'table2' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + ] +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +### Example 7: _Deploying with a NFS File Share_ + +This instance deploys the module with a NFS File Share. + + +

+ +via Bicep module + +```bicep +module storageAccount 'br/public:avm/res/storage/storage-account:' = { + name: 'storageAccountDeployment' + params: { + // Required parameters + name: 'ssanfs001' + // Non-required parameters + fileServices: { + shares: [ + { + enabledProtocols: 'NFS' + name: 'nfsfileshare' + } + ] + } + kind: 'FileStorage' + location: '' + skuName: 'Premium_LRS' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ssanfs001" + }, + // Non-required parameters + "fileServices": { + "value": { + "shares": [ + { + "enabledProtocols": "NFS", + "name": "nfsfileshare" + } + ] + } + }, + "kind": { + "value": "FileStorage" + }, + "location": { + "value": "" + }, + "skuName": { + "value": "Premium_LRS" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssanfs001' +// Non-required parameters +param fileServices = { + shares: [ + { + enabledProtocols: 'NFS' + name: 'nfsfileshare' + } + ] +} +param kind = 'FileStorage' +param location = '' +param skuName = 'Premium_LRS' +``` + +
+

+ +### Example 8: _Using Customer-Managed-Keys with System-Assigned identity_ + +This instance deploys the module using Customer-Managed-Keys using a System-Assigned Identity. This required the service to be deployed twice, once as a pre-requisite to create the System-Assigned Identity, and once to use it for accessing the Customer-Managed-Key secret. + + +

+ +via Bicep module + +```bicep +module storageAccount 'br/public:avm/res/storage/storage-account:' = { + name: 'storageAccountDeployment' + params: { + // Required parameters + name: '' + // Non-required parameters + blobServices: { + containers: [ + { + name: 'container' + publicAccess: 'None' + } + ] + } + customerManagedKey: { + keyName: '' + keyVaultResourceId: '' + } + location: '' + managedIdentities: { + systemAssigned: true + } + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "" + }, + // Non-required parameters + "blobServices": { + "value": { + "containers": [ + { + "name": "container", + "publicAccess": "None" + } + ] + } + }, + "customerManagedKey": { + "value": { + "keyName": "", + "keyVaultResourceId": "" + } + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "blob", + "subnetResourceId": "" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = '' +// Non-required parameters +param blobServices = { + containers: [ + { + name: 'container' + publicAccess: 'None' + } + ] +} +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' +} +param location = '' +param managedIdentities = { + systemAssigned: true +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + } +] +``` + +
+

+ +### Example 9: _Using Customer-Managed-Keys with User-Assigned identity_ + +This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. + + +

+ +via Bicep module + +```bicep +module storageAccount 'br/public:avm/res/storage/storage-account:' = { + name: 'storageAccountDeployment' + params: { + // Required parameters + name: 'ssauacr001' + // Non-required parameters + blobServices: { + containers: [ + { + name: 'container' + publicAccess: 'None' + } + ] + } + customerManagedKey: { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' + } + location: '' + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + } + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + } + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ssauacr001" + }, + // Non-required parameters + "blobServices": { + "value": { + "containers": [ + { + "name": "container", + "publicAccess": "None" + } + ] + } + }, + "customerManagedKey": { + "value": { + "keyName": "", + "keyVaultResourceId": "", + "userAssignedIdentityResourceId": "" + } + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "Deny" + } + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "blob", + "subnetResourceId": "" + } + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssauacr001' +// Non-required parameters +param blobServices = { + containers: [ + { + name: 'container' + publicAccess: 'None' + } + ] +} +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param networkAcls = { + bypass: 'AzureServices' + defaultAction: 'Deny' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + } +] +``` + +
+

+ +### Example 10: _Deploying as Storage Account version 1_ + +This instance deploys the module as Storage Account version 1. + + +

+ +via Bicep module + +```bicep +module storageAccount 'br/public:avm/res/storage/storage-account:' = { + name: 'storageAccountDeployment' + params: { + // Required parameters + name: 'ssav1001' + // Non-required parameters + kind: 'Storage' + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ssav1001" + }, + // Non-required parameters + "kind": { + "value": "Storage" + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssav1001' +// Non-required parameters +param kind = 'Storage' +param location = '' +``` + +
+

+ +### Example 11: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module storageAccount 'br/public:avm/res/storage/storage-account:' = { + name: 'storageAccountDeployment' + params: { + // Required parameters + name: 'ssawaf001' + // Non-required parameters + allowBlobPublicAccess: false + blobServices: { + automaticSnapshotPolicyEnabled: true + containerDeleteRetentionPolicyDays: 10 + containerDeleteRetentionPolicyEnabled: true + containers: [ + { + enableNfsV3AllSquash: true + enableNfsV3RootSquash: true + name: 'avdscripts' + publicAccess: 'None' + } + { + allowProtectedAppendWrites: false + metadata: { + testKey: 'testValue' + } + name: 'archivecontainer' + publicAccess: 'None' + } + ] + deleteRetentionPolicyDays: 9 + deleteRetentionPolicyEnabled: true + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + lastAccessTimeTrackingPolicyEnabled: true + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + enableHierarchicalNamespace: true + enableNfsV3: true + enableSftp: true + fileServices: { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + shares: [ + { + accessTier: 'Hot' + name: 'avdprofiles' + shareQuota: 5120 + } + { + name: 'avdprofiles2' + shareQuota: 102400 + } + ] + } + largeFileSharesState: 'Enabled' + localUsers: [ + { + hasSharedKey: false + hasSshKey: true + hasSshPassword: false + homeDirectory: 'avdscripts' + name: 'testuser' + permissionScopes: [ + { + permissions: 'r' + resourceName: 'avdscripts' + service: 'blob' + } + ] + } + ] + location: '' + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] + } + managementPolicyRules: [ + { + definition: { + actions: { + baseBlob: { + delete: { + daysAfterModificationGreaterThan: 30 + } + tierToCool: { + daysAfterLastAccessTimeGreaterThan: 5 + } + } + } + filters: { + blobIndexMatch: [ + { + name: 'BlobIndex' + op: '==' + value: '1' + } + ] + blobTypes: [ + 'blockBlob' + ] + prefixMatch: [ + 'sample-container/log' + ] + } + } + enabled: true + name: 'FirstRule' + type: 'Lifecycle' + } + ] + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + value: '1.1.1.1' + } + ] + virtualNetworkRules: [ + { + action: 'Allow' + id: '' + } + ] + } + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + queueServices: { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + queues: [ + { + metadata: { + key1: 'value1' + key2: 'value2' + } + name: 'queue1' + } + { + metadata: {} + name: 'queue2' + } + ] + } + requireInfrastructureEncryption: true + sasExpirationPeriod: '180.00:00:00' + skuName: 'Standard_ZRS' + tableServices: { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + tables: [ + { + name: 'table1' + } + { + name: 'table2' + } + ] + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ssawaf001" + }, + // Non-required parameters + "allowBlobPublicAccess": { + "value": false + }, + "blobServices": { + "value": { + "automaticSnapshotPolicyEnabled": true, + "containerDeleteRetentionPolicyDays": 10, + "containerDeleteRetentionPolicyEnabled": true, + "containers": [ + { + "enableNfsV3AllSquash": true, + "enableNfsV3RootSquash": true, + "name": "avdscripts", + "publicAccess": "None" + }, + { + "allowProtectedAppendWrites": false, + "metadata": { + "testKey": "testValue" + }, + "name": "archivecontainer", + "publicAccess": "None" + } + ], + "deleteRetentionPolicyDays": 9, + "deleteRetentionPolicyEnabled": true, + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "lastAccessTimeTrackingPolicyEnabled": true + } + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "enableHierarchicalNamespace": { + "value": true + }, + "enableNfsV3": { + "value": true + }, + "enableSftp": { + "value": true + }, + "fileServices": { + "value": { + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "shares": [ + { + "accessTier": "Hot", + "name": "avdprofiles", + "shareQuota": 5120 + }, + { + "name": "avdprofiles2", + "shareQuota": 102400 + } + ] + } + }, + "largeFileSharesState": { + "value": "Enabled" + }, + "localUsers": { + "value": [ + { + "hasSharedKey": false, + "hasSshKey": true, + "hasSshPassword": false, + "homeDirectory": "avdscripts", + "name": "testuser", + "permissionScopes": [ + { + "permissions": "r", + "resourceName": "avdscripts", + "service": "blob" + } + ] + } + ] + }, + "location": { + "value": "" + }, + "managedIdentities": { + "value": { + "systemAssigned": true, + "userAssignedResourceIds": [ + "" + ] + } + }, + "managementPolicyRules": { + "value": [ + { + "definition": { + "actions": { + "baseBlob": { + "delete": { + "daysAfterModificationGreaterThan": 30 + }, + "tierToCool": { + "daysAfterLastAccessTimeGreaterThan": 5 + } + } + }, + "filters": { + "blobIndexMatch": [ + { + "name": "BlobIndex", + "op": "==", + "value": "1" + } + ], + "blobTypes": [ + "blockBlob" + ], + "prefixMatch": [ + "sample-container/log" + ] + } + }, + "enabled": true, + "name": "FirstRule", + "type": "Lifecycle" + } + ] + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "Deny", + "ipRules": [ + { + "action": "Allow", + "value": "1.1.1.1" + } + ], + "virtualNetworkRules": [ + { + "action": "Allow", + "id": "" + } + ] + } + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "service": "blob", + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + ] + }, + "queueServices": { + "value": { + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "queues": [ + { + "metadata": { + "key1": "value1", + "key2": "value2" + }, + "name": "queue1" + }, + { + "metadata": {}, + "name": "queue2" + } + ] + } + }, + "requireInfrastructureEncryption": { + "value": true + }, + "sasExpirationPeriod": { + "value": "180.00:00:00" + }, + "skuName": { + "value": "Standard_ZRS" + }, + "tableServices": { + "value": { + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "tables": [ + { + "name": "table1" + }, + { + "name": "table2" + } + ] + } + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssawaf001' +// Non-required parameters +param allowBlobPublicAccess = false +param blobServices = { + automaticSnapshotPolicyEnabled: true + containerDeleteRetentionPolicyDays: 10 + containerDeleteRetentionPolicyEnabled: true + containers: [ + { + enableNfsV3AllSquash: true + enableNfsV3RootSquash: true + name: 'avdscripts' + publicAccess: 'None' + } + { + allowProtectedAppendWrites: false + metadata: { + testKey: 'testValue' + } + name: 'archivecontainer' + publicAccess: 'None' + } + ] + deleteRetentionPolicyDays: 9 + deleteRetentionPolicyEnabled: true + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + lastAccessTimeTrackingPolicyEnabled: true +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enableHierarchicalNamespace = true +enableNfsV3: true +param enableSftp = true +param fileServices = { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + shares: [ + { + accessTier: 'Hot' + name: 'avdprofiles' + shareQuota: 5120 + } + { + name: 'avdprofiles2' + shareQuota: 102400 + } + ] +} +param largeFileSharesState = 'Enabled' +param localUsers = [ + { + hasSharedKey: false + hasSshKey: true + hasSshPassword: false + homeDirectory: 'avdscripts' + name: 'testuser' + permissionScopes: [ + { + permissions: 'r' + resourceName: 'avdscripts' + service: 'blob' + } + ] + } +] +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param managementPolicyRules = [ + { + definition: { + actions: { + baseBlob: { + delete: { + daysAfterModificationGreaterThan: 30 + } + tierToCool: { + daysAfterLastAccessTimeGreaterThan: 5 + } + } + } + filters: { + blobIndexMatch: [ + { + name: 'BlobIndex' + op: '==' + value: '1' + } + ] + blobTypes: [ + 'blockBlob' + ] + prefixMatch: [ + 'sample-container/log' + ] + } + } + enabled: true + name: 'FirstRule' + type: 'Lifecycle' + } +] +param networkAcls = { + bypass: 'AzureServices' + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + value: '1.1.1.1' + } + ] + virtualNetworkRules: [ + { + action: 'Allow' + id: '' + } + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param queueServices = { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + queues: [ + { + metadata: { + key1: 'value1' + key2: 'value2' + } + name: 'queue1' + } + { + metadata: {} + name: 'queue2' + } + ] +} +param requireInfrastructureEncryption = true +param sasExpirationPeriod = '180.00:00:00' +param skuName = 'Standard_ZRS' +param tableServices = { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + tables: [ + { + name: 'table1' + } + { + name: 'table2' + } + ] +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Storage Account. Must be lower-case. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`accessTier`](#parameter-accesstier) | string | Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The "Premium" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type. | +| [`enableHierarchicalNamespace`](#parameter-enablehierarchicalnamespace) | bool | If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowBlobPublicAccess`](#parameter-allowblobpublicaccess) | bool | Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false. | +| [`allowCrossTenantReplication`](#parameter-allowcrosstenantreplication) | bool | Allow or disallow cross AAD tenant object replication. | +| [`allowedCopyScope`](#parameter-allowedcopyscope) | string | Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet. | +| [`allowSharedKeyAccess`](#parameter-allowsharedkeyaccess) | bool | Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true. | +| [`azureFilesIdentityBasedAuthentication`](#parameter-azurefilesidentitybasedauthentication) | object | Provides the identity based authentication settings for Azure Files. | +| [`blobServices`](#parameter-blobservices) | object | Blob service and containers to deploy. | +| [`customDomainName`](#parameter-customdomainname) | string | Sets the custom domain name assigned to the storage account. Name is the CNAME source. | +| [`customDomainUseSubDomainName`](#parameter-customdomainusesubdomainname) | bool | Indicates whether indirect CName validation is enabled. This should only be set on updates. | +| [`customerManagedKey`](#parameter-customermanagedkey) | object | The customer managed key definition. | +| [`defaultToOAuthAuthentication`](#parameter-defaulttooauthauthentication) | bool | A boolean flag which indicates whether the default authentication is OAuth or not. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`dnsEndpointType`](#parameter-dnsendpointtype) | string | Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier. | +| [`enableNfsV3`](#parameter-enablenfsv3) | bool | If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true. | +| [`enableSftp`](#parameter-enablesftp) | bool | If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`fileServices`](#parameter-fileservices) | object | File service and shares to deploy. | +| [`isLocalUserEnabled`](#parameter-islocaluserenabled) | bool | Enables local users feature, if set to true. | +| [`keyType`](#parameter-keytype) | string | The keyType to use with Queue & Table services. | +| [`kind`](#parameter-kind) | string | Type of Storage Account to create. | +| [`largeFileSharesState`](#parameter-largefilesharesstate) | string | Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares). | +| [`localUsers`](#parameter-localusers) | array | Local users to deploy for SFTP authentication. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`managementPolicyRules`](#parameter-managementpolicyrules) | array | The Storage Account ManagementPolicies Rules. | +| [`minimumTlsVersion`](#parameter-minimumtlsversion) | string | Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore. | +| [`networkAcls`](#parameter-networkacls) | object | Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny. | +| [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set. | +| [`queueServices`](#parameter-queueservices) | object | Queue service and queues to create. | +| [`requireInfrastructureEncryption`](#parameter-requireinfrastructureencryption) | bool | A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`sasExpirationPeriod`](#parameter-sasexpirationperiod) | string | The SAS expiration period. DD.HH:MM:SS. | +| [`secretsExportConfiguration`](#parameter-secretsexportconfiguration) | object | Key vault reference and secret settings for the module's secrets export. | +| [`skuName`](#parameter-skuname) | string | Storage Account Sku Name. | +| [`supportsHttpsTrafficOnly`](#parameter-supportshttpstrafficonly) | bool | Allows HTTPS traffic only to storage service if sets to true. | +| [`tableServices`](#parameter-tableservices) | object | Table service and tables to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `name` + +Name of the Storage Account. Must be lower-case. + +- Required: Yes +- Type: string + +### Parameter: `accessTier` + +Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The "Premium" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type. + +- Required: No +- Type: string +- Default: `'Hot'` +- Allowed: + ```Bicep + [ + 'Cold' + 'Cool' + 'Hot' + 'Premium' + ] + ``` + +### Parameter: `enableHierarchicalNamespace` + +If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `allowBlobPublicAccess` + +Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `allowCrossTenantReplication` + +Allow or disallow cross AAD tenant object replication. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `allowedCopyScope` + +Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'AAD' + 'PrivateLink' + ] + ``` + +### Parameter: `allowSharedKeyAccess` + +Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `azureFilesIdentityBasedAuthentication` + +Provides the identity based authentication settings for Azure Files. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `blobServices` + +Blob service and containers to deploy. + +- Required: No +- Type: object +- Default: `[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]` + +### Parameter: `customDomainName` + +Sets the custom domain name assigned to the storage account. Name is the CNAME source. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `customDomainUseSubDomainName` + +Indicates whether indirect CName validation is enabled. This should only be set on updates. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `customerManagedKey` + +The customer managed key definition. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyName`](#parameter-customermanagedkeykeyname) | string | The name of the customer managed key to use for encryption. | +| [`keyVaultResourceId`](#parameter-customermanagedkeykeyvaultresourceid) | string | The resource ID of a key vault to reference a customer managed key for encryption from. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`autoRotationEnabled`](#parameter-customermanagedkeyautorotationenabled) | bool | Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used. | +| [`keyVersion`](#parameter-customermanagedkeykeyversion) | string | The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting. | +| [`userAssignedIdentityResourceId`](#parameter-customermanagedkeyuserassignedidentityresourceid) | string | User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use. | + +### Parameter: `customerManagedKey.keyName` + +The name of the customer managed key to use for encryption. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKey.keyVaultResourceId` + +The resource ID of a key vault to reference a customer managed key for encryption from. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKey.autoRotationEnabled` + +Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used. + +- Required: No +- Type: bool + +### Parameter: `customerManagedKey.keyVersion` + +The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting. + +- Required: No +- Type: string + +### Parameter: `customerManagedKey.userAssignedIdentityResourceId` + +User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use. + +- Required: No +- Type: string + +### Parameter: `defaultToOAuthAuthentication` + +A boolean flag which indicates whether the default authentication is OAuth or not. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of the diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of the diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `dnsEndpointType` + +Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'AzureDnsZone' + 'Standard' + ] + ``` + +### Parameter: `enableNfsV3` + +If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableSftp` + +If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `fileServices` + +File service and shares to deploy. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `isLocalUserEnabled` + +Enables local users feature, if set to true. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `keyType` + +The keyType to use with Queue & Table services. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Account' + 'Service' + ] + ``` + +### Parameter: `kind` + +Type of Storage Account to create. + +- Required: No +- Type: string +- Default: `'StorageV2'` +- Allowed: + ```Bicep + [ + 'BlobStorage' + 'BlockBlobStorage' + 'FileStorage' + 'Storage' + 'StorageV2' + ] + ``` + +### Parameter: `largeFileSharesState` + +Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares). + +- Required: No +- Type: string +- Default: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `localUsers` + +Local users to deploy for SFTP authentication. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`hasSshKey`](#parameter-localusershassshkey) | bool | Indicates whether SSH key exists. Set it to false to remove existing SSH key. | +| [`hasSshPassword`](#parameter-localusershassshpassword) | bool | Indicates whether SSH password exists. Set it to false to remove existing SSH password. | +| [`name`](#parameter-localusersname) | string | The name of the local user used for SFTP Authentication. | +| [`permissionScopes`](#parameter-localuserspermissionscopes) | array | The permission scopes of the local user. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`hasSharedKey`](#parameter-localusershassharedkey) | bool | Indicates whether shared key exists. Set it to false to remove existing shared key. | +| [`homeDirectory`](#parameter-localusershomedirectory) | string | The local user home directory. | +| [`sshAuthorizedKeys`](#parameter-localuserssshauthorizedkeys) | array | The local user SSH authorized keys for SFTP. | + +### Parameter: `localUsers.hasSshKey` + +Indicates whether SSH key exists. Set it to false to remove existing SSH key. + +- Required: Yes +- Type: bool + +### Parameter: `localUsers.hasSshPassword` + +Indicates whether SSH password exists. Set it to false to remove existing SSH password. + +- Required: Yes +- Type: bool + +### Parameter: `localUsers.name` + +The name of the local user used for SFTP Authentication. + +- Required: Yes +- Type: string + +### Parameter: `localUsers.permissionScopes` + +The permission scopes of the local user. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`permissions`](#parameter-localuserspermissionscopespermissions) | string | The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c). | +| [`resourceName`](#parameter-localuserspermissionscopesresourcename) | string | The name of resource, normally the container name or the file share name, used by the local user. | +| [`service`](#parameter-localuserspermissionscopesservice) | string | The service used by the local user, e.g. blob, file. | + +### Parameter: `localUsers.permissionScopes.permissions` + +The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c). + +- Required: Yes +- Type: string + +### Parameter: `localUsers.permissionScopes.resourceName` + +The name of resource, normally the container name or the file share name, used by the local user. + +- Required: Yes +- Type: string + +### Parameter: `localUsers.permissionScopes.service` + +The service used by the local user, e.g. blob, file. + +- Required: Yes +- Type: string + +### Parameter: `localUsers.hasSharedKey` + +Indicates whether shared key exists. Set it to false to remove existing shared key. + +- Required: No +- Type: bool + +### Parameter: `localUsers.homeDirectory` + +The local user home directory. + +- Required: No +- Type: string + +### Parameter: `localUsers.sshAuthorizedKeys` + +The local user SSH authorized keys for SFTP. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`key`](#parameter-localuserssshauthorizedkeyskey) | securestring | SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-localuserssshauthorizedkeysdescription) | string | Description used to store the function/usage of the key. | + +### Parameter: `localUsers.sshAuthorizedKeys.key` + +SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB. + +- Required: Yes +- Type: securestring + +### Parameter: `localUsers.sshAuthorizedKeys.description` + +Description used to store the function/usage of the key. + +- Required: No +- Type: string + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. + +- Required: No +- Type: array + +### Parameter: `managementPolicyRules` + +The Storage Account ManagementPolicies Rules. + +- Required: No +- Type: array + +### Parameter: `minimumTlsVersion` + +Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore. + +- Required: No +- Type: string +- Default: `'TLS1_2'` +- Allowed: + ```Bicep + [ + 'TLS1_2' + 'TLS1_3' + ] + ``` + +### Parameter: `networkAcls` + +Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`bypass`](#parameter-networkaclsbypass) | string | Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, "Logging, Metrics"), or None to bypass none of those traffics. | +| [`defaultAction`](#parameter-networkaclsdefaultaction) | string | Specifies the default action of allow or deny when no other rules match. | +| [`ipRules`](#parameter-networkaclsiprules) | array | Sets the IP ACL rules. | +| [`resourceAccessRules`](#parameter-networkaclsresourceaccessrules) | array | Sets the resource access rules. Array entries must consist of "tenantId" and "resourceId" fields only. | +| [`virtualNetworkRules`](#parameter-networkaclsvirtualnetworkrules) | array | Sets the virtual network rules. | + +### Parameter: `networkAcls.bypass` + +Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, "Logging, Metrics"), or None to bypass none of those traffics. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureServices' + 'AzureServices, Logging' + 'AzureServices, Logging, Metrics' + 'AzureServices, Metrics' + 'Logging' + 'Logging, Metrics' + 'Metrics' + 'None' + ] + ``` + +### Parameter: `networkAcls.defaultAction` + +Specifies the default action of allow or deny when no other rules match. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Allow' + 'Deny' + ] + ``` + +### Parameter: `networkAcls.ipRules` + +Sets the IP ACL rules. + +- Required: No +- Type: array + +### Parameter: `networkAcls.resourceAccessRules` + +Sets the resource access rules. Array entries must consist of "tenantId" and "resourceId" fields only. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`resourceId`](#parameter-networkaclsresourceaccessrulesresourceid) | string | The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included. | +| [`tenantId`](#parameter-networkaclsresourceaccessrulestenantid) | string | The ID of the tenant in which the resource resides in. | + +### Parameter: `networkAcls.resourceAccessRules.resourceId` + +The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included. + +- Required: Yes +- Type: string + +### Parameter: `networkAcls.resourceAccessRules.tenantId` + +The ID of the tenant in which the resource resides in. + +- Required: Yes +- Type: string + +### Parameter: `networkAcls.virtualNetworkRules` + +Sets the virtual network rules. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints` + +Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file" for a Storage Account's Private Endpoints. | +| [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationSecurityGroupResourceIds`](#parameter-privateendpointsapplicationsecuritygroupresourceids) | array | Application security groups in which the private endpoint IP configuration is included. | +| [`customDnsConfigs`](#parameter-privateendpointscustomdnsconfigs) | array | Custom DNS configurations. | +| [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | +| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | +| [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | +| [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | +| [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | +| [`privateDnsZoneGroup`](#parameter-privateendpointsprivatednszonegroup) | object | The private DNS zone group to configure for the private endpoint. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | +| [`resourceGroupResourceId`](#parameter-privateendpointsresourcegroupresourceid) | string | The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | + +### Parameter: `privateEndpoints.service` + +The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file" for a Storage Account's Private Endpoints. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.subnetResourceId` + +Resource ID of the subnet where the endpoint needs to be created. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.applicationSecurityGroupResourceIds` + +Application security groups in which the private endpoint IP configuration is included. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs` + +Custom DNS configurations. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | FQDN that resolves to private endpoint IP address. | + +### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +A list of private IP addresses of the private endpoint. + +- Required: Yes +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +FQDN that resolves to private endpoint IP address. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.customNetworkInterfaceName` + +The custom name of the network interface attached to the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.ipConfigurations` + +A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsipconfigurationsname) | string | The name of the resource that is unique within a resource group. | +| [`properties`](#parameter-privateendpointsipconfigurationsproperties) | object | Properties of private endpoint IP configurations. | + +### Parameter: `privateEndpoints.ipConfigurations.name` + +The name of the resource that is unique within a resource group. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties` + +Properties of private endpoint IP configurations. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private IP address obtained from the private endpoint's subnet. | + +### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` + +The ID of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.memberName` + +The member name of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` + +A private IP address obtained from the private endpoint's subnet. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.location` + +The location to deploy the private endpoint to. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.lock` + +Specify the type of lock. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-privateendpointslockkind) | string | Specify the type of lock. | +| [`name`](#parameter-privateendpointslockname) | string | Specify the name of lock. | + +### Parameter: `privateEndpoints.lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `privateEndpoints.lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.manualConnectionRequestMessage` + +A message passed to the owner of the remote resource with the manual connection request. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.name` + +The name of the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup` + +The private DNS zone group to configure for the private endpoint. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneGroupConfigs`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigs) | array | The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the Private DNS Zone Group. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs` + +The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneResourceId`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsprivatednszoneresourceid) | string | The resource id of the private DNS zone. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsname) | string | The name of the private DNS Zone Group config. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.privateDnsZoneResourceId` + +The resource id of the private DNS zone. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.name` + +The name of the private DNS Zone Group config. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.name` + +The name of the Private DNS Zone Group. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.resourceGroupResourceId` + +The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-privateendpointsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-privateendpointsroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-privateendpointsroleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-privateendpointsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-privateendpointsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-privateendpointsroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-privateendpointsroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-privateendpointsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `privateEndpoints.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `privateEndpoints.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `privateEndpoints.tags` + +Tags to be applied on all resources/resource groups in this deployment. + +- Required: No +- Type: object + +### Parameter: `publicNetworkAccess` + +Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set. + +- Required: No +- Type: string +- Default: `''` +- Allowed: + ```Bicep + [ + '' + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `queueServices` + +Queue service and queues to create. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `requireInfrastructureEncryption` + +A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reader and Data Access'` + - `'Role Based Access Control Administrator'` + - `'Storage Account Backup Contributor'` + - `'Storage Account Contributor'` + - `'Storage Account Key Operator Service Role'` + - `'Storage Blob Data Contributor'` + - `'Storage Blob Data Owner'` + - `'Storage Blob Data Reader'` + - `'Storage Blob Delegator'` + - `'Storage File Data Privileged Contributor'` + - `'Storage File Data Privileged Reader'` + - `'Storage File Data SMB Share Contributor'` + - `'Storage File Data SMB Share Elevated Contributor'` + - `'Storage File Data SMB Share Reader'` + - `'Storage Queue Data Contributor'` + - `'Storage Queue Data Message Processor'` + - `'Storage Queue Data Message Sender'` + - `'Storage Queue Data Reader'` + - `'Storage Table Data Contributor'` + - `'Storage Table Data Reader'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `sasExpirationPeriod` + +The SAS expiration period. DD.HH:MM:SS. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `secretsExportConfiguration` + +Key vault reference and secret settings for the module's secrets export. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVaultResourceId`](#parameter-secretsexportconfigurationkeyvaultresourceid) | string | The key vault name where to store the keys and connection strings generated by the modules. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`accessKey1Name`](#parameter-secretsexportconfigurationaccesskey1name) | string | The accessKey1 secret name to create. | +| [`accessKey2Name`](#parameter-secretsexportconfigurationaccesskey2name) | string | The accessKey2 secret name to create. | +| [`connectionString1Name`](#parameter-secretsexportconfigurationconnectionstring1name) | string | The connectionString1 secret name to create. | +| [`connectionString2Name`](#parameter-secretsexportconfigurationconnectionstring2name) | string | The connectionString2 secret name to create. | + +### Parameter: `secretsExportConfiguration.keyVaultResourceId` + +The key vault name where to store the keys and connection strings generated by the modules. + +- Required: Yes +- Type: string + +### Parameter: `secretsExportConfiguration.accessKey1Name` + +The accessKey1 secret name to create. + +- Required: No +- Type: string + +### Parameter: `secretsExportConfiguration.accessKey2Name` + +The accessKey2 secret name to create. + +- Required: No +- Type: string + +### Parameter: `secretsExportConfiguration.connectionString1Name` + +The connectionString1 secret name to create. + +- Required: No +- Type: string + +### Parameter: `secretsExportConfiguration.connectionString2Name` + +The connectionString2 secret name to create. + +- Required: No +- Type: string + +### Parameter: `skuName` + +Storage Account Sku Name. + +- Required: No +- Type: string +- Default: `'Standard_GRS'` +- Allowed: + ```Bicep + [ + 'Premium_LRS' + 'Premium_ZRS' + 'Standard_GRS' + 'Standard_GZRS' + 'Standard_LRS' + 'Standard_RAGRS' + 'Standard_RAGZRS' + 'Standard_ZRS' + ] + ``` + +### Parameter: `supportsHttpsTrafficOnly` + +Allows HTTPS traffic only to storage service if sets to true. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `tableServices` + +Table service and tables to create. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `exportedSecrets` | | A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed storage account. | +| `primaryBlobEndpoint` | string | The primary blob endpoint reference if blob services are deployed. | +| `privateEndpoints` | array | The private endpoints of the Storage Account. | +| `resourceGroupName` | string | The resource group of the deployed storage account. | +| `resourceId` | string | The resource ID of the deployed storage account. | +| `serviceEndpoints` | object | All service endpoints of the deployed storage account, Note Standard_LRS and Standard_ZRS accounts only have a blob service endpoint. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/private-endpoint:0.10.1` | Remote reference | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Notes + +This is a generic module for deploying a Storage Account. Any customization for different storage needs (such as a diagnostic or other storage account) need to be done through the Archetype. +The hierarchical namespace of the storage account (see parameter `enableHierarchicalNamespace`), can be only set at creation time. + +A list of supported resource types for the parameter ``networkAclsType.resourceAccessRules`` can be found [here](https://learn.microsoft.com/en-us/azure/storage/common/storage-network-security?tabs=azure-powershell#trusted-access-based-on-a-managed-identity). These can be used with or without wildcards (`*`) in the ``resourceId`` field. + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/storage/storage-account/blob-service/README.md b/avm/1.1.0/res/storage/storage-account/blob-service/README.md new file mode 100644 index 000000000..831df721e --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/blob-service/README.md @@ -0,0 +1,471 @@ +# Storage Account blob Services `[Microsoft.Storage/storageAccounts/blobServices]` + +This module deploys a Storage Account Blob Service. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Storage/storageAccounts/blobServices` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices) | +| `Microsoft.Storage/storageAccounts/blobServices/containers` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers) | +| `Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers/immutabilityPolicies) | + +## Parameters + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageAccountName`](#parameter-storageaccountname) | string | The name of the parent Storage Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`automaticSnapshotPolicyEnabled`](#parameter-automaticsnapshotpolicyenabled) | bool | Automatic Snapshot is enabled if set to true. | +| [`changeFeedEnabled`](#parameter-changefeedenabled) | bool | The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service. | +| [`changeFeedRetentionInDays`](#parameter-changefeedretentionindays) | int | Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed. | +| [`containerDeleteRetentionPolicyAllowPermanentDelete`](#parameter-containerdeleteretentionpolicyallowpermanentdelete) | bool | This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share. | +| [`containerDeleteRetentionPolicyDays`](#parameter-containerdeleteretentionpolicydays) | int | Indicates the number of days that the deleted item should be retained. | +| [`containerDeleteRetentionPolicyEnabled`](#parameter-containerdeleteretentionpolicyenabled) | bool | The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled. | +| [`containers`](#parameter-containers) | array | Blob containers to create. | +| [`corsRules`](#parameter-corsrules) | array | The List of CORS rules. You can include up to five CorsRule elements in the request. | +| [`defaultServiceVersion`](#parameter-defaultserviceversion) | string | Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions. | +| [`deleteRetentionPolicyAllowPermanentDelete`](#parameter-deleteretentionpolicyallowpermanentdelete) | bool | This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share. | +| [`deleteRetentionPolicyDays`](#parameter-deleteretentionpolicydays) | int | Indicates the number of days that the deleted blob should be retained. | +| [`deleteRetentionPolicyEnabled`](#parameter-deleteretentionpolicyenabled) | bool | The blob service properties for blob soft delete. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`isVersioningEnabled`](#parameter-isversioningenabled) | bool | Use versioning to automatically maintain previous versions of your blobs. | +| [`lastAccessTimeTrackingPolicyEnabled`](#parameter-lastaccesstimetrackingpolicyenabled) | bool | The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled. | +| [`restorePolicyDays`](#parameter-restorepolicydays) | int | How long this blob can be restored. It should be less than DeleteRetentionPolicy days. | +| [`restorePolicyEnabled`](#parameter-restorepolicyenabled) | bool | The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled. | + +### Parameter: `storageAccountName` + +The name of the parent Storage Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `automaticSnapshotPolicyEnabled` + +Automatic Snapshot is enabled if set to true. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `changeFeedEnabled` + +The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `changeFeedRetentionInDays` + +Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed. + +- Required: No +- Type: int +- MinValue: 1 +- MaxValue: 146000 + +### Parameter: `containerDeleteRetentionPolicyAllowPermanentDelete` + +This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 1 +- MaxValue: 146000 + +### Parameter: `containerDeleteRetentionPolicyDays` + +Indicates the number of days that the deleted item should be retained. + +- Required: No +- Type: int +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `containerDeleteRetentionPolicyEnabled` + +The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled. + +- Required: No +- Type: bool +- Default: `True` +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `containers` + +Blob containers to create. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `corsRules` + +The List of CORS rules. You can include up to five CorsRule elements in the request. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 365 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowedHeaders`](#parameter-corsrulesallowedheaders) | array | A list of headers allowed to be part of the cross-origin request. | +| [`allowedMethods`](#parameter-corsrulesallowedmethods) | array | A list of HTTP methods that are allowed to be executed by the origin. | +| [`allowedOrigins`](#parameter-corsrulesallowedorigins) | array | A list of origin domains that will be allowed via CORS, or "*" to allow all domains. | +| [`exposedHeaders`](#parameter-corsrulesexposedheaders) | array | A list of response headers to expose to CORS clients. | +| [`maxAgeInSeconds`](#parameter-corsrulesmaxageinseconds) | int | The number of seconds that the client/browser should cache a preflight response. | + +### Parameter: `corsRules.allowedHeaders` + +A list of headers allowed to be part of the cross-origin request. + +- Required: Yes +- Type: array +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `corsRules.allowedMethods` + +A list of HTTP methods that are allowed to be executed by the origin. + +- Required: Yes +- Type: array +- Allowed: + ```Bicep + [ + 'CONNECT' + 'DELETE' + 'GET' + 'HEAD' + 'MERGE' + 'OPTIONS' + 'PATCH' + 'POST' + 'PUT' + 'TRACE' + ] + ``` +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `corsRules.allowedOrigins` + +A list of origin domains that will be allowed via CORS, or "*" to allow all domains. + +- Required: Yes +- Type: array +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `corsRules.exposedHeaders` + +A list of response headers to expose to CORS clients. + +- Required: Yes +- Type: array +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `corsRules.maxAgeInSeconds` + +The number of seconds that the client/browser should cache a preflight response. + +- Required: Yes +- Type: int +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `defaultServiceVersion` + +Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions. + +- Required: No +- Type: string +- Default: `''` +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `deleteRetentionPolicyAllowPermanentDelete` + +This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `deleteRetentionPolicyDays` + +Indicates the number of days that the deleted blob should be retained. + +- Required: No +- Type: int +- Default: `7` +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `deleteRetentionPolicyEnabled` + +The blob service properties for blob soft delete. + +- Required: No +- Type: bool +- Default: `True` +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 365 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of the diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 365 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array +- MinValue: 1 +- MaxValue: 365 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `diagnosticSettings.name` + +The name of the diagnostic setting. + +- Required: No +- Type: string +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `isVersioningEnabled` + +Use versioning to automatically maintain previous versions of your blobs. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `lastAccessTimeTrackingPolicyEnabled` + +The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `restorePolicyDays` + +How long this blob can be restored. It should be less than DeleteRetentionPolicy days. + +- Required: No +- Type: int +- Default: `7` +- MinValue: 1 +- MaxValue: 365 + +### Parameter: `restorePolicyEnabled` + +The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled. + +- Required: No +- Type: bool +- Default: `False` +- MinValue: 1 +- MaxValue: 365 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed blob service. | +| `resourceGroupName` | string | The name of the deployed blob service. | +| `resourceId` | string | The resource ID of the deployed blob service. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | diff --git a/avm/1.1.0/res/storage/storage-account/blob-service/container/README.md b/avm/1.1.0/res/storage/storage-account/blob-service/container/README.md new file mode 100644 index 000000000..1269407b4 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/blob-service/container/README.md @@ -0,0 +1,275 @@ +# Storage Account Blob Containers `[Microsoft.Storage/storageAccounts/blobServices/containers]` + +This module deploys a Storage Account Blob Container. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Storage/storageAccounts/blobServices/containers` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers) | +| `Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers/immutabilityPolicies) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the storage container to deploy. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageAccountName`](#parameter-storageaccountname) | string | The name of the parent Storage Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`blobServiceName`](#parameter-blobservicename) | string | The name of the parent Blob Service. Required if the template is used in a standalone deployment. | +| [`defaultEncryptionScope`](#parameter-defaultencryptionscope) | string | Default the container to use specified encryption scope for all writes. | +| [`denyEncryptionScopeOverride`](#parameter-denyencryptionscopeoverride) | bool | Block override of encryption scope from the container default. | +| [`enableNfsV3AllSquash`](#parameter-enablenfsv3allsquash) | bool | Enable NFSv3 all squash on blob container. | +| [`enableNfsV3RootSquash`](#parameter-enablenfsv3rootsquash) | bool | Enable NFSv3 root squash on blob container. | +| [`immutabilityPolicyName`](#parameter-immutabilitypolicyname) | string | Name of the immutable policy. | +| [`immutabilityPolicyProperties`](#parameter-immutabilitypolicyproperties) | object | Configure immutability policy. | +| [`immutableStorageWithVersioningEnabled`](#parameter-immutablestoragewithversioningenabled) | bool | This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process. | +| [`metadata`](#parameter-metadata) | object | A name-value pair to associate with the container as metadata. | +| [`publicAccess`](#parameter-publicaccess) | string | Specifies whether data in the container may be accessed publicly and the level of access. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | + +### Parameter: `name` + +The name of the storage container to deploy. + +- Required: Yes +- Type: string + +### Parameter: `storageAccountName` + +The name of the parent Storage Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `blobServiceName` + +The name of the parent Blob Service. Required if the template is used in a standalone deployment. + +- Required: No +- Type: string +- Default: `'default'` + +### Parameter: `defaultEncryptionScope` + +Default the container to use specified encryption scope for all writes. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `denyEncryptionScopeOverride` + +Block override of encryption scope from the container default. + +- Required: No +- Type: bool + +### Parameter: `enableNfsV3AllSquash` + +Enable NFSv3 all squash on blob container. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableNfsV3RootSquash` + +Enable NFSv3 root squash on blob container. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `immutabilityPolicyName` + +Name of the immutable policy. + +- Required: No +- Type: string +- Default: `'default'` + +### Parameter: `immutabilityPolicyProperties` + +Configure immutability policy. + +- Required: No +- Type: object + +### Parameter: `immutableStorageWithVersioningEnabled` + +This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `metadata` + +A name-value pair to associate with the container as metadata. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `publicAccess` + +Specifies whether data in the container may be accessed publicly and the level of access. + +- Required: No +- Type: string +- Default: `'None'` +- Allowed: + ```Bicep + [ + 'Blob' + 'Container' + 'None' + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reader and Data Access'` + - `'Role Based Access Control Administrator'` + - `'Storage Account Backup Contributor'` + - `'Storage Account Contributor'` + - `'Storage Account Key Operator Service Role'` + - `'Storage Blob Data Contributor'` + - `'Storage Blob Data Owner'` + - `'Storage Blob Data Reader'` + - `'Storage Blob Delegator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed container. | +| `resourceGroupName` | string | The resource group of the deployed container. | +| `resourceId` | string | The resource ID of the deployed container. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | diff --git a/avm/1.1.0/res/storage/storage-account/blob-service/container/immutability-policy/README.md b/avm/1.1.0/res/storage/storage-account/blob-service/container/immutability-policy/README.md new file mode 100644 index 000000000..2bf8af7bb --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/blob-service/container/immutability-policy/README.md @@ -0,0 +1,78 @@ +# Storage Account Blob Container Immutability Policies `[Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies]` + +This module deploys a Storage Account Blob Container Immutability Policy. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers/immutabilityPolicies) | + +## Parameters + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`containerName`](#parameter-containername) | string | The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment. | +| [`storageAccountName`](#parameter-storageaccountname) | string | The name of the parent Storage Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowProtectedAppendWrites`](#parameter-allowprotectedappendwrites) | bool | This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. | +| [`allowProtectedAppendWritesAll`](#parameter-allowprotectedappendwritesall) | bool | This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both "Append and Block Blobs" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The "allowProtectedAppendWrites" and "allowProtectedAppendWritesAll" properties are mutually exclusive. | +| [`immutabilityPeriodSinceCreationInDays`](#parameter-immutabilityperiodsincecreationindays) | int | The immutability period for the blobs in the container since the policy creation, in days. | + +### Parameter: `containerName` + +The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `storageAccountName` + +The name of the parent Storage Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `allowProtectedAppendWrites` + +This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `allowProtectedAppendWritesAll` + +This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both "Append and Block Blobs" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The "allowProtectedAppendWrites" and "allowProtectedAppendWritesAll" properties are mutually exclusive. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `immutabilityPeriodSinceCreationInDays` + +The immutability period for the blobs in the container since the policy creation, in days. + +- Required: No +- Type: int +- Default: `365` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed immutability policy. | +| `resourceGroupName` | string | The resource group of the deployed immutability policy. | +| `resourceId` | string | The resource ID of the deployed immutability policy. | diff --git a/avm/1.1.0/res/storage/storage-account/blob-service/container/immutability-policy/main.bicep b/avm/1.1.0/res/storage/storage-account/blob-service/container/immutability-policy/main.bicep new file mode 100644 index 000000000..54ef937c9 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/blob-service/container/immutability-policy/main.bicep @@ -0,0 +1,49 @@ +metadata name = 'Storage Account Blob Container Immutability Policies' +metadata description = 'This module deploys a Storage Account Blob Container Immutability Policy.' + +@maxLength(24) +@description('Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment.') +param storageAccountName string + +@description('Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment.') +param containerName string + +@description('Optional. The immutability period for the blobs in the container since the policy creation, in days.') +param immutabilityPeriodSinceCreationInDays int = 365 + +@description('Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API.') +param allowProtectedAppendWrites bool = true + +@description('Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both "Append and Block Blobs" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The "allowProtectedAppendWrites" and "allowProtectedAppendWritesAll" properties are mutually exclusive.') +param allowProtectedAppendWritesAll bool = true + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' existing = { + name: storageAccountName + + resource blobServices 'blobServices@2022-09-01' existing = { + name: 'default' + + resource container 'containers@2022-09-01' existing = { + name: containerName + } + } +} + +resource immutabilityPolicy 'Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies@2022-09-01' = { + name: 'default' + parent: storageAccount::blobServices::container + properties: { + immutabilityPeriodSinceCreationInDays: immutabilityPeriodSinceCreationInDays + allowProtectedAppendWrites: allowProtectedAppendWrites + allowProtectedAppendWritesAll: allowProtectedAppendWritesAll + } +} + +@description('The name of the deployed immutability policy.') +output name string = immutabilityPolicy.name + +@description('The resource ID of the deployed immutability policy.') +output resourceId string = immutabilityPolicy.id + +@description('The resource group of the deployed immutability policy.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/storage/storage-account/blob-service/container/immutability-policy/main.json b/avm/1.1.0/res/storage/storage-account/blob-service/container/immutability-policy/main.json new file mode 100644 index 000000000..834d2b283 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/blob-service/container/immutability-policy/main.json @@ -0,0 +1,84 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "2769922037435749045" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + } + }, + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "properties": { + "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", + "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", + "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed immutability policy." + }, + "value": "default" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed immutability policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed immutability policy." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/storage/storage-account/blob-service/container/main.bicep b/avm/1.1.0/res/storage/storage-account/blob-service/container/main.bicep new file mode 100644 index 000000000..4bf5ee145 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/blob-service/container/main.bicep @@ -0,0 +1,167 @@ +metadata name = 'Storage Account Blob Containers' +metadata description = 'This module deploys a Storage Account Blob Container.' + +@maxLength(24) +@description('Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment.') +param storageAccountName string + +@description('Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment.') +param blobServiceName string = 'default' + +@description('Required. The name of the storage container to deploy.') +param name string + +@description('Optional. Default the container to use specified encryption scope for all writes.') +param defaultEncryptionScope string = '' + +@description('Optional. Block override of encryption scope from the container default.') +param denyEncryptionScopeOverride bool? + +@description('Optional. Enable NFSv3 all squash on blob container.') +param enableNfsV3AllSquash bool = false + +@description('Optional. Enable NFSv3 root squash on blob container.') +param enableNfsV3RootSquash bool = false + +@description('Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process.') +param immutableStorageWithVersioningEnabled bool = false + +@description('Optional. Name of the immutable policy.') +param immutabilityPolicyName string = 'default' + +@description('Optional. Configure immutability policy.') +param immutabilityPolicyProperties object? + +@description('Optional. A name-value pair to associate with the container as metadata.') +param metadata object = {} + +@allowed([ + 'Container' + 'Blob' + 'None' +]) +@description('Optional. Specifies whether data in the container may be accessed publicly and the level of access.') +param publicAccess string = 'None' + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Reader and Data Access': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'c12c1c16-33a1-487b-954d-41c89c60f349' + ) + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'Storage Account Backup Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1' + ) + 'Storage Account Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '17d1049b-9a84-46fb-8f53-869881c3d3ab' + ) + 'Storage Account Key Operator Service Role': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '81a9662b-bebf-436f-a333-f67b29880f12' + ) + 'Storage Blob Data Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' + ) + 'Storage Blob Data Owner': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b' + ) + 'Storage Blob Data Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' + ) + 'Storage Blob Delegator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' existing = { + name: storageAccountName + + resource blobServices 'blobServices@2022-09-01' existing = { + name: blobServiceName + } +} + +resource container 'Microsoft.Storage/storageAccounts/blobServices/containers@2022-09-01' = { + name: name + parent: storageAccount::blobServices + properties: { + defaultEncryptionScope: !empty(defaultEncryptionScope) ? defaultEncryptionScope : null + denyEncryptionScopeOverride: denyEncryptionScopeOverride + enableNfsV3AllSquash: enableNfsV3AllSquash == true ? enableNfsV3AllSquash : null + enableNfsV3RootSquash: enableNfsV3RootSquash == true ? enableNfsV3RootSquash : null + immutableStorageWithVersioning: immutableStorageWithVersioningEnabled == true + ? { + enabled: immutableStorageWithVersioningEnabled + } + : null + metadata: metadata + publicAccess: publicAccess + } +} + +module immutabilityPolicy 'immutability-policy/main.bicep' = if (!empty((immutabilityPolicyProperties ?? {}))) { + name: immutabilityPolicyName + params: { + storageAccountName: storageAccount.name + containerName: container.name + immutabilityPeriodSinceCreationInDays: immutabilityPolicyProperties.?immutabilityPeriodSinceCreationInDays + allowProtectedAppendWrites: immutabilityPolicyProperties.?allowProtectedAppendWrites + allowProtectedAppendWritesAll: immutabilityPolicyProperties.?allowProtectedAppendWritesAll + } +} + +resource container_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(container.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: container + } +] + +@description('The name of the deployed container.') +output name string = container.name + +@description('The resource ID of the deployed container.') +output resourceId string = container.id + +@description('The resource group of the deployed container.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/storage/storage-account/blob-service/container/main.json b/avm/1.1.0/res/storage/storage-account/blob-service/container/main.json new file mode 100644 index 000000000..2cc242698 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/blob-service/container/main.json @@ -0,0 +1,404 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "15727824641798999553" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "blobServiceName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicyName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. Name of the immutable policy." + } + }, + "immutabilityPolicyProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. A name-value pair to associate with the container as metadata." + } + }, + "publicAccess": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Container", + "Blob", + "None" + ], + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::blobServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('storageAccountName')]" + }, + "container": { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", + "denyEncryptionScopeOverride": "[parameters('denyEncryptionScopeOverride')]", + "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", + "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", + "immutableStorageWithVersioning": "[if(equals(parameters('immutableStorageWithVersioningEnabled'), true()), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", + "metadata": "[parameters('metadata')]", + "publicAccess": "[parameters('publicAccess')]" + } + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "container" + ] + }, + "immutabilityPolicy": { + "condition": "[not(empty(coalesce(parameters('immutabilityPolicyProperties'), createObject())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[parameters('immutabilityPolicyName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "containerName": { + "value": "[parameters('name')]" + }, + "immutabilityPeriodSinceCreationInDays": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'immutabilityPeriodSinceCreationInDays')]" + }, + "allowProtectedAppendWrites": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'allowProtectedAppendWrites')]" + }, + "allowProtectedAppendWritesAll": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'allowProtectedAppendWritesAll')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "2769922037435749045" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + } + }, + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "properties": { + "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", + "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", + "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed immutability policy." + }, + "value": "default" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed immutability policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed immutability policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "container" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed container." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/storage/storage-account/blob-service/main.bicep b/avm/1.1.0/res/storage/storage-account/blob-service/main.bicep new file mode 100644 index 000000000..3198c5f31 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/blob-service/main.bicep @@ -0,0 +1,199 @@ +metadata name = 'Storage Account blob Services' +metadata description = 'This module deploys a Storage Account Blob Service.' + +@maxLength(24) +@description('Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment.') +param storageAccountName string + +@description('Optional. Automatic Snapshot is enabled if set to true.') +param automaticSnapshotPolicyEnabled bool = false + +@description('Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service.') +param changeFeedEnabled bool = false + +@minValue(1) +@maxValue(146000) +@description('Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed.') +param changeFeedRetentionInDays int? + +@description('Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled.') +param containerDeleteRetentionPolicyEnabled bool = true + +@minValue(1) +@maxValue(365) +@description('Optional. Indicates the number of days that the deleted item should be retained.') +param containerDeleteRetentionPolicyDays int? + +@description('Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share.') +param containerDeleteRetentionPolicyAllowPermanentDelete bool = false + +@description('Optional. The List of CORS rules. You can include up to five CorsRule elements in the request.') +param corsRules corsRuleType[]? + +@description('Optional. Indicates the default version to use for requests to the Blob service if an incoming request\'s version is not specified. Possible values include version 2008-10-27 and all more recent versions.') +param defaultServiceVersion string = '' + +@description('Optional. The blob service properties for blob soft delete.') +param deleteRetentionPolicyEnabled bool = true + +@minValue(1) +@maxValue(365) +@description('Optional. Indicates the number of days that the deleted blob should be retained.') +param deleteRetentionPolicyDays int = 7 + +@description('Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share.') +param deleteRetentionPolicyAllowPermanentDelete bool = false + +@description('Optional. Use versioning to automatically maintain previous versions of your blobs.') +param isVersioningEnabled bool = false + +@description('Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled.') +param lastAccessTimeTrackingPolicyEnabled bool = false + +@description('Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled.') +param restorePolicyEnabled bool = false + +@minValue(1) +@description('Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days.') +param restorePolicyDays int = 7 + +@description('Optional. Blob containers to create.') +param containers array? + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +// The name of the blob services +var name = 'default' + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' existing = { + name: storageAccountName +} + +resource blobServices 'Microsoft.Storage/storageAccounts/blobServices@2022-09-01' = { + name: name + parent: storageAccount + properties: { + automaticSnapshotPolicyEnabled: automaticSnapshotPolicyEnabled + changeFeed: changeFeedEnabled + ? { + enabled: true + retentionInDays: changeFeedRetentionInDays + } + : null + containerDeleteRetentionPolicy: { + enabled: containerDeleteRetentionPolicyEnabled + days: containerDeleteRetentionPolicyDays + allowPermanentDelete: containerDeleteRetentionPolicyEnabled == true + ? containerDeleteRetentionPolicyAllowPermanentDelete + : null + } + cors: corsRules != null + ? { + corsRules: corsRules + } + : null + defaultServiceVersion: !empty(defaultServiceVersion) ? defaultServiceVersion : null + deleteRetentionPolicy: { + enabled: deleteRetentionPolicyEnabled + days: deleteRetentionPolicyDays + allowPermanentDelete: deleteRetentionPolicyEnabled && deleteRetentionPolicyAllowPermanentDelete ? true : null + } + isVersioningEnabled: isVersioningEnabled + lastAccessTimeTrackingPolicy: storageAccount.kind != 'Storage' + ? { + enable: lastAccessTimeTrackingPolicyEnabled + name: lastAccessTimeTrackingPolicyEnabled == true ? 'AccessTimeTracking' : null + trackingGranularityInDays: lastAccessTimeTrackingPolicyEnabled == true ? 1 : null + } + : null + restorePolicy: restorePolicyEnabled + ? { + enabled: true + days: restorePolicyDays + } + : null + } +} + +resource blobServices_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: blobServices + } +] + +module blobServices_container 'container/main.bicep' = [ + for (container, index) in (containers ?? []): { + name: '${deployment().name}-Container-${index}' + params: { + storageAccountName: storageAccount.name + blobServiceName: blobServices.name + name: container.name + defaultEncryptionScope: container.?defaultEncryptionScope + denyEncryptionScopeOverride: container.?denyEncryptionScopeOverride + enableNfsV3AllSquash: container.?enableNfsV3AllSquash + enableNfsV3RootSquash: container.?enableNfsV3RootSquash + immutableStorageWithVersioningEnabled: container.?immutableStorageWithVersioningEnabled + metadata: container.?metadata + publicAccess: container.?publicAccess + roleAssignments: container.?roleAssignments + immutabilityPolicyProperties: container.?immutabilityPolicyProperties + } + } +] + +@description('The name of the deployed blob service.') +output name string = blobServices.name + +@description('The resource ID of the deployed blob service.') +output resourceId string = blobServices.id + +@description('The name of the deployed blob service.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +@export() +@description('The type for a cors rule.') +type corsRuleType = { + @description('Required. A list of headers allowed to be part of the cross-origin request.') + allowedHeaders: string[] + + @description('Required. A list of HTTP methods that are allowed to be executed by the origin.') + allowedMethods: ('CONNECT' | 'DELETE' | 'GET' | 'HEAD' | 'MERGE' | 'OPTIONS' | 'PATCH' | 'POST' | 'PUT' | 'TRACE')[] + + @description('Required. A list of origin domains that will be allowed via CORS, or "*" to allow all domains.') + allowedOrigins: string[] + + @description('Required. A list of response headers to expose to CORS clients.') + exposedHeaders: string[] + + @description('Required. The number of seconds that the client/browser should cache a preflight response.') + maxAgeInSeconds: int +} diff --git a/avm/1.1.0/res/storage/storage-account/blob-service/main.json b/avm/1.1.0/res/storage/storage-account/blob-service/main.json new file mode 100644 index 000000000..653da1e35 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/blob-service/main.json @@ -0,0 +1,901 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "13802891409950802048" + }, + "name": "Storage Account blob Services", + "description": "This module deploys a Storage Account Blob Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "defaultServiceVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('storageAccountName')]" + }, + "blobServices": { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", + "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", + "containerDeleteRetentionPolicy": { + "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", + "days": "[parameters('containerDeleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" + }, + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "defaultServiceVersion": "[if(not(empty(parameters('defaultServiceVersion'))), parameters('defaultServiceVersion'), null())]", + "deleteRetentionPolicy": { + "enabled": "[parameters('deleteRetentionPolicyEnabled')]", + "days": "[parameters('deleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" + }, + "isVersioningEnabled": "[parameters('isVersioningEnabled')]", + "lastAccessTimeTrackingPolicy": "[if(not(equals(reference('storageAccount', '2022-09-01', 'full').kind, 'Storage')), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", + "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "blobServices_diagnosticSettings": { + "copy": { + "name": "blobServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "blobServices" + ] + }, + "blobServices_container": { + "copy": { + "name": "blobServices_container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "blobServiceName": { + "value": "[variables('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "defaultEncryptionScope": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" + }, + "denyEncryptionScopeOverride": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" + }, + "enableNfsV3AllSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" + }, + "enableNfsV3RootSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" + }, + "immutableStorageWithVersioningEnabled": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" + }, + "publicAccess": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "immutabilityPolicyProperties": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicyProperties')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "15727824641798999553" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "blobServiceName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicyName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. Name of the immutable policy." + } + }, + "immutabilityPolicyProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. A name-value pair to associate with the container as metadata." + } + }, + "publicAccess": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Container", + "Blob", + "None" + ], + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::blobServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('storageAccountName')]" + }, + "container": { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", + "denyEncryptionScopeOverride": "[parameters('denyEncryptionScopeOverride')]", + "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", + "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", + "immutableStorageWithVersioning": "[if(equals(parameters('immutableStorageWithVersioningEnabled'), true()), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", + "metadata": "[parameters('metadata')]", + "publicAccess": "[parameters('publicAccess')]" + } + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "container" + ] + }, + "immutabilityPolicy": { + "condition": "[not(empty(coalesce(parameters('immutabilityPolicyProperties'), createObject())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[parameters('immutabilityPolicyName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "containerName": { + "value": "[parameters('name')]" + }, + "immutabilityPeriodSinceCreationInDays": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'immutabilityPeriodSinceCreationInDays')]" + }, + "allowProtectedAppendWrites": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'allowProtectedAppendWrites')]" + }, + "allowProtectedAppendWritesAll": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'allowProtectedAppendWritesAll')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "2769922037435749045" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + } + }, + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "properties": { + "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", + "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", + "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed immutability policy." + }, + "value": "default" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed immutability policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed immutability policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "container" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed container." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "blobServices" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed blob service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/storage/storage-account/file-service/README.md b/avm/1.1.0/res/storage/storage-account/file-service/README.md new file mode 100644 index 000000000..1cfc35009 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/file-service/README.md @@ -0,0 +1,311 @@ +# Storage Account File Share Services `[Microsoft.Storage/storageAccounts/fileServices]` + +This module deploys a Storage Account File Share Service. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/fileServices) | +| `Microsoft.Storage/storageAccounts/fileServices/shares` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/fileServices/shares) | + +## Parameters + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageAccountName`](#parameter-storageaccountname) | string | The name of the parent Storage Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`corsRules`](#parameter-corsrules) | array | The List of CORS rules. You can include up to five CorsRule elements in the request. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`name`](#parameter-name) | string | The name of the file service. | +| [`protocolSettings`](#parameter-protocolsettings) | object | Protocol settings for file service. | +| [`shareDeleteRetentionPolicy`](#parameter-sharedeleteretentionpolicy) | object | The service properties for soft delete. | +| [`shares`](#parameter-shares) | array | File shares to create. | + +### Parameter: `storageAccountName` + +The name of the parent Storage Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `corsRules` + +The List of CORS rules. You can include up to five CorsRule elements in the request. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowedHeaders`](#parameter-corsrulesallowedheaders) | array | A list of headers allowed to be part of the cross-origin request. | +| [`allowedMethods`](#parameter-corsrulesallowedmethods) | array | A list of HTTP methods that are allowed to be executed by the origin. | +| [`allowedOrigins`](#parameter-corsrulesallowedorigins) | array | A list of origin domains that will be allowed via CORS, or "*" to allow all domains. | +| [`exposedHeaders`](#parameter-corsrulesexposedheaders) | array | A list of response headers to expose to CORS clients. | +| [`maxAgeInSeconds`](#parameter-corsrulesmaxageinseconds) | int | The number of seconds that the client/browser should cache a preflight response. | + +### Parameter: `corsRules.allowedHeaders` + +A list of headers allowed to be part of the cross-origin request. + +- Required: Yes +- Type: array + +### Parameter: `corsRules.allowedMethods` + +A list of HTTP methods that are allowed to be executed by the origin. + +- Required: Yes +- Type: array +- Allowed: + ```Bicep + [ + 'CONNECT' + 'DELETE' + 'GET' + 'HEAD' + 'MERGE' + 'OPTIONS' + 'PATCH' + 'POST' + 'PUT' + 'TRACE' + ] + ``` + +### Parameter: `corsRules.allowedOrigins` + +A list of origin domains that will be allowed via CORS, or "*" to allow all domains. + +- Required: Yes +- Type: array + +### Parameter: `corsRules.exposedHeaders` + +A list of response headers to expose to CORS clients. + +- Required: Yes +- Type: array + +### Parameter: `corsRules.maxAgeInSeconds` + +The number of seconds that the client/browser should cache a preflight response. + +- Required: Yes +- Type: int + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of the diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of the diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `name` + +The name of the file service. + +- Required: No +- Type: string +- Default: `'default'` + +### Parameter: `protocolSettings` + +Protocol settings for file service. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `shareDeleteRetentionPolicy` + +The service properties for soft delete. + +- Required: No +- Type: object +- Default: + ```Bicep + { + days: 7 + enabled: true + } + ``` + +### Parameter: `shares` + +File shares to create. + +- Required: No +- Type: array + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed file share service. | +| `resourceGroupName` | string | The resource group of the deployed file share service. | +| `resourceId` | string | The resource ID of the deployed file share service. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | diff --git a/avm/1.1.0/res/storage/storage-account/file-service/main.bicep b/avm/1.1.0/res/storage/storage-account/file-service/main.bicep new file mode 100644 index 000000000..b14a2ef3e --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/file-service/main.bicep @@ -0,0 +1,125 @@ +metadata name = 'Storage Account File Share Services' +metadata description = 'This module deploys a Storage Account File Share Service.' + +@maxLength(24) +@description('Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment.') +param storageAccountName string + +@description('Optional. The name of the file service.') +param name string = 'default' + +@description('Optional. Protocol settings for file service.') +param protocolSettings object = {} + +@description('Optional. The service properties for soft delete.') +param shareDeleteRetentionPolicy object = { + enabled: true + days: 7 +} + +@description('Optional. The List of CORS rules. You can include up to five CorsRule elements in the request.') +param corsRules corsRuleType[]? + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +@description('Optional. File shares to create.') +param shares array? + +var defaultShareAccessTier = storageAccount.kind == 'FileStorage' ? 'Premium' : 'TransactionOptimized' // default share accessTier depends on the Storage Account kind: 'Premium' for 'FileStorage' kind, 'TransactionOptimized' otherwise + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' existing = { + name: storageAccountName +} + +resource fileServices 'Microsoft.Storage/storageAccounts/fileServices@2023-04-01' = { + name: name + parent: storageAccount + properties: { + cors: corsRules != null + ? { + corsRules: corsRules + } + : null + protocolSettings: protocolSettings + shareDeleteRetentionPolicy: shareDeleteRetentionPolicy + } +} + +resource fileServices_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: fileServices + } +] + +module fileServices_shares 'share/main.bicep' = [ + for (share, index) in (shares ?? []): { + name: '${deployment().name}-shares-${index}' + params: { + storageAccountName: storageAccount.name + fileServicesName: fileServices.name + name: share.name + accessTier: share.?accessTier ?? defaultShareAccessTier + enabledProtocols: share.?enabledProtocols + rootSquash: share.?rootSquash + shareQuota: share.?shareQuota + roleAssignments: share.?roleAssignments + } + } +] + +@description('The name of the deployed file share service.') +output name string = fileServices.name + +@description('The resource ID of the deployed file share service.') +output resourceId string = fileServices.id + +@description('The resource group of the deployed file share service.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +@export() +@description('The type for a cors rule.') +type corsRuleType = { + @description('Required. A list of headers allowed to be part of the cross-origin request.') + allowedHeaders: string[] + + @description('Required. A list of HTTP methods that are allowed to be executed by the origin.') + allowedMethods: ('CONNECT' | 'DELETE' | 'GET' | 'HEAD' | 'MERGE' | 'OPTIONS' | 'PATCH' | 'POST' | 'PUT' | 'TRACE')[] + + @description('Required. A list of origin domains that will be allowed via CORS, or "*" to allow all domains.') + allowedOrigins: string[] + + @description('Required. A list of response headers to expose to CORS clients.') + exposedHeaders: string[] + + @description('Required. The number of seconds that the client/browser should cache a preflight response.') + maxAgeInSeconds: int +} diff --git a/avm/1.1.0/res/storage/storage-account/file-service/main.json b/avm/1.1.0/res/storage/storage-account/file-service/main.json new file mode 100644 index 000000000..525749699 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/file-service/main.json @@ -0,0 +1,760 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "987643333058038389" + }, + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Protocol settings for file service." + } + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "defaultValue": { + "enabled": true, + "days": 7 + }, + "metadata": { + "description": "Optional. The service properties for soft delete." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + } + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "15193761941438215308" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "TransactionOptimized", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" + } + }, + "fileShare_roleAssignments": { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "scope": { + "value": "[replace(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), '/shares/', '/fileshares/')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "condition": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), createObject('value', coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0')), createObject('value', null()))]", + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[parameters('scope')]", + "name": "[parameters('name')]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('principalId')]", + "description": "[parameters('description')]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "fileServices", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/storage/storage-account/file-service/share/README.md b/avm/1.1.0/res/storage/storage-account/file-service/share/README.md new file mode 100644 index 000000000..2f9f1ef4e --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/file-service/share/README.md @@ -0,0 +1,246 @@ +# Storage Account File Shares `[Microsoft.Storage/storageAccounts/fileServices/shares]` + +This module deploys a Storage Account File Share. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Storage/storageAccounts/fileServices/shares` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/fileServices/shares) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the file share to create. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`accessTier`](#parameter-accesstier) | string | Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to "Premium"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool. | +| [`fileServicesName`](#parameter-fileservicesname) | string | The name of the parent file service. Required if the template is used in a standalone deployment. | +| [`storageAccountName`](#parameter-storageaccountname) | string | The name of the parent Storage Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabledProtocols`](#parameter-enabledprotocols) | string | The authentication protocol that is used for the file share. Can only be specified when creating a share. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`rootSquash`](#parameter-rootsquash) | string | Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares. | +| [`shareQuota`](#parameter-sharequota) | int | The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB). | + +### Parameter: `name` + +The name of the file share to create. + +- Required: Yes +- Type: string + +### Parameter: `accessTier` + +Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to "Premium"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool. + +- Required: No +- Type: string +- Default: `'TransactionOptimized'` +- Allowed: + ```Bicep + [ + 'Cool' + 'Hot' + 'Premium' + 'TransactionOptimized' + ] + ``` + +### Parameter: `fileServicesName` + +The name of the parent file service. Required if the template is used in a standalone deployment. + +- Required: No +- Type: string +- Default: `'default'` + +### Parameter: `storageAccountName` + +The name of the parent Storage Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `enabledProtocols` + +The authentication protocol that is used for the file share. Can only be specified when creating a share. + +- Required: No +- Type: string +- Default: `'SMB'` +- Allowed: + ```Bicep + [ + 'NFS' + 'SMB' + ] + ``` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reader and Data Access'` + - `'Role Based Access Control Administrator'` + - `'Storage Account Backup Contributor'` + - `'Storage Account Contributor'` + - `'Storage Account Key Operator Service Role'` + - `'Storage File Data SMB Share Contributor'` + - `'Storage File Data SMB Share Elevated Contributor'` + - `'Storage File Data SMB Share Reader'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `rootSquash` + +Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares. + +- Required: No +- Type: string +- Default: `'NoRootSquash'` +- Allowed: + ```Bicep + [ + 'AllSquash' + 'NoRootSquash' + 'RootSquash' + ] + ``` + +### Parameter: `shareQuota` + +The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB). + +- Required: No +- Type: int +- Default: `5120` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed file share. | +| `resourceGroupName` | string | The resource group of the deployed file share. | +| `resourceId` | string | The resource ID of the deployed file share. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | diff --git a/avm/1.1.0/res/storage/storage-account/file-service/share/main.bicep b/avm/1.1.0/res/storage/storage-account/file-service/share/main.bicep new file mode 100644 index 000000000..ce1477aab --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/file-service/share/main.bicep @@ -0,0 +1,142 @@ +metadata name = 'Storage Account File Shares' +metadata description = 'This module deploys a Storage Account File Share.' + +@maxLength(24) +@description('Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment.') +param storageAccountName string + +@description('Conditional. The name of the parent file service. Required if the template is used in a standalone deployment.') +param fileServicesName string = 'default' + +@description('Required. The name of the file share to create.') +param name string + +@allowed([ + 'Premium' + 'Hot' + 'Cool' + 'TransactionOptimized' +]) +@description('Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to "Premium"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool.') +param accessTier string = 'TransactionOptimized' + +@description('Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB).') +param shareQuota int = 5120 + +@allowed([ + 'NFS' + 'SMB' +]) +@description('Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share.') +param enabledProtocols string = 'SMB' + +@allowed([ + 'AllSquash' + 'NoRootSquash' + 'RootSquash' +]) +@description('Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares.') +param rootSquash string = 'NoRootSquash' + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Reader and Data Access': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'c12c1c16-33a1-487b-954d-41c89c60f349' + ) + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'Storage Account Backup Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1' + ) + 'Storage Account Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '17d1049b-9a84-46fb-8f53-869881c3d3ab' + ) + 'Storage Account Key Operator Service Role': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '81a9662b-bebf-436f-a333-f67b29880f12' + ) + 'Storage File Data SMB Share Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb' + ) + 'Storage File Data SMB Share Elevated Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a7264617-510b-434b-a828-9731dc254ea7' + ) + 'Storage File Data SMB Share Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'aba4ae5f-2193-4029-9191-0cb91df5e314' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' existing = { + name: storageAccountName + + resource fileService 'fileServices@2023-04-01' existing = { + name: fileServicesName + } +} + +resource fileShare 'Microsoft.Storage/storageAccounts/fileServices/shares@2023-01-01' = { + name: name + parent: storageAccount::fileService + properties: { + accessTier: accessTier + shareQuota: shareQuota + rootSquash: enabledProtocols == 'NFS' ? rootSquash : null + enabledProtocols: enabledProtocols + } +} + +// NOTE: This is a workaround for a bug of the resource provider. Ref: https://github.com/Azure/bicep-types-az/issues/1532 +module fileShare_roleAssignments './modules/nested_inner_roleAssignment.json' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: '${uniqueString(deployment().name)}-Share-Rbac-${index}' + params: { + scope: replace(fileShare.id, '/shares/', '/fileshares/') + name: roleAssignment.?name ?? guid(fileShare.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + description: roleAssignment.?description + } + } +] + +@description('The name of the deployed file share.') +output name string = fileShare.name + +@description('The resource ID of the deployed file share.') +output resourceId string = fileShare.id + +@description('The resource group of the deployed file share.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/storage/storage-account/file-service/share/main.json b/avm/1.1.0/res/storage/storage-account/file-service/share/main.json new file mode 100644 index 000000000..8d520a827 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/file-service/share/main.json @@ -0,0 +1,375 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "15193761941438215308" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "TransactionOptimized", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" + } + }, + "fileShare_roleAssignments": { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "scope": { + "value": "[replace(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), '/shares/', '/fileshares/')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "condition": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), createObject('value', coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0')), createObject('value', null()))]", + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[parameters('scope')]", + "name": "[parameters('name')]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('principalId')]", + "description": "[parameters('description')]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/storage/storage-account/file-service/share/modules/nested_inner_roleAssignment.json b/avm/1.1.0/res/storage/storage-account/file-service/share/modules/nested_inner_roleAssignment.json new file mode 100644 index 000000000..12470dd7d --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/file-service/share/modules/nested_inner_roleAssignment.json @@ -0,0 +1,93 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[parameters('scope')]", + "name": "[parameters('name')]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('principalId')]", + "description": "[parameters('description')]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] +} diff --git a/avm/1.1.0/res/storage/storage-account/local-user/README.md b/avm/1.1.0/res/storage/storage-account/local-user/README.md new file mode 100644 index 000000000..31246477d --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/local-user/README.md @@ -0,0 +1,161 @@ +# Storage Account Local Users `[Microsoft.Storage/storageAccounts/localUsers]` + +This module deploys a Storage Account Local User, which is used for SFTP authentication. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/localUsers) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`hasSshKey`](#parameter-hassshkey) | bool | Indicates whether SSH key exists. Set it to false to remove existing SSH key. | +| [`hasSshPassword`](#parameter-hassshpassword) | bool | Indicates whether SSH password exists. Set it to false to remove existing SSH password. | +| [`name`](#parameter-name) | string | The name of the local user used for SFTP Authentication. | +| [`permissionScopes`](#parameter-permissionscopes) | array | The permission scopes of the local user. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageAccountName`](#parameter-storageaccountname) | string | The name of the parent Storage Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`hasSharedKey`](#parameter-hassharedkey) | bool | Indicates whether shared key exists. Set it to false to remove existing shared key. | +| [`homeDirectory`](#parameter-homedirectory) | string | The local user home directory. | +| [`sshAuthorizedKeys`](#parameter-sshauthorizedkeys) | array | The local user SSH authorized keys for SFTP. | + +### Parameter: `hasSshKey` + +Indicates whether SSH key exists. Set it to false to remove existing SSH key. + +- Required: Yes +- Type: bool + +### Parameter: `hasSshPassword` + +Indicates whether SSH password exists. Set it to false to remove existing SSH password. + +- Required: Yes +- Type: bool + +### Parameter: `name` + +The name of the local user used for SFTP Authentication. + +- Required: Yes +- Type: string + +### Parameter: `permissionScopes` + +The permission scopes of the local user. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`permissions`](#parameter-permissionscopespermissions) | string | The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c). | +| [`resourceName`](#parameter-permissionscopesresourcename) | string | The name of resource, normally the container name or the file share name, used by the local user. | +| [`service`](#parameter-permissionscopesservice) | string | The service used by the local user, e.g. blob, file. | + +### Parameter: `permissionScopes.permissions` + +The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c). + +- Required: Yes +- Type: string + +### Parameter: `permissionScopes.resourceName` + +The name of resource, normally the container name or the file share name, used by the local user. + +- Required: Yes +- Type: string + +### Parameter: `permissionScopes.service` + +The service used by the local user, e.g. blob, file. + +- Required: Yes +- Type: string + +### Parameter: `storageAccountName` + +The name of the parent Storage Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `hasSharedKey` + +Indicates whether shared key exists. Set it to false to remove existing shared key. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `homeDirectory` + +The local user home directory. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `sshAuthorizedKeys` + +The local user SSH authorized keys for SFTP. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`key`](#parameter-sshauthorizedkeyskey) | securestring | SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-sshauthorizedkeysdescription) | string | Description used to store the function/usage of the key. | + +### Parameter: `sshAuthorizedKeys.key` + +SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB. + +- Required: Yes +- Type: securestring + +### Parameter: `sshAuthorizedKeys.description` + +Description used to store the function/usage of the key. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed local user. | +| `resourceGroupName` | string | The resource group of the deployed local user. | +| `resourceId` | string | The resource ID of the deployed local user. | diff --git a/avm/1.1.0/res/storage/storage-account/local-user/main.bicep b/avm/1.1.0/res/storage/storage-account/local-user/main.bicep new file mode 100644 index 000000000..d5e6edcb5 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/local-user/main.bicep @@ -0,0 +1,78 @@ +metadata name = 'Storage Account Local Users' +metadata description = 'This module deploys a Storage Account Local User, which is used for SFTP authentication.' + +@maxLength(24) +@description('Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment.') +param storageAccountName string + +@description('Required. The name of the local user used for SFTP Authentication.') +param name string + +@description('Optional. Indicates whether shared key exists. Set it to false to remove existing shared key.') +param hasSharedKey bool = false + +@description('Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key.') +param hasSshKey bool + +@description('Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password.') +param hasSshPassword bool + +@description('Optional. The local user home directory.') +param homeDirectory string = '' + +@description('Required. The permission scopes of the local user.') +param permissionScopes permissionScopeType[] + +@description('Optional. The local user SSH authorized keys for SFTP.') +param sshAuthorizedKeys sshAuthorizedKeyType[]? + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' existing = { + name: storageAccountName +} + +resource localUsers 'Microsoft.Storage/storageAccounts/localUsers@2023-04-01' = { + name: name + parent: storageAccount + properties: { + hasSharedKey: hasSharedKey + hasSshKey: hasSshKey + hasSshPassword: hasSshPassword + homeDirectory: homeDirectory + permissionScopes: permissionScopes + sshAuthorizedKeys: sshAuthorizedKeys + } +} + +@description('The name of the deployed local user.') +output name string = localUsers.name + +@description('The resource group of the deployed local user.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the deployed local user.') +output resourceId string = localUsers.id + +// =============== // +// Definitions // +// =============== // +@export() +type sshAuthorizedKeyType = { + @description('Optional. Description used to store the function/usage of the key.') + description: string? + + @secure() + @description('Required. SSH public key base64 encoded. The format should be: \'{keyType} {keyData}\', e.g. ssh-rsa AAAABBBB.') + key: string +} + +@export() +type permissionScopeType = { + @description('Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c).') + permissions: string + + @description('Required. The name of resource, normally the container name or the file share name, used by the local user.') + resourceName: string + + @description('Required. The service used by the local user, e.g. blob, file.') + service: string +} diff --git a/avm/1.1.0/res/storage/storage-account/local-user/main.json b/avm/1.1.0/res/storage/storage-account/local-user/main.json new file mode 100644 index 000000000..12583d34c --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/local-user/main.json @@ -0,0 +1,167 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "2528560857012083896" + }, + "name": "Storage Account Local Users", + "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication." + }, + "definitions": { + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "localUsers": { + "type": "Microsoft.Storage/storageAccounts/localUsers", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "hasSharedKey": "[parameters('hasSharedKey')]", + "hasSshKey": "[parameters('hasSshKey')]", + "hasSshPassword": "[parameters('hasSshPassword')]", + "homeDirectory": "[parameters('homeDirectory')]", + "permissionScopes": "[parameters('permissionScopes')]", + "sshAuthorizedKeys": "[parameters('sshAuthorizedKeys')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed local user." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed local user." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed local user." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/storage/storage-account/main.bicep b/avm/1.1.0/res/storage/storage-account/main.bicep new file mode 100644 index 000000000..c6a0d7b02 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/main.bicep @@ -0,0 +1,833 @@ +metadata name = 'Storage Accounts' +metadata description = 'This module deploys a Storage Account.' + +@maxLength(24) +@description('Required. Name of the Storage Account. Must be lower-case.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +import { managedIdentityAllType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentityAllType? + +@allowed([ + 'Storage' + 'StorageV2' + 'BlobStorage' + 'FileStorage' + 'BlockBlobStorage' +]) +@description('Optional. Type of Storage Account to create.') +param kind string = 'StorageV2' + +@allowed([ + 'Standard_LRS' + 'Standard_GRS' + 'Standard_RAGRS' + 'Standard_ZRS' + 'Premium_LRS' + 'Premium_ZRS' + 'Standard_GZRS' + 'Standard_RAGZRS' +]) +@description('Optional. Storage Account Sku Name.') +param skuName string = 'Standard_GRS' + +@allowed([ + 'Premium' + 'Hot' + 'Cool' + 'Cold' +]) +@description('Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The "Premium" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type.') +param accessTier string = 'Hot' + +@allowed([ + 'Disabled' + 'Enabled' +]) +@description('Optional. Allow large file shares if sets to \'Enabled\'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares).') +param largeFileSharesState string = 'Disabled' + +@description('Optional. Provides the identity based authentication settings for Azure Files.') +param azureFilesIdentityBasedAuthentication object = {} + +@description('Optional. A boolean flag which indicates whether the default authentication is OAuth or not.') +param defaultToOAuthAuthentication bool = false + +@description('Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true.') +param allowSharedKeyAccess bool = true + +import { privateEndpointMultiServiceType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointMultiServiceType[]? + +@description('Optional. The Storage Account ManagementPolicies Rules.') +param managementPolicyRules array? + +@description('Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny.') +param networkAcls networkAclsType? + +@description('Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true.') +param requireInfrastructureEncryption bool = true + +@description('Optional. Allow or disallow cross AAD tenant object replication.') +param allowCrossTenantReplication bool = false + +@description('Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source.') +param customDomainName string = '' + +@description('Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates.') +param customDomainUseSubDomainName bool = false + +@description('Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier.') +@allowed([ + '' + 'AzureDnsZone' + 'Standard' +]) +param dnsEndpointType string = '' + +@description('Optional. Blob service and containers to deploy.') +param blobServices object = kind != 'FileStorage' + ? { + containerDeleteRetentionPolicyEnabled: true + containerDeleteRetentionPolicyDays: 7 + deleteRetentionPolicyEnabled: true + deleteRetentionPolicyDays: 6 + } + : {} + +@description('Optional. File service and shares to deploy.') +param fileServices object = {} + +@description('Optional. Queue service and queues to create.') +param queueServices object = {} + +@description('Optional. Table service and tables to create.') +param tableServices object = {} + +@description('Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false.') +param allowBlobPublicAccess bool = false + +@allowed([ + 'TLS1_2' + 'TLS1_3' +]) +@description('Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore.') +param minimumTlsVersion string = 'TLS1_2' + +@description('Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true.') +param enableHierarchicalNamespace bool = false + +@description('Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true.') +param enableSftp bool = false + +@description('Optional. Local users to deploy for SFTP authentication.') +param localUsers localUserType[]? + +@description('Optional. Enables local users feature, if set to true.') +param isLocalUserEnabled bool = false + +@description('Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true.') +param enableNfsV3 bool = false + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet.') +@allowed([ + '' + 'AAD' + 'PrivateLink' +]) +param allowedCopyScope string = '' + +@description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set.') +@allowed([ + '' + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string = '' + +@description('Optional. Allows HTTPS traffic only to storage service if sets to true.') +param supportsHttpsTrafficOnly bool = true + +import { customerManagedKeyWithAutoRotateType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The customer managed key definition.') +param customerManagedKey customerManagedKeyWithAutoRotateType? + +@description('Optional. The SAS expiration period. DD.HH:MM:SS.') +param sasExpirationPeriod string = '' + +@description('Optional. The keyType to use with Queue & Table services.') +@allowed([ + 'Account' + 'Service' +]) +param keyType string? + +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + +var supportsBlobService = kind == 'BlockBlobStorage' || kind == 'BlobStorage' || kind == 'StorageV2' || kind == 'Storage' +var supportsFileService = kind == 'FileStorage' || kind == 'StorageV2' || kind == 'Storage' + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Reader and Data Access': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'c12c1c16-33a1-487b-954d-41c89c60f349' + ) + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'Storage Account Backup Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1' + ) + 'Storage Account Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '17d1049b-9a84-46fb-8f53-869881c3d3ab' + ) + 'Storage Account Key Operator Service Role': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '81a9662b-bebf-436f-a333-f67b29880f12' + ) + 'Storage Blob Data Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' + ) + 'Storage Blob Data Owner': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b' + ) + 'Storage Blob Data Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' + ) + 'Storage Blob Delegator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a' + ) + 'Storage File Data Privileged Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '69566ab7-960f-475b-8e7c-b3118f30c6bd' + ) + 'Storage File Data Privileged Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b8eda974-7b85-4f76-af95-65846b26df6d' + ) + 'Storage File Data SMB Share Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb' + ) + 'Storage File Data SMB Share Elevated Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a7264617-510b-434b-a828-9731dc254ea7' + ) + 'Storage File Data SMB Share Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'aba4ae5f-2193-4029-9191-0cb91df5e314' + ) + 'Storage Queue Data Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '974c5e8b-45b9-4653-ba55-5f855dd0fb88' + ) + 'Storage Queue Data Message Processor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '8a0f0c08-91a1-4084-bc3d-661d67233fed' + ) + 'Storage Queue Data Message Sender': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a' + ) + 'Storage Queue Data Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '19e7f393-937e-4f77-808e-94535e297925' + ) + 'Storage Table Data Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3' + ) + 'Storage Table Data Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '76199698-9eea-4c19-bc75-cec21354c6b6' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.storage-storageaccount.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource cMKKeyVault 'Microsoft.KeyVault/vaults@2023-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId)) { + name: last(split((customerManagedKey.?keyVaultResourceId ?? 'dummyVault'), '/')) + scope: resourceGroup( + split((customerManagedKey.?keyVaultResourceId ?? '//'), '/')[2], + split((customerManagedKey.?keyVaultResourceId ?? '////'), '/')[4] + ) + + resource cMKKey 'keys@2023-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { + name: customerManagedKey.?keyName ?? 'dummyKey' + } +} + +resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = if (!empty(customerManagedKey.?userAssignedIdentityResourceId)) { + name: last(split(customerManagedKey.?userAssignedIdentityResourceId ?? 'dummyMsi', '/')) + scope: resourceGroup( + split((customerManagedKey.?userAssignedIdentityResourceId ?? '//'), '/')[2], + split((customerManagedKey.?userAssignedIdentityResourceId ?? '////'), '/')[4] + ) +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = { + name: name + location: location + kind: kind + sku: { + name: skuName + } + identity: identity + tags: tags + properties: { + allowSharedKeyAccess: allowSharedKeyAccess + defaultToOAuthAuthentication: defaultToOAuthAuthentication + allowCrossTenantReplication: allowCrossTenantReplication + allowedCopyScope: !empty(allowedCopyScope) ? allowedCopyScope : null + customDomain: { + name: customDomainName + useSubDomainName: customDomainUseSubDomainName + } + dnsEndpointType: !empty(dnsEndpointType) ? dnsEndpointType : null + isLocalUserEnabled: isLocalUserEnabled + encryption: union( + { + keySource: !empty(customerManagedKey) ? 'Microsoft.Keyvault' : 'Microsoft.Storage' + services: { + blob: supportsBlobService + ? { + enabled: true + } + : null + file: supportsFileService + ? { + enabled: true + } + : null + table: { + enabled: true + keyType: keyType + } + queue: { + enabled: true + keyType: keyType + } + } + keyvaultproperties: !empty(customerManagedKey) + ? { + keyname: customerManagedKey!.keyName + keyvaulturi: cMKKeyVault.properties.vaultUri + keyversion: !empty(customerManagedKey.?keyVersion) + ? customerManagedKey!.keyVersion + : (customerManagedKey.?autoRotationEnabled ?? true) + ? null + : last(split(cMKKeyVault::cMKKey.properties.keyUriWithVersion, '/')) + } + : null + identity: { + userAssignedIdentity: !empty(customerManagedKey.?userAssignedIdentityResourceId) + ? cMKUserAssignedIdentity.id + : null + } + }, + (requireInfrastructureEncryption + ? { + requireInfrastructureEncryption: kind != 'Storage' ? requireInfrastructureEncryption : null + } + : {}) + ) + accessTier: (kind != 'Storage' && kind != 'BlockBlobStorage') ? accessTier : null + sasPolicy: !empty(sasExpirationPeriod) + ? { + expirationAction: 'Log' + sasExpirationPeriod: sasExpirationPeriod + } + : null + supportsHttpsTrafficOnly: supportsHttpsTrafficOnly + isHnsEnabled: enableHierarchicalNamespace + isSftpEnabled: enableSftp + isNfsV3Enabled: enableNfsV3 ? enableNfsV3 : any('') + largeFileSharesState: (skuName == 'Standard_LRS') || (skuName == 'Standard_ZRS') ? largeFileSharesState : null + minimumTlsVersion: minimumTlsVersion + networkAcls: !empty(networkAcls) + ? union( + { + resourceAccessRules: networkAcls.?resourceAccessRules + defaultAction: networkAcls.?defaultAction ?? 'Deny' + virtualNetworkRules: networkAcls.?virtualNetworkRules + ipRules: networkAcls.?ipRules + }, + (contains(networkAcls!, 'bypass') ? { bypass: networkAcls.?bypass } : {}) // setting `bypass` to `null`is not supported + ) + : { + // New default case that enables the firewall by default + bypass: 'AzureServices' + defaultAction: 'Deny' + } + allowBlobPublicAccess: allowBlobPublicAccess + publicNetworkAccess: !empty(publicNetworkAccess) + ? any(publicNetworkAccess) + : (!empty(privateEndpoints) && empty(networkAcls) ? 'Disabled' : null) + azureFilesIdentityBasedAuthentication: !empty(azureFilesIdentityBasedAuthentication) + ? azureFilesIdentityBasedAuthentication + : null + } +} + +resource storageAccount_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: storageAccount + } +] + +resource storageAccount_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: storageAccount +} + +resource storageAccount_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(storageAccount.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: storageAccount + } +] + +module storageAccount_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.10.1' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-storageAccount-PrivateEndpoint-${index}' + scope: resourceGroup( + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[2], + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[4] + ) + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(storageAccount.id, '/'))}-${privateEndpoint.service}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(storageAccount.id, '/'))}-${privateEndpoint.service}-${index}' + properties: { + privateLinkServiceId: storageAccount.id + groupIds: [ + privateEndpoint.service + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(storageAccount.id, '/'))}-${privateEndpoint.service}-${index}' + properties: { + privateLinkServiceId: storageAccount.id + groupIds: [ + privateEndpoint.service + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] + : null + subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry + location: privateEndpoint.?location ?? reference( + split(privateEndpoint.subnetResourceId, '/subnets/')[0], + '2020-06-01', + 'Full' + ).location + lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } + } +] + +// Lifecycle Policy +module storageAccount_managementPolicies 'management-policy/main.bicep' = if (!empty(managementPolicyRules ?? [])) { + name: '${uniqueString(deployment().name, location)}-Storage-ManagementPolicies' + params: { + storageAccountName: storageAccount.name + rules: managementPolicyRules ?? [] + } + dependsOn: [ + storageAccount_blobServices // To ensure the lastAccessTimeTrackingPolicy is set first (if used in rule) + ] +} + +// SFTP user settings +module storageAccount_localUsers 'local-user/main.bicep' = [ + for (localUser, index) in (localUsers ?? []): { + name: '${uniqueString(deployment().name, location)}-Storage-LocalUsers-${index}' + params: { + storageAccountName: storageAccount.name + name: localUser.name + hasSshKey: localUser.hasSshKey + hasSshPassword: localUser.hasSshPassword + permissionScopes: localUser.permissionScopes + hasSharedKey: localUser.?hasSharedKey + homeDirectory: localUser.?homeDirectory + sshAuthorizedKeys: localUser.?sshAuthorizedKeys + } + } +] + +// Containers +module storageAccount_blobServices 'blob-service/main.bicep' = if (!empty(blobServices)) { + name: '${uniqueString(deployment().name, location)}-Storage-BlobServices' + params: { + storageAccountName: storageAccount.name + containers: blobServices.?containers + automaticSnapshotPolicyEnabled: blobServices.?automaticSnapshotPolicyEnabled + changeFeedEnabled: blobServices.?changeFeedEnabled + changeFeedRetentionInDays: blobServices.?changeFeedRetentionInDays + containerDeleteRetentionPolicyEnabled: blobServices.?containerDeleteRetentionPolicyEnabled + containerDeleteRetentionPolicyDays: blobServices.?containerDeleteRetentionPolicyDays + containerDeleteRetentionPolicyAllowPermanentDelete: blobServices.?containerDeleteRetentionPolicyAllowPermanentDelete + corsRules: blobServices.?corsRules + defaultServiceVersion: blobServices.?defaultServiceVersion + deleteRetentionPolicyAllowPermanentDelete: blobServices.?deleteRetentionPolicyAllowPermanentDelete + deleteRetentionPolicyEnabled: blobServices.?deleteRetentionPolicyEnabled + deleteRetentionPolicyDays: blobServices.?deleteRetentionPolicyDays + isVersioningEnabled: blobServices.?isVersioningEnabled + lastAccessTimeTrackingPolicyEnabled: blobServices.?lastAccessTimeTrackingPolicyEnabled + restorePolicyEnabled: blobServices.?restorePolicyEnabled + restorePolicyDays: blobServices.?restorePolicyDays + diagnosticSettings: blobServices.?diagnosticSettings + } +} + +// File Shares +module storageAccount_fileServices 'file-service/main.bicep' = if (!empty(fileServices)) { + name: '${uniqueString(deployment().name, location)}-Storage-FileServices' + params: { + storageAccountName: storageAccount.name + diagnosticSettings: fileServices.?diagnosticSettings + protocolSettings: fileServices.?protocolSettings + shareDeleteRetentionPolicy: fileServices.?shareDeleteRetentionPolicy + shares: fileServices.?shares + corsRules: queueServices.?corsRules + } +} + +// Queue +module storageAccount_queueServices 'queue-service/main.bicep' = if (!empty(queueServices)) { + name: '${uniqueString(deployment().name, location)}-Storage-QueueServices' + params: { + storageAccountName: storageAccount.name + diagnosticSettings: queueServices.?diagnosticSettings + queues: queueServices.?queues + corsRules: queueServices.?corsRules + } +} + +// Table +module storageAccount_tableServices 'table-service/main.bicep' = if (!empty(tableServices)) { + name: '${uniqueString(deployment().name, location)}-Storage-TableServices' + params: { + storageAccountName: storageAccount.name + diagnosticSettings: tableServices.?diagnosticSettings + tables: tableServices.?tables + corsRules: tableServices.?corsRules + } +} + +module secretsExport 'modules/keyVaultExport.bicep' = if (secretsExportConfiguration != null) { + name: '${uniqueString(deployment().name, location)}-secrets-kv' + scope: resourceGroup( + split((secretsExportConfiguration.?keyVaultResourceId ?? '//'), '/')[2], + split((secretsExportConfiguration.?keyVaultResourceId ?? '////'), '/')[4] + ) + params: { + keyVaultName: last(split(secretsExportConfiguration.?keyVaultResourceId ?? '//', '/')) + secretsToSet: union( + [], + contains(secretsExportConfiguration!, 'accessKey1Name') + ? [ + { + name: secretsExportConfiguration!.?accessKey1Name + value: storageAccount.listKeys().keys[0].value + } + ] + : [], + contains(secretsExportConfiguration!, 'connectionString1Name') + ? [ + { + name: secretsExportConfiguration!.?connectionString1Name + value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value};EndpointSuffix=${environment().suffixes.storage}' + } + ] + : [], + contains(secretsExportConfiguration!, 'accessKey2Name') + ? [ + { + name: secretsExportConfiguration!.?accessKey2Name + value: storageAccount.listKeys().keys[1].value + } + ] + : [], + contains(secretsExportConfiguration!, 'connectionString2Name') + ? [ + { + name: secretsExportConfiguration!.?connectionString2Name + value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[1].value};EndpointSuffix=${environment().suffixes.storage}' + } + ] + : [] + ) + } +} + +@description('The resource ID of the deployed storage account.') +output resourceId string = storageAccount.id + +@description('The name of the deployed storage account.') +output name string = storageAccount.name + +@description('The resource group of the deployed storage account.') +output resourceGroupName string = resourceGroup().name + +@description('The primary blob endpoint reference if blob services are deployed.') +output primaryBlobEndpoint string = !empty(blobServices) && contains(blobServices, 'containers') + ? reference('Microsoft.Storage/storageAccounts/${storageAccount.name}', '2019-04-01').primaryEndpoints.blob + : '' + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string? = storageAccount.?identity.?principalId + +@description('The location the resource was deployed into.') +output location string = storageAccount.location + +@description('All service endpoints of the deployed storage account, Note Standard_LRS and Standard_ZRS accounts only have a blob service endpoint.') +output serviceEndpoints object = storageAccount.properties.primaryEndpoints + +@description('The private endpoints of the Storage Account.') +output privateEndpoints privateEndpointOutputType[] = [ + for (item, index) in (privateEndpoints ?? []): { + name: storageAccount_privateEndpoints[index].outputs.name + resourceId: storageAccount_privateEndpoints[index].outputs.resourceId + groupId: storageAccount_privateEndpoints[index].outputs.?groupId! + customDnsConfigs: storageAccount_privateEndpoints[index].outputs.customDnsConfigs + networkInterfaceResourceIds: storageAccount_privateEndpoints[index].outputs.networkInterfaceResourceIds + } +] + +import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') +output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) + ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) + : {} + +// =============== // +// Definitions // +// =============== // + +@export() +type privateEndpointOutputType = { + @description('The name of the private endpoint.') + name: string + + @description('The resource ID of the private endpoint.') + resourceId: string + + @description('The group Id for the private endpoint Group.') + groupId: string? + + @description('The custom DNS configurations of the private endpoint.') + customDnsConfigs: { + @description('FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @description('A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[] + + @description('The IDs of the network interfaces associated with the private endpoint.') + networkInterfaceResourceIds: string[] +} + +@export() +type networkAclsType = { + @description('Optional. Sets the resource access rules. Array entries must consist of "tenantId" and "resourceId" fields only.') + resourceAccessRules: { + @description('Required. The ID of the tenant in which the resource resides in.') + tenantId: string + + @description('Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included.') + resourceId: string + }[]? + + @description('Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, "Logging, Metrics"), or None to bypass none of those traffics.') + bypass: ( + | 'None' + | 'AzureServices' + | 'Logging' + | 'Metrics' + | 'AzureServices, Logging' + | 'AzureServices, Metrics' + | 'AzureServices, Logging, Metrics' + | 'Logging, Metrics')? + + @description('Optional. Sets the virtual network rules.') + virtualNetworkRules: array? + + @description('Optional. Sets the IP ACL rules.') + ipRules: array? + + @description('Optional. Specifies the default action of allow or deny when no other rules match.') + defaultAction: ('Allow' | 'Deny')? +} + +@export() +type secretsExportConfigurationType = { + @description('Required. The key vault name where to store the keys and connection strings generated by the modules.') + keyVaultResourceId: string + + @description('Optional. The accessKey1 secret name to create.') + accessKey1Name: string? + + @description('Optional. The connectionString1 secret name to create.') + connectionString1Name: string? + + @description('Optional. The accessKey2 secret name to create.') + accessKey2Name: string? + + @description('Optional. The connectionString2 secret name to create.') + connectionString2Name: string? +} + +import { sshAuthorizedKeyType, permissionScopeType } from 'local-user/main.bicep' +@export() +type localUserType = { + @description('Required. The name of the local user used for SFTP Authentication.') + name: string + + @description('Optional. Indicates whether shared key exists. Set it to false to remove existing shared key.') + hasSharedKey: bool? + + @description('Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key.') + hasSshKey: bool + + @description('Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password.') + hasSshPassword: bool + + @description('Optional. The local user home directory.') + homeDirectory: string? + + @description('Required. The permission scopes of the local user.') + permissionScopes: permissionScopeType[] + + @description('Optional. The local user SSH authorized keys for SFTP.') + sshAuthorizedKeys: sshAuthorizedKeyType[]? +} diff --git a/avm/1.1.0/res/storage/storage-account/main.json b/avm/1.1.0/res/storage/storage-account/main.json new file mode 100644 index 000000000..cb5eefe1d --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/main.json @@ -0,0 +1,5657 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "383280615510920938" + }, + "name": "Storage Accounts", + "description": "This module deploys a Storage Account." + }, + "definitions": { + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey1 secret name to create." + } + }, + "connectionString1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString1 secret name to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The accessKey2 secret name to create." + } + }, + "connectionString2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The connectionString2 secret name to create." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "localUserType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS Zone Group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" + } + } + }, + "privateEndpointMultiServiceType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "local-user/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Storage Account. Must be lower-case." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], + "metadata": { + "description": "Optional. Type of Storage Account to create." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS", + "Premium_ZRS", + "Standard_GZRS", + "Standard_RAGZRS" + ], + "metadata": { + "description": "Optional. Storage Account Sku Name." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "Cold" + ], + "metadata": { + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + } + }, + "largeFileSharesState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + } + }, + "azureFilesIdentityBasedAuthentication": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Provides the identity based authentication settings for Azure Files." + } + }, + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointMultiServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "managementPolicyRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The Storage Account ManagementPolicies Rules." + } + }, + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + } + }, + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + } + }, + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + } + }, + "dnsEndpointType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." + } + }, + "blobServices": { + "type": "object", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", + "metadata": { + "description": "Optional. Blob service and containers to deploy." + } + }, + "fileServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_2", + "TLS1_3" + ], + "metadata": { + "description": "Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore." + } + }, + "enableHierarchicalNamespace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + } + }, + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "localUsers": { + "type": "array", + "items": { + "$ref": "#/definitions/localUserType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Local users to deploy for SFTP authentication." + } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables local users feature, if set to true." + } + }, + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "allowedCopyScope": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AAD", + "PrivateLink" + ], + "metadata": { + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "Storage File Data Privileged Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '69566ab7-960f-475b-8e7c-b3118f30c6bd')]", + "Storage File Data Privileged Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b8eda974-7b85-4f76-af95-65846b26df6d')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-05-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", + "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", + "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", + "customDomain": { + "name": "[parameters('customDomainName')]", + "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" + }, + "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", + "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", + "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(tryGet(parameters('customerManagedKey'), 'keyVersion'))), parameters('customerManagedKey').keyVersion, if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), null(), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", + "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", + "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", + "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", + "isHnsEnabled": "[parameters('enableHierarchicalNamespace')]", + "isSftpEnabled": "[parameters('enableSftp')]", + "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", + "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", + "minimumTlsVersion": "[parameters('minimumTlsVersion')]", + "networkAcls": "[if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", + "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" + }, + "dependsOn": [ + "cMKKeyVault::cMKKey", + "cMKKeyVault" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_roleAssignments": { + "copy": { + "name": "storageAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_privateEndpoints": { + "copy": { + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-storageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "15954548978129725136" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.10.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "5440815542537978381" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_managementPolicies": { + "condition": "[not(empty(coalesce(parameters('managementPolicyRules'), createArray())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "rules": { + "value": "[coalesce(parameters('managementPolicyRules'), createArray())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "4967204006599351003" + }, + "name": "Storage Account Management Policies", + "description": "This module deploys a Storage Account Management Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "rules": { + "type": "array", + "metadata": { + "description": "Required. The Storage Account ManagementPolicies Rules." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/managementPolicies", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "properties": { + "policy": { + "rules": "[parameters('rules')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed management policy." + }, + "value": "default" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed management policy." + }, + "value": "default" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed management policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount", + "storageAccount_blobServices" + ] + }, + "storageAccount_localUsers": { + "copy": { + "name": "storageAccount_localUsers", + "count": "[length(coalesce(parameters('localUsers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].name]" + }, + "hasSshKey": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshKey]" + }, + "hasSshPassword": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].hasSshPassword]" + }, + "permissionScopes": { + "value": "[coalesce(parameters('localUsers'), createArray())[copyIndex()].permissionScopes]" + }, + "hasSharedKey": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'hasSharedKey')]" + }, + "homeDirectory": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'homeDirectory')]" + }, + "sshAuthorizedKeys": { + "value": "[tryGet(coalesce(parameters('localUsers'), createArray())[copyIndex()], 'sshAuthorizedKeys')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "2528560857012083896" + }, + "name": "Storage Account Local Users", + "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication." + }, + "definitions": { + "sshAuthorizedKeyType": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "securestring", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "permissionScopeType": { + "type": "object", + "properties": { + "permissions": { + "type": "string", + "metadata": { + "description": "Required. The permissions for the local user. Possible values include: Read (r), Write (w), Delete (d), List (l), and Create (c)." + } + }, + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. The name of resource, normally the container name or the file share name, used by the local user." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service used by the local user, e.g. blob, file." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "items": { + "$ref": "#/definitions/permissionScopeType" + }, + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/sshAuthorizedKeyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "localUsers": { + "type": "Microsoft.Storage/storageAccounts/localUsers", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "hasSharedKey": "[parameters('hasSharedKey')]", + "hasSshKey": "[parameters('hasSshKey')]", + "hasSshPassword": "[parameters('hasSshPassword')]", + "homeDirectory": "[parameters('homeDirectory')]", + "permissionScopes": "[parameters('permissionScopes')]", + "sshAuthorizedKeys": "[parameters('sshAuthorizedKeys')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed local user." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed local user." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed local user." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_blobServices": { + "condition": "[not(empty(parameters('blobServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(parameters('blobServices'), 'containers')]" + }, + "automaticSnapshotPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" + }, + "changeFeedEnabled": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" + }, + "changeFeedRetentionInDays": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" + }, + "containerDeleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" + }, + "containerDeleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" + }, + "corsRules": { + "value": "[tryGet(parameters('blobServices'), 'corsRules')]" + }, + "defaultServiceVersion": { + "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" + }, + "deleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" + }, + "deleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" + }, + "isVersioningEnabled": { + "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" + }, + "lastAccessTimeTrackingPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" + }, + "restorePolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" + }, + "restorePolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "13802891409950802048" + }, + "name": "Storage Account blob Services", + "description": "This module deploys a Storage Account Blob Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "defaultServiceVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('storageAccountName')]" + }, + "blobServices": { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", + "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", + "containerDeleteRetentionPolicy": { + "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", + "days": "[parameters('containerDeleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" + }, + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "defaultServiceVersion": "[if(not(empty(parameters('defaultServiceVersion'))), parameters('defaultServiceVersion'), null())]", + "deleteRetentionPolicy": { + "enabled": "[parameters('deleteRetentionPolicyEnabled')]", + "days": "[parameters('deleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" + }, + "isVersioningEnabled": "[parameters('isVersioningEnabled')]", + "lastAccessTimeTrackingPolicy": "[if(not(equals(reference('storageAccount', '2022-09-01', 'full').kind, 'Storage')), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", + "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "blobServices_diagnosticSettings": { + "copy": { + "name": "blobServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "blobServices" + ] + }, + "blobServices_container": { + "copy": { + "name": "blobServices_container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "blobServiceName": { + "value": "[variables('name')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "defaultEncryptionScope": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" + }, + "denyEncryptionScopeOverride": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" + }, + "enableNfsV3AllSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" + }, + "enableNfsV3RootSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" + }, + "immutableStorageWithVersioningEnabled": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" + }, + "publicAccess": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "immutabilityPolicyProperties": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicyProperties')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "15727824641798999553" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "blobServiceName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicyName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. Name of the immutable policy." + } + }, + "immutabilityPolicyProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. A name-value pair to associate with the container as metadata." + } + }, + "publicAccess": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Container", + "Blob", + "None" + ], + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::blobServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('storageAccountName')]" + }, + "container": { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", + "denyEncryptionScopeOverride": "[parameters('denyEncryptionScopeOverride')]", + "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", + "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", + "immutableStorageWithVersioning": "[if(equals(parameters('immutableStorageWithVersioningEnabled'), true()), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", + "metadata": "[parameters('metadata')]", + "publicAccess": "[parameters('publicAccess')]" + } + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "container" + ] + }, + "immutabilityPolicy": { + "condition": "[not(empty(coalesce(parameters('immutabilityPolicyProperties'), createObject())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[parameters('immutabilityPolicyName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "containerName": { + "value": "[parameters('name')]" + }, + "immutabilityPeriodSinceCreationInDays": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'immutabilityPeriodSinceCreationInDays')]" + }, + "allowProtectedAppendWrites": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'allowProtectedAppendWrites')]" + }, + "allowProtectedAppendWritesAll": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'allowProtectedAppendWritesAll')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "2769922037435749045" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + } + }, + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "properties": { + "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", + "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", + "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed immutability policy." + }, + "value": "default" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed immutability policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed immutability policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "container" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed container." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "blobServices" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed blob service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + }, + "corsRules": { + "value": "[tryGet(parameters('queueServices'), 'corsRules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "987643333058038389" + }, + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Protocol settings for file service." + } + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "defaultValue": { + "enabled": true, + "days": 7 + }, + "metadata": { + "description": "Optional. The service properties for soft delete." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]", + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + } + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "15193761941438215308" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "TransactionOptimized", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" + } + }, + "fileShare_roleAssignments": { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "scope": { + "value": "[replace(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), '/shares/', '/fileshares/')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]" + }, + "roleDefinitionId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]" + }, + "principalId": { + "value": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "condition": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), createObject('value', coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0')), createObject('value', null()))]", + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "description": { + "value": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[parameters('scope')]", + "name": "[parameters('name')]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "principalId": "[parameters('principalId')]", + "description": "[parameters('description')]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "fileServices", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_queueServices": { + "condition": "[not(empty(parameters('queueServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" + }, + "queues": { + "value": "[tryGet(parameters('queueServices'), 'queues')]" + }, + "corsRules": { + "value": "[tryGet(parameters('queueServices'), 'corsRules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "8158577333548255612" + }, + "name": "Storage Account Queue Services", + "description": "This module deploys a Storage Account Queue Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "queues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Queues to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "queueServices": { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + } + }, + "queueServices_diagnosticSettings": { + "copy": { + "name": "queueServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/queueServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "queueServices" + ] + }, + "queueServices_queues": { + "copy": { + "name": "queueServices_queues", + "count": "[length(coalesce(parameters('queues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "name": { + "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "9877120144610775153" + }, + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage queue to deploy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. A name-value pair that represents queue metadata." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::queueServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "queue": { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]" + } + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/queueServices/{1}/queues/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "queue" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue." + }, + "value": "[resourceGroup().name]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_tableServices": { + "condition": "[not(empty(parameters('tableServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" + }, + "tables": { + "value": "[tryGet(parameters('tableServices'), 'tables')]" + }, + "corsRules": { + "value": "[tryGet(parameters('tableServices'), 'corsRules')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "541986423744885003" + }, + "name": "Storage Account Table Services", + "description": "This module deploys a Storage Account Table Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. tables to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "tableServices": { + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + } + }, + "tableServices_diagnosticSettings": { + "copy": { + "name": "tableServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/tableServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "tableServices" + ] + }, + "tableServices_tables": { + "copy": { + "name": "tableServices_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('tables')[copyIndex()].name]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "11234204519679347949" + }, + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::tableServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "table": { + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/tableServices/{1}/tables/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '////'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '//'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2023-05-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString1Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2023-05-01').keys[0].value, environment().suffixes.storage))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2023-05-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'connectionString2Name'), 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('name'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2023-05-01').keys[1].value, environment().suffixes.storage))), createArray()))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "14510275109257916717" + } + }, + "definitions": { + "secretSetOutputType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed storage account." + }, + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('storageAccount', '2023-05-01', 'full'), 'identity'), 'principalId')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2023-05-01', 'full').location]" + }, + "serviceEndpoints": { + "type": "object", + "metadata": { + "description": "All service endpoints of the deployed storage account, Note Standard_LRS and Standard_ZRS accounts only have a blob service endpoint." + }, + "value": "[reference('storageAccount').primaryEndpoints]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the Storage Account." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('storageAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/storage/storage-account/management-policy/README.md b/avm/1.1.0/res/storage/storage-account/management-policy/README.md new file mode 100644 index 000000000..b96a10ac6 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/management-policy/README.md @@ -0,0 +1,51 @@ +# Storage Account Management Policies `[Microsoft.Storage/storageAccounts/managementPolicies]` + +This module deploys a Storage Account Management Policy. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Storage/storageAccounts/managementPolicies` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/managementPolicies) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`rules`](#parameter-rules) | array | The Storage Account ManagementPolicies Rules. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageAccountName`](#parameter-storageaccountname) | string | The name of the parent Storage Account. Required if the template is used in a standalone deployment. | + +### Parameter: `rules` + +The Storage Account ManagementPolicies Rules. + +- Required: Yes +- Type: array + +### Parameter: `storageAccountName` + +The name of the parent Storage Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed management policy. | +| `resourceGroupName` | string | The resource group of the deployed management policy. | +| `resourceId` | string | The resource ID of the deployed management policy. | diff --git a/avm/1.1.0/res/storage/storage-account/management-policy/main.bicep b/avm/1.1.0/res/storage/storage-account/management-policy/main.bicep new file mode 100644 index 000000000..705a6a5d9 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/management-policy/main.bicep @@ -0,0 +1,33 @@ +metadata name = 'Storage Account Management Policies' +metadata description = 'This module deploys a Storage Account Management Policy.' + +@maxLength(24) +@description('Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment.') +param storageAccountName string + +@description('Required. The Storage Account ManagementPolicies Rules.') +param rules array + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = { + name: storageAccountName +} + +// lifecycle policy +resource managementPolicy 'Microsoft.Storage/storageAccounts/managementPolicies@2023-01-01' = { + name: 'default' + parent: storageAccount + properties: { + policy: { + rules: rules + } + } +} + +@description('The resource ID of the deployed management policy.') +output resourceId string = managementPolicy.name + +@description('The name of the deployed management policy.') +output name string = managementPolicy.name + +@description('The resource group of the deployed management policy.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/storage/storage-account/management-policy/main.json b/avm/1.1.0/res/storage/storage-account/management-policy/main.json new file mode 100644 index 000000000..55ab734bb --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/management-policy/main.json @@ -0,0 +1,63 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "4967204006599351003" + }, + "name": "Storage Account Management Policies", + "description": "This module deploys a Storage Account Management Policy." + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "rules": { + "type": "array", + "metadata": { + "description": "Required. The Storage Account ManagementPolicies Rules." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/managementPolicies", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "properties": { + "policy": { + "rules": "[parameters('rules')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed management policy." + }, + "value": "default" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed management policy." + }, + "value": "default" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed management policy." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/storage/storage-account/modules/keyVaultExport.bicep b/avm/1.1.0/res/storage/storage-account/modules/keyVaultExport.bicep new file mode 100644 index 000000000..ade17063c --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/modules/keyVaultExport.bicep @@ -0,0 +1,42 @@ +// ============== // +// Parameters // +// ============== // + +@description('Required. The name of the Key Vault to set the ecrets in.') +param keyVaultName string + +import { secretToSetType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Required. The secrets to set in the Key Vault.') +param secretsToSet secretToSetType[] + +// ============= // +// Resources // +// ============= // + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +resource secrets 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = [ + for secret in secretsToSet: { + name: secret.name + parent: keyVault + properties: { + value: secret.value + } + } +] + +// =========== // +// Outputs // +// =========== // +import { secretSetOutputType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('The references to the secrets exported to the provided Key Vault.') +output secretsSet secretSetOutputType[] = [ + #disable-next-line outputs-should-not-contain-secrets // Only returning the references, not a secret value + for index in range(0, length(secretsToSet ?? [])): { + secretResourceId: secrets[index].id + secretUri: secrets[index].properties.secretUri + secretUriWithVersion: secrets[index].properties.secretUriWithVersion + } +] diff --git a/avm/1.1.0/res/storage/storage-account/queue-service/README.md b/avm/1.1.0/res/storage/storage-account/queue-service/README.md new file mode 100644 index 000000000..2616087b7 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/queue-service/README.md @@ -0,0 +1,278 @@ +# Storage Account Queue Services `[Microsoft.Storage/storageAccounts/queueServices]` + +This module deploys a Storage Account Queue Service. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices) | +| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices/queues) | + +## Parameters + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageAccountName`](#parameter-storageaccountname) | string | The name of the parent Storage Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`corsRules`](#parameter-corsrules) | array | The List of CORS rules. You can include up to five CorsRule elements in the request. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`queues`](#parameter-queues) | array | Queues to create. | + +### Parameter: `storageAccountName` + +The name of the parent Storage Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `corsRules` + +The List of CORS rules. You can include up to five CorsRule elements in the request. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowedHeaders`](#parameter-corsrulesallowedheaders) | array | A list of headers allowed to be part of the cross-origin request. | +| [`allowedMethods`](#parameter-corsrulesallowedmethods) | array | A list of HTTP methods that are allowed to be executed by the origin. | +| [`allowedOrigins`](#parameter-corsrulesallowedorigins) | array | A list of origin domains that will be allowed via CORS, or "*" to allow all domains. | +| [`exposedHeaders`](#parameter-corsrulesexposedheaders) | array | A list of response headers to expose to CORS clients. | +| [`maxAgeInSeconds`](#parameter-corsrulesmaxageinseconds) | int | The number of seconds that the client/browser should cache a preflight response. | + +### Parameter: `corsRules.allowedHeaders` + +A list of headers allowed to be part of the cross-origin request. + +- Required: Yes +- Type: array + +### Parameter: `corsRules.allowedMethods` + +A list of HTTP methods that are allowed to be executed by the origin. + +- Required: Yes +- Type: array +- Allowed: + ```Bicep + [ + 'CONNECT' + 'DELETE' + 'GET' + 'HEAD' + 'MERGE' + 'OPTIONS' + 'PATCH' + 'POST' + 'PUT' + 'TRACE' + ] + ``` + +### Parameter: `corsRules.allowedOrigins` + +A list of origin domains that will be allowed via CORS, or "*" to allow all domains. + +- Required: Yes +- Type: array + +### Parameter: `corsRules.exposedHeaders` + +A list of response headers to expose to CORS clients. + +- Required: Yes +- Type: array + +### Parameter: `corsRules.maxAgeInSeconds` + +The number of seconds that the client/browser should cache a preflight response. + +- Required: Yes +- Type: int + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of the diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of the diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `queues` + +Queues to create. + +- Required: No +- Type: array + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed file share service. | +| `resourceGroupName` | string | The resource group of the deployed file share service. | +| `resourceId` | string | The resource ID of the deployed file share service. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | diff --git a/avm/1.1.0/res/storage/storage-account/queue-service/main.bicep b/avm/1.1.0/res/storage/storage-account/queue-service/main.bicep new file mode 100644 index 000000000..a43e2747e --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/queue-service/main.bicep @@ -0,0 +1,108 @@ +metadata name = 'Storage Account Queue Services' +metadata description = 'This module deploys a Storage Account Queue Service.' + +@maxLength(24) +@description('Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment.') +param storageAccountName string + +@description('Optional. Queues to create.') +param queues array? + +@description('Optional. The List of CORS rules. You can include up to five CorsRule elements in the request.') +param corsRules corsRuleType[]? + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +// The name of the blob services +var name = 'default' + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' existing = { + name: storageAccountName +} + +resource queueServices 'Microsoft.Storage/storageAccounts/queueServices@2023-04-01' = { + name: name + parent: storageAccount + properties: { + cors: corsRules != null + ? { + corsRules: corsRules + } + : null + } +} + +resource queueServices_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: queueServices + } +] + +module queueServices_queues 'queue/main.bicep' = [ + for (queue, index) in (queues ?? []): { + name: '${deployment().name}-Queue-${index}' + params: { + storageAccountName: storageAccount.name + name: queue.name + metadata: queue.?metadata + roleAssignments: queue.?roleAssignments + } + } +] + +@description('The name of the deployed file share service.') +output name string = queueServices.name + +@description('The resource ID of the deployed file share service.') +output resourceId string = queueServices.id + +@description('The resource group of the deployed file share service.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +@export() +@description('The type for a cors rule.') +type corsRuleType = { + @description('Required. A list of headers allowed to be part of the cross-origin request.') + allowedHeaders: string[] + + @description('Required. A list of HTTP methods that are allowed to be executed by the origin.') + allowedMethods: ('CONNECT' | 'DELETE' | 'GET' | 'HEAD' | 'MERGE' | 'OPTIONS' | 'PATCH' | 'POST' | 'PUT' | 'TRACE')[] + + @description('Required. A list of origin domains that will be allowed via CORS, or "*" to allow all domains.') + allowedOrigins: string[] + + @description('Required. A list of response headers to expose to CORS clients.') + exposedHeaders: string[] + + @description('Required. The number of seconds that the client/browser should cache a preflight response.') + maxAgeInSeconds: int +} diff --git a/avm/1.1.0/res/storage/storage-account/queue-service/main.json b/avm/1.1.0/res/storage/storage-account/queue-service/main.json new file mode 100644 index 000000000..994d11d29 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/queue-service/main.json @@ -0,0 +1,560 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "8158577333548255612" + }, + "name": "Storage Account Queue Services", + "description": "This module deploys a Storage Account Queue Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "queues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Queues to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "queueServices": { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + } + }, + "queueServices_diagnosticSettings": { + "copy": { + "name": "queueServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/queueServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "queueServices" + ] + }, + "queueServices_queues": { + "copy": { + "name": "queueServices_queues", + "count": "[length(coalesce(parameters('queues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "name": { + "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "9877120144610775153" + }, + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage queue to deploy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. A name-value pair that represents queue metadata." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::queueServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "queue": { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]" + } + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/queueServices/{1}/queues/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "queue" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue." + }, + "value": "[resourceGroup().name]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/storage/storage-account/queue-service/queue/README.md b/avm/1.1.0/res/storage/storage-account/queue-service/queue/README.md new file mode 100644 index 000000000..6ed02e1f9 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/queue-service/queue/README.md @@ -0,0 +1,187 @@ +# Storage Account Queues `[Microsoft.Storage/storageAccounts/queueServices/queues]` + +This module deploys a Storage Account Queue. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices/queues) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the storage queue to deploy. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageAccountName`](#parameter-storageaccountname) | string | The name of the parent Storage Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`metadata`](#parameter-metadata) | object | A name-value pair that represents queue metadata. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | + +### Parameter: `name` + +The name of the storage queue to deploy. + +- Required: Yes +- Type: string + +### Parameter: `storageAccountName` + +The name of the parent Storage Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `metadata` + +A name-value pair that represents queue metadata. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reader and Data Access'` + - `'Role Based Access Control Administrator'` + - `'Storage Account Backup Contributor'` + - `'Storage Account Contributor'` + - `'Storage Account Key Operator Service Role'` + - `'Storage Queue Data Contributor'` + - `'Storage Queue Data Message Processor'` + - `'Storage Queue Data Message Sender'` + - `'Storage Queue Data Reader'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed queue. | +| `resourceGroupName` | string | The resource group of the deployed queue. | +| `resourceId` | string | The resource ID of the deployed queue. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | diff --git a/avm/1.1.0/res/storage/storage-account/queue-service/queue/main.bicep b/avm/1.1.0/res/storage/storage-account/queue-service/queue/main.bicep new file mode 100644 index 000000000..cb5def669 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/queue-service/queue/main.bicep @@ -0,0 +1,114 @@ +metadata name = 'Storage Account Queues' +metadata description = 'This module deploys a Storage Account Queue.' + +@maxLength(24) +@description('Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment.') +param storageAccountName string + +@description('Required. The name of the storage queue to deploy.') +param name string + +@description('Optional. A name-value pair that represents queue metadata.') +param metadata object = {} + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Reader and Data Access': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'c12c1c16-33a1-487b-954d-41c89c60f349' + ) + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'Storage Account Backup Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1' + ) + 'Storage Account Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '17d1049b-9a84-46fb-8f53-869881c3d3ab' + ) + 'Storage Account Key Operator Service Role': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '81a9662b-bebf-436f-a333-f67b29880f12' + ) + 'Storage Queue Data Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '974c5e8b-45b9-4653-ba55-5f855dd0fb88' + ) + 'Storage Queue Data Message Processor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '8a0f0c08-91a1-4084-bc3d-661d67233fed' + ) + 'Storage Queue Data Message Sender': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a' + ) + 'Storage Queue Data Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '19e7f393-937e-4f77-808e-94535e297925' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' existing = { + name: storageAccountName + + resource queueServices 'queueServices@2023-04-01' existing = { + name: 'default' + } +} + +resource queue 'Microsoft.Storage/storageAccounts/queueServices/queues@2023-04-01' = { + name: name + parent: storageAccount::queueServices + properties: { + metadata: metadata + } +} + +resource queue_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(queue.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: queue + } +] + +@description('The name of the deployed queue.') +output name string = queue.name + +@description('The resource ID of the deployed queue.') +output resourceId string = queue.id + +@description('The resource group of the deployed queue.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/storage/storage-account/queue-service/queue/main.json b/avm/1.1.0/res/storage/storage-account/queue-service/queue/main.json new file mode 100644 index 000000000..a5175e522 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/queue-service/queue/main.json @@ -0,0 +1,214 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "9877120144610775153" + }, + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage queue to deploy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. A name-value pair that represents queue metadata." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::queueServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "queue": { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]" + } + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/queueServices/{1}/queues/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "queue" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/storage/storage-account/table-service/README.md b/avm/1.1.0/res/storage/storage-account/table-service/README.md new file mode 100644 index 000000000..68db257c3 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/table-service/README.md @@ -0,0 +1,279 @@ +# Storage Account Table Services `[Microsoft.Storage/storageAccounts/tableServices]` + +This module deploys a Storage Account Table Service. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices) | +| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices/tables) | + +## Parameters + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageAccountName`](#parameter-storageaccountname) | string | The name of the parent Storage Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`corsRules`](#parameter-corsrules) | array | The List of CORS rules. You can include up to five CorsRule elements in the request. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`tables`](#parameter-tables) | array | tables to create. | + +### Parameter: `storageAccountName` + +The name of the parent Storage Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `corsRules` + +The List of CORS rules. You can include up to five CorsRule elements in the request. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowedHeaders`](#parameter-corsrulesallowedheaders) | array | A list of headers allowed to be part of the cross-origin request. | +| [`allowedMethods`](#parameter-corsrulesallowedmethods) | array | A list of HTTP methods that are allowed to be executed by the origin. | +| [`allowedOrigins`](#parameter-corsrulesallowedorigins) | array | A list of origin domains that will be allowed via CORS, or "*" to allow all domains. | +| [`exposedHeaders`](#parameter-corsrulesexposedheaders) | array | A list of response headers to expose to CORS clients. | +| [`maxAgeInSeconds`](#parameter-corsrulesmaxageinseconds) | int | The number of seconds that the client/browser should cache a preflight response. | + +### Parameter: `corsRules.allowedHeaders` + +A list of headers allowed to be part of the cross-origin request. + +- Required: Yes +- Type: array + +### Parameter: `corsRules.allowedMethods` + +A list of HTTP methods that are allowed to be executed by the origin. + +- Required: Yes +- Type: array +- Allowed: + ```Bicep + [ + 'CONNECT' + 'DELETE' + 'GET' + 'HEAD' + 'MERGE' + 'OPTIONS' + 'PATCH' + 'POST' + 'PUT' + 'TRACE' + ] + ``` + +### Parameter: `corsRules.allowedOrigins` + +A list of origin domains that will be allowed via CORS, or "*" to allow all domains. + +- Required: Yes +- Type: array + +### Parameter: `corsRules.exposedHeaders` + +A list of response headers to expose to CORS clients. + +- Required: Yes +- Type: array + +### Parameter: `corsRules.maxAgeInSeconds` + +The number of seconds that the client/browser should cache a preflight response. + +- Required: Yes +- Type: int + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of the diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of the diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `tables` + +tables to create. + +- Required: No +- Type: array +- Default: `[]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed table service. | +| `resourceGroupName` | string | The resource group of the deployed table service. | +| `resourceId` | string | The resource ID of the deployed table service. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | diff --git a/avm/1.1.0/res/storage/storage-account/table-service/main.bicep b/avm/1.1.0/res/storage/storage-account/table-service/main.bicep new file mode 100644 index 000000000..de90d0596 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/table-service/main.bicep @@ -0,0 +1,107 @@ +metadata name = 'Storage Account Table Services' +metadata description = 'This module deploys a Storage Account Table Service.' + +@maxLength(24) +@description('Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment.') +param storageAccountName string + +@description('Optional. tables to create.') +param tables array = [] + +@description('Optional. The List of CORS rules. You can include up to five CorsRule elements in the request.') +param corsRules corsRuleType[]? + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +// The name of the table service +var name = 'default' + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' existing = { + name: storageAccountName +} + +resource tableServices 'Microsoft.Storage/storageAccounts/tableServices@2023-04-01' = { + name: name + parent: storageAccount + properties: { + cors: corsRules != null + ? { + corsRules: corsRules + } + : null + } +} + +resource tableServices_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: tableServices + } +] + +module tableServices_tables 'table/main.bicep' = [ + for (table, index) in tables: { + name: '${deployment().name}-Table-${index}' + params: { + name: table.name + storageAccountName: storageAccount.name + roleAssignments: table.?roleAssignments + } + } +] + +@description('The name of the deployed table service.') +output name string = tableServices.name + +@description('The resource ID of the deployed table service.') +output resourceId string = tableServices.id + +@description('The resource group of the deployed table service.') +output resourceGroupName string = resourceGroup().name + +// =============== // +// Definitions // +// =============== // + +@export() +@description('The type for a cors rule.') +type corsRuleType = { + @description('Required. A list of headers allowed to be part of the cross-origin request.') + allowedHeaders: string[] + + @description('Required. A list of HTTP methods that are allowed to be executed by the origin.') + allowedMethods: ('CONNECT' | 'DELETE' | 'GET' | 'HEAD' | 'MERGE' | 'OPTIONS' | 'PATCH' | 'POST' | 'PUT' | 'TRACE')[] + + @description('Required. A list of origin domains that will be allowed via CORS, or "*" to allow all domains.') + allowedOrigins: string[] + + @description('Required. A list of response headers to expose to CORS clients.') + exposedHeaders: string[] + + @description('Required. The number of seconds that the client/browser should cache a preflight response.') + maxAgeInSeconds: int +} diff --git a/avm/1.1.0/res/storage/storage-account/table-service/main.json b/avm/1.1.0/res/storage/storage-account/table-service/main.json new file mode 100644 index 000000000..c51678429 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/table-service/main.json @@ -0,0 +1,545 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "541986423744885003" + }, + "name": "Storage Account Table Services", + "description": "This module deploys a Storage Account Table Service." + }, + "definitions": { + "corsRuleType": { + "type": "object", + "properties": { + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of headers allowed to be part of the cross-origin request." + } + }, + "allowedMethods": { + "type": "array", + "allowedValues": [ + "CONNECT", + "DELETE", + "GET", + "HEAD", + "MERGE", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "TRACE" + ], + "metadata": { + "description": "Required. A list of HTTP methods that are allowed to be executed by the origin." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of origin domains that will be allowed via CORS, or \"*\" to allow all domains." + } + }, + "exposedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of response headers to expose to CORS clients." + } + }, + "maxAgeInSeconds": { + "type": "int", + "metadata": { + "description": "Required. The number of seconds that the client/browser should cache a preflight response." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a cors rule." + } + }, + "diagnosticSettingFullType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if both logs & metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. tables to create." + } + }, + "corsRules": { + "type": "array", + "items": { + "$ref": "#/definitions/corsRuleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The List of CORS rules. You can include up to five CorsRule elements in the request." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingFullType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "tableServices": { + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "cors": "[if(not(equals(parameters('corsRules'), null())), createObject('corsRules', parameters('corsRules')), null())]" + } + }, + "tableServices_diagnosticSettings": { + "copy": { + "name": "tableServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/tableServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "tableServices" + ] + }, + "tableServices_tables": { + "copy": { + "name": "tableServices_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('tables')[copyIndex()].name]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "11234204519679347949" + }, + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::tableServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "table": { + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/tableServices/{1}/tables/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table service." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/storage/storage-account/table-service/table/README.md b/avm/1.1.0/res/storage/storage-account/table-service/table/README.md new file mode 100644 index 000000000..4e97ea70f --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/table-service/table/README.md @@ -0,0 +1,176 @@ +# Storage Account Table `[Microsoft.Storage/storageAccounts/tableServices/tables]` + +This module deploys a Storage Account Table. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices/tables) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the table. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageAccountName`](#parameter-storageaccountname) | string | The name of the parent Storage Account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | + +### Parameter: `name` + +Name of the table. + +- Required: Yes +- Type: string + +### Parameter: `storageAccountName` + +The name of the parent Storage Account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reader and Data Access'` + - `'Role Based Access Control Administrator'` + - `'Storage Account Backup Contributor'` + - `'Storage Account Contributor'` + - `'Storage Account Key Operator Service Role'` + - `'Storage Table Data Contributor'` + - `'Storage Table Data Reader'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed file share service. | +| `resourceGroupName` | string | The resource group of the deployed file share service. | +| `resourceId` | string | The resource ID of the deployed file share service. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | diff --git a/avm/1.1.0/res/storage/storage-account/table-service/table/main.bicep b/avm/1.1.0/res/storage/storage-account/table-service/table/main.bicep new file mode 100644 index 000000000..3f15a1bf2 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/table-service/table/main.bicep @@ -0,0 +1,100 @@ +metadata name = 'Storage Account Table' +metadata description = 'This module deploys a Storage Account Table.' + +@maxLength(24) +@description('Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment.') +param storageAccountName string + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Required. Name of the table.') +param name string + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Reader and Data Access': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'c12c1c16-33a1-487b-954d-41c89c60f349' + ) + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'Storage Account Backup Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1' + ) + 'Storage Account Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '17d1049b-9a84-46fb-8f53-869881c3d3ab' + ) + 'Storage Account Key Operator Service Role': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '81a9662b-bebf-436f-a333-f67b29880f12' + ) + 'Storage Table Data Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3' + ) + 'Storage Table Data Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '76199698-9eea-4c19-bc75-cec21354c6b6' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' existing = { + name: storageAccountName + + resource tableServices 'tableServices@2023-04-01' existing = { + name: 'default' + } +} + +resource table 'Microsoft.Storage/storageAccounts/tableServices/tables@2023-04-01' = { + name: name + parent: storageAccount::tableServices +} + +resource table_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(table.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: table + } +] + +@description('The name of the deployed file share service.') +output name string = table.name + +@description('The resource ID of the deployed file share service.') +output resourceId string = table.id + +@description('The resource group of the deployed file share service.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/1.1.0/res/storage/storage-account/table-service/table/main.json b/avm/1.1.0/res/storage/storage-account/table-service/table/main.json new file mode 100644 index 000000000..f4ea8be69 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/table-service/table/main.json @@ -0,0 +1,202 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "11234204519679347949" + }, + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table." + }, + "definitions": { + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::tableServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "table": { + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/tableServices/{1}/tables/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/blob/main.test.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/blob/main.test.bicep new file mode 100644 index 000000000..f0f1dcc6b --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/blob/main.test.bicep @@ -0,0 +1,50 @@ +targetScope = 'subscription' + +metadata name = 'Deploying as a Blob Storage' +metadata description = 'This instance deploys the module as a Blob Storage account.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-storage.storageaccounts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssablob' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + skuName: 'Standard_LRS' + kind: 'BlobStorage' + } + } +] diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/block/main.test.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/block/main.test.bicep new file mode 100644 index 000000000..239eac756 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/block/main.test.bicep @@ -0,0 +1,50 @@ +targetScope = 'subscription' + +metadata name = 'Deploying as a Block Blob Storage' +metadata description = 'This instance deploys the module as a Premium Block Blob Storage account.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-storage.storageaccounts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssablock' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + skuName: 'Premium_LRS' + kind: 'BlockBlobStorage' + } + } +] diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/changefeed/main.test.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/changefeed/main.test.bicep new file mode 100644 index 000000000..d4ab99d73 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/changefeed/main.test.bicep @@ -0,0 +1,52 @@ +targetScope = 'subscription' + +metadata name = 'Using only changefeed configuration' +metadata description = 'This instance deploys the module with the minimum set of required parameters for the changefeed configuration.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-storage.storageaccounts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssachf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + allowBlobPublicAccess: false + location: resourceLocation + blobServices: { + changeFeedEnabled: true + } + } + } +] diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..c6de9c25b --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,53 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-storage.storageaccounts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssamin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + allowBlobPublicAccess: false + location: resourceLocation + networkAcls: { + defaultAction: 'Deny' + bypass: 'AzureServices' + } + } + } +] diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/kvSecrets/dependencies.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/kvSecrets/dependencies.bicep new file mode 100644 index 000000000..61c051d86 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/kvSecrets/dependencies.bicep @@ -0,0 +1,21 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param keyVaultName string + +resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + enableRbacAuthorization: true + tenantId: subscription().tenantId + } +} + +@description('The name of the Key Vault created.') +output keyVaultResourceId string = keyVault.id diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/kvSecrets/main.test.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/kvSecrets/main.test.bicep new file mode 100644 index 000000000..ea5474d1d --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/kvSecrets/main.test.bicep @@ -0,0 +1,58 @@ +targetScope = 'subscription' + +metadata name = 'Deploying with a key vault reference to save secrets' +metadata description = 'This instance deploys the module saving all its secrets in a key vault.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-storage.storageaccount-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssakvs' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============== // +// General resources +// ============== // +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + location: resourceLocation + name: '${namePrefix}kvref' + secretsExportConfiguration: { + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + accessKey1Name: 'custom-key1-name' + accessKey2Name: 'custom-key2-name' + connectionString1Name: 'custom-connectionString1-name' + connectionString2Name: 'custom-connectionString2-name' + } + } +} diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..2accc238d --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/max/dependencies.bicep @@ -0,0 +1,99 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 0) + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + ] + } + } + { + name: 'custom-private-subnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 1) + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + ] + } + } + { + name: 'custom-private-subnet-2' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 2) + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + ] + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.blob.${environment().suffixes.storage}' + location: 'global' + dependsOn: [ + virtualNetwork + ] + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network Default Subnet.') +output defaultSubnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the 2nd created Virtual Network Subnet.') +output customSubnet1ResourceId string = virtualNetwork.properties.subnets[1].id + +@description('The resource ID of the 3rd created Virtual Network Subnet.') +output customSubnet2ResourceId string = virtualNetwork.properties.subnets[2].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..6215b8907 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/max/main.test.bicep @@ -0,0 +1,599 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-storage.storageaccounts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssamax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + skuName: 'Standard_LRS' + allowBlobPublicAccess: false + requireInfrastructureEncryption: true + largeFileSharesState: 'Enabled' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + enableHierarchicalNamespace: true + enableSftp: true + enableNfsV3: true + privateEndpoints: [ + { + service: 'blob' + subnetResourceId: nestedDependencies.outputs.customSubnet1ResourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + { + service: 'blob' + subnetResourceId: nestedDependencies.outputs.customSubnet2ResourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + subnetResourceId: nestedDependencies.outputs.customSubnet1ResourceId + service: 'table' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + subnetResourceId: nestedDependencies.outputs.customSubnet1ResourceId + service: 'queue' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + subnetResourceId: nestedDependencies.outputs.customSubnet1ResourceId + service: 'file' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + subnetResourceId: nestedDependencies.outputs.customSubnet1ResourceId + service: 'web' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + subnetResourceId: nestedDependencies.outputs.customSubnet1ResourceId + service: 'dfs' + } + ] + networkAcls: { + resourceAccessRules: [ + { + tenantId: subscription().tenantId + resourceId: '/subscriptions/${subscription().subscriptionId}/resourceGroups/*/providers/Microsoft.ContainerRegistry/registries/*' + } + ] + bypass: 'AzureServices' + defaultAction: 'Deny' + virtualNetworkRules: [ + { + action: 'Allow' + id: nestedDependencies.outputs.defaultSubnetResourceId + } + ] + ipRules: [ + { + action: 'Allow' + value: '1.1.1.1' + } + ] + } + localUsers: [ + { + name: 'testuser' + hasSharedKey: false + hasSshKey: true + hasSshPassword: false + homeDirectory: 'avdscripts' + permissionScopes: [ + { + permissions: 'r' + service: 'blob' + resourceName: 'avdscripts' + } + ] + } + ] + blobServices: { + lastAccessTimeTrackingPolicyEnabled: true + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + containers: [ + { + name: 'avdscripts' + enableNfsV3AllSquash: true + enableNfsV3RootSquash: true + publicAccess: 'None' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + { + name: 'archivecontainer' + publicAccess: 'None' + metadata: { + testKey: 'testValue' + } + allowProtectedAppendWrites: false + } + ] + automaticSnapshotPolicyEnabled: true + containerDeleteRetentionPolicyEnabled: true + containerDeleteRetentionPolicyDays: 10 + deleteRetentionPolicyEnabled: true + deleteRetentionPolicyDays: 9 + corsRules: [ + { + allowedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-target-path' + 'x-ms-meta-source-path' + ] + exposedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-target-path' + 'x-ms-meta-source-path' + ] + allowedOrigins: [ + 'http://*.contoso.com' + 'http://www.fabrikam.com' + ] + allowedMethods: [ + 'GET' + 'PUT' + ] + maxAgeInSeconds: 200 + } + ] + } + fileServices: { + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + shares: [ + { + name: 'avdprofiles' + accessTier: 'Hot' + shareQuota: 5120 + roleAssignments: [ + { + name: 'cff1213b-7877-4425-b67c-bb1de8950dfb' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}-share-avdprofiles') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + { + name: 'avdprofiles2' + shareQuota: 102400 + } + ] + corsRules: [ + { + allowedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-target-path' + 'x-ms-meta-source-path' + ] + exposedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-target-path' + 'x-ms-meta-source-path' + ] + allowedOrigins: [ + 'http://*.contoso.com' + 'http://www.fabrikam.com' + ] + allowedMethods: [ + 'GET' + 'PUT' + ] + maxAgeInSeconds: 200 + } + ] + } + tableServices: { + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tables: [ + { + name: 'table1' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + { + name: 'table2' + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + ] + corsRules: [ + { + allowedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-target-path' + 'x-ms-meta-source-path' + ] + exposedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-target-path' + 'x-ms-meta-source-path' + ] + allowedOrigins: [ + 'http://*.contoso.com' + 'http://www.fabrikam.com' + ] + allowedMethods: [ + 'GET' + 'PUT' + ] + maxAgeInSeconds: 200 + } + ] + } + queueServices: { + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + queues: [ + { + name: 'queue1' + metadata: { + key1: 'value1' + key2: 'value2' + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + } + { + name: 'queue2' + metadata: {} + } + ] + corsRules: [ + { + allowedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-target-path' + 'x-ms-meta-source-path' + ] + exposedHeaders: [ + 'x-ms-meta-data' + 'x-ms-meta-target-path' + 'x-ms-meta-source-path' + ] + allowedOrigins: [ + 'http://*.contoso.com' + 'http://www.fabrikam.com' + ] + allowedMethods: [ + 'GET' + 'PUT' + ] + maxAgeInSeconds: 200 + } + ] + } + sasExpirationPeriod: '180.00:00:00' + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + roleAssignments: [ + { + name: '30b99723-a3d8-4e31-8872-b80c960d62bd' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + managementPolicyRules: [ + { + enabled: true + name: 'FirstRule' + type: 'Lifecycle' + definition: { + actions: { + baseBlob: { + delete: { + daysAfterModificationGreaterThan: 30 + } + tierToCool: { + daysAfterLastAccessTimeGreaterThan: 5 + } + } + } + filters: { + blobIndexMatch: [ + { + name: 'BlobIndex' + op: '==' + value: '1' + } + ] + blobTypes: [ + 'blockBlob' + ] + prefixMatch: [ + 'sample-container/log' + ] + } + } + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/nfs/main.test.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/nfs/main.test.bicep new file mode 100644 index 000000000..5a02f91fd --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/nfs/main.test.bicep @@ -0,0 +1,58 @@ +targetScope = 'subscription' + +metadata name = 'Deploying with a NFS File Share' +metadata description = 'This instance deploys the module with a NFS File Share.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-storage.storageaccounts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssanfs' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + skuName: 'Premium_LRS' + kind: 'FileStorage' + fileServices: { + shares: [ + { + name: 'nfsfileshare' + enabledProtocols: 'NFS' + } + ] + } + } + } +] diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/system-assigned-cmk-encryption/dependencies.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/system-assigned-cmk-encryption/dependencies.bicep new file mode 100644 index 000000000..26d25098d --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/system-assigned-cmk-encryption/dependencies.bicep @@ -0,0 +1,124 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_GRS' + } + kind: 'StorageV2' + identity: { + type: 'SystemAssigned' + } + properties: { + encryption: { + requireInfrastructureEncryption: true + } + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault::key.id}-${location}-${storageAccount.id}-Key-Key-Vault-Crypto-User-RoleAssignment') + scope: keyVault::key + properties: { + principalId: storageAccount.identity.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + ] + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.blob.${environment().suffixes.storage}' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The resource ID of the created Storage Account.') +output storageAccountName string = storageAccount.name + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The name of the created encryption key.') +output keyName string = keyVault::key.name diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/system-assigned-cmk-encryption/main.test.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/system-assigned-cmk-encryption/main.test.bicep new file mode 100644 index 000000000..f25d1ddd7 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/system-assigned-cmk-encryption/main.test.bicep @@ -0,0 +1,94 @@ +targetScope = 'subscription' + +metadata name = 'Using Customer-Managed-Keys with System-Assigned identity' +metadata description = 'This instance deploys the module using Customer-Managed-Keys using a System-Assigned Identity. This required the service to be deployed twice, once as a pre-requisite to create the System-Assigned Identity, and once to use it for accessing the Customer-Managed-Key secret.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-storage.storageaccounts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssasacr' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + storageAccountName: '${namePrefix}${serviceShort}001' + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: nestedDependencies.outputs.storageAccountName + privateEndpoints: [ + { + service: 'blob' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + } + ] + blobServices: { + containers: [ + { + name: '${namePrefix}container' + publicAccess: 'None' + } + ] + } + managedIdentities: { + systemAssigned: true + } + customerManagedKey: { + keyName: nestedDependencies.outputs.keyName + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + } + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep new file mode 100644 index 000000000..a2f946fa9 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep @@ -0,0 +1,116 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + ] + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.blob.${environment().suffixes.storage}' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-KeyVault-Reader-RoleAssignment.') + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The name of the created encryption key.') +output keyName string = keyVault::key.name diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/user-assigned-cmk-encryption/main.test.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/user-assigned-cmk-encryption/main.test.bicep new file mode 100644 index 000000000..47a49ecd3 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/user-assigned-cmk-encryption/main.test.bicep @@ -0,0 +1,101 @@ +targetScope = 'subscription' + +metadata name = 'Using Customer-Managed-Keys with User-Assigned identity' +metadata description = 'This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-storage.storageaccounts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssauacr' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + } + privateEndpoints: [ + { + service: 'blob' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + } + ] + blobServices: { + containers: [ + { + name: '${namePrefix}container' + publicAccess: 'None' + } + ] + } + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + customerManagedKey: { + keyName: nestedDependencies.outputs.keyName + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + userAssignedIdentityResourceId: nestedDependencies.outputs.managedIdentityResourceId + } + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/v1/main.test.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/v1/main.test.bicep new file mode 100644 index 000000000..3378266e6 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/v1/main.test.bicep @@ -0,0 +1,49 @@ +targetScope = 'subscription' + +metadata name = 'Deploying as Storage Account version 1' +metadata description = 'This instance deploys the module as Storage Account version 1.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-storage.storageaccounts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssav1' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + kind: 'Storage' + } + } +] diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..b7cff8b3d --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,68 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + ] + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.blob.${environment().suffixes.storage}' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/1.1.0/res/storage/storage-account/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/storage/storage-account/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..2ead4ebd6 --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,311 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-storage.storageaccounts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssawaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + skuName: 'Standard_ZRS' + allowBlobPublicAccess: false + requireInfrastructureEncryption: true + largeFileSharesState: 'Enabled' + enableHierarchicalNamespace: true + enableSftp: true + enableNfsV3: true + privateEndpoints: [ + { + service: 'blob' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + virtualNetworkRules: [ + { + action: 'Allow' + id: nestedDependencies.outputs.subnetResourceId + } + ] + ipRules: [ + { + action: 'Allow' + value: '1.1.1.1' + } + ] + } + localUsers: [ + { + name: 'testuser' + hasSharedKey: false + hasSshKey: true + hasSshPassword: false + homeDirectory: 'avdscripts' + permissionScopes: [ + { + permissions: 'r' + service: 'blob' + resourceName: 'avdscripts' + } + ] + } + ] + blobServices: { + lastAccessTimeTrackingPolicyEnabled: true + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + containers: [ + { + name: 'avdscripts' + enableNfsV3AllSquash: true + enableNfsV3RootSquash: true + publicAccess: 'None' + } + { + name: 'archivecontainer' + publicAccess: 'None' + metadata: { + testKey: 'testValue' + } + allowProtectedAppendWrites: false + } + ] + automaticSnapshotPolicyEnabled: true + containerDeleteRetentionPolicyEnabled: true + containerDeleteRetentionPolicyDays: 10 + deleteRetentionPolicyEnabled: true + deleteRetentionPolicyDays: 9 + } + fileServices: { + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + shares: [ + { + name: 'avdprofiles' + accessTier: 'Hot' + shareQuota: 5120 + } + { + name: 'avdprofiles2' + shareQuota: 102400 + } + ] + } + tableServices: { + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tables: [ + { + name: 'table1' + } + { + name: 'table2' + } + ] + } + queueServices: { + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + queues: [ + { + name: 'queue1' + metadata: { + key1: 'value1' + key2: 'value2' + } + } + { + name: 'queue2' + metadata: {} + } + ] + } + sasExpirationPeriod: '180.00:00:00' + managedIdentities: { + systemAssigned: true + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + managementPolicyRules: [ + { + enabled: true + name: 'FirstRule' + type: 'Lifecycle' + definition: { + actions: { + baseBlob: { + delete: { + daysAfterModificationGreaterThan: 30 + } + tierToCool: { + daysAfterLastAccessTimeGreaterThan: 5 + } + } + } + filters: { + blobIndexMatch: [ + { + name: 'BlobIndex' + op: '==' + value: '1' + } + ] + blobTypes: [ + 'blockBlob' + ] + prefixMatch: [ + 'sample-container/log' + ] + } + } + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/1.1.0/res/storage/storage-account/version.json b/avm/1.1.0/res/storage/storage-account/version.json new file mode 100644 index 000000000..77443210a --- /dev/null +++ b/avm/1.1.0/res/storage/storage-account/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.18", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/1.1.0/res/virtual-machine-images/image-template/README.md b/avm/1.1.0/res/virtual-machine-images/image-template/README.md new file mode 100644 index 000000000..c411e4fe7 --- /dev/null +++ b/avm/1.1.0/res/virtual-machine-images/image-template/README.md @@ -0,0 +1,1454 @@ +# Virtual Machine Image Templates `[Microsoft.VirtualMachineImages/imageTemplates]` + +This module deploys a Virtual Machine Image Template that can be consumed by Azure Image Builder (AIB). + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) +- [Data Collection](#Data-Collection) + +## 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.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.VirtualMachineImages/imageTemplates` | [2024-02-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.VirtualMachineImages/2024-02-01/imageTemplates) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/virtual-machine-images/image-template:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:' = { + name: 'imageTemplateDeployment' + params: { + // Required parameters + distributions: [ + { + imageName: 'mi-vmiitmin-001' + type: 'ManagedImage' + } + ] + imageSource: { + offer: 'Windows-11' + publisher: 'MicrosoftWindowsDesktop' + sku: 'win11-23h2-ent' + type: 'PlatformImage' + version: 'latest' + } + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + name: 'vmiitmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "distributions": { + "value": [ + { + "imageName": "mi-vmiitmin-001", + "type": "ManagedImage" + } + ] + }, + "imageSource": { + "value": { + "offer": "Windows-11", + "publisher": "MicrosoftWindowsDesktop", + "sku": "win11-23h2-ent", + "type": "PlatformImage", + "version": "latest" + } + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "name": { + "value": "vmiitmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/virtual-machine-images/image-template:' + +// Required parameters +param distributions = [ + { + imageName: 'mi-vmiitmin-001' + type: 'ManagedImage' + } +] +param imageSource = { + offer: 'Windows-11' + publisher: 'MicrosoftWindowsDesktop' + sku: 'win11-23h2-ent' + type: 'PlatformImage' + version: 'latest' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param name = 'vmiitmin001' +// Non-required parameters +param location = '' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:' = { + name: 'imageTemplateDeployment' + params: { + // Required parameters + distributions: [ + { + imageName: 'mi-vmiitmax-001' + type: 'ManagedImage' + } + { + imageName: 'umi-vmiitmax-001' + type: 'VHD' + } + { + replicationRegions: [ + '' + ] + sharedImageGalleryImageDefinitionResourceId: '' + sharedImageGalleryImageDefinitionTargetVersion: '' + type: 'SharedImage' + } + ] + imageSource: { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' + } + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + name: 'vmiitmax001' + // Non-required parameters + autoRunState: 'Enabled' + buildTimeoutInMinutes: 60 + customizationSteps: [ + { + name: 'PowerShell installation' + scriptUri: '' + type: 'Shell' + } + { + destination: 'Initialize-LinuxSoftware.ps1' + name: 'Initialize-LinuxSoftware' + sourceUri: '' + type: 'File' + } + { + inline: [ + 'pwsh \'Initialize-LinuxSoftware.ps1\'' + ] + name: 'Software installation' + type: 'Shell' + } + ] + errorHandlingOnCustomizerError: 'cleanup' + errorHandlingOnValidationError: 'abort' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedResourceTags: { + testKey1: 'testValue1' + testKey2: 'testValue2' + } + optimizeVmBoot: 'Enabled' + osDiskSizeGB: 127 + roleAssignments: [ + { + name: 'bb257a92-dc06-4831-9b74-ee5442d8ce0f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + stagingResourceGroupResourceId: '' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + validationProcess: { + continueDistributeOnFailure: true + inVMValidations: [ + { + inline: [ + 'echo \'Software validation successful.\'' + ] + name: 'Validate-Software' + type: 'Shell' + } + ] + sourceValidationOnly: false + } + vmSize: 'Standard_D2s_v3' + vmUserAssignedIdentities: [ + '' + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "distributions": { + "value": [ + { + "imageName": "mi-vmiitmax-001", + "type": "ManagedImage" + }, + { + "imageName": "umi-vmiitmax-001", + "type": "VHD" + }, + { + "replicationRegions": [ + "" + ], + "sharedImageGalleryImageDefinitionResourceId": "", + "sharedImageGalleryImageDefinitionTargetVersion": "", + "type": "SharedImage" + } + ] + }, + "imageSource": { + "value": { + "offer": "ubuntu-24_04-lts", + "publisher": "canonical", + "sku": "server", + "type": "PlatformImage", + "version": "latest" + } + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "name": { + "value": "vmiitmax001" + }, + // Non-required parameters + "autoRunState": { + "value": "Enabled" + }, + "buildTimeoutInMinutes": { + "value": 60 + }, + "customizationSteps": { + "value": [ + { + "name": "PowerShell installation", + "scriptUri": "", + "type": "Shell" + }, + { + "destination": "Initialize-LinuxSoftware.ps1", + "name": "Initialize-LinuxSoftware", + "sourceUri": "", + "type": "File" + }, + { + "inline": [ + "pwsh \"Initialize-LinuxSoftware.ps1\"" + ], + "name": "Software installation", + "type": "Shell" + } + ] + }, + "errorHandlingOnCustomizerError": { + "value": "cleanup" + }, + "errorHandlingOnValidationError": { + "value": "abort" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedResourceTags": { + "value": { + "testKey1": "testValue1", + "testKey2": "testValue2" + } + }, + "optimizeVmBoot": { + "value": "Enabled" + }, + "osDiskSizeGB": { + "value": 127 + }, + "roleAssignments": { + "value": [ + { + "name": "bb257a92-dc06-4831-9b74-ee5442d8ce0f", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "stagingResourceGroupResourceId": { + "value": "" + }, + "subnetResourceId": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "validationProcess": { + "value": { + "continueDistributeOnFailure": true, + "inVMValidations": [ + { + "inline": [ + "echo \"Software validation successful.\"" + ], + "name": "Validate-Software", + "type": "Shell" + } + ], + "sourceValidationOnly": false + } + }, + "vmSize": { + "value": "Standard_D2s_v3" + }, + "vmUserAssignedIdentities": { + "value": [ + "" + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/virtual-machine-images/image-template:' + +// Required parameters +param distributions = [ + { + imageName: 'mi-vmiitmax-001' + type: 'ManagedImage' + } + { + imageName: 'umi-vmiitmax-001' + type: 'VHD' + } + { + replicationRegions: [ + '' + ] + sharedImageGalleryImageDefinitionResourceId: '' + sharedImageGalleryImageDefinitionTargetVersion: '' + type: 'SharedImage' + } +] +param imageSource = { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param name = 'vmiitmax001' +// Non-required parameters +param autoRunState = 'Enabled' +param buildTimeoutInMinutes = 60 +param customizationSteps = [ + { + name: 'PowerShell installation' + scriptUri: '' + type: 'Shell' + } + { + destination: 'Initialize-LinuxSoftware.ps1' + name: 'Initialize-LinuxSoftware' + sourceUri: '' + type: 'File' + } + { + inline: [ + 'pwsh \'Initialize-LinuxSoftware.ps1\'' + ] + name: 'Software installation' + type: 'Shell' + } +] +param errorHandlingOnCustomizerError = 'cleanup' +param errorHandlingOnValidationError = 'abort' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedResourceTags = { + testKey1: 'testValue1' + testKey2: 'testValue2' +} +param optimizeVmBoot = 'Enabled' +param osDiskSizeGB = 127 +param roleAssignments = [ + { + name: 'bb257a92-dc06-4831-9b74-ee5442d8ce0f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param stagingResourceGroupResourceId = '' +param subnetResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param validationProcess = { + continueDistributeOnFailure: true + inVMValidations: [ + { + inline: [ + 'echo \'Software validation successful.\'' + ] + name: 'Validate-Software' + type: 'Shell' + } + ] + sourceValidationOnly: false +} +param vmSize = 'Standard_D2s_v3' +param vmUserAssignedIdentities = [ + '' +] +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:' = { + name: 'imageTemplateDeployment' + params: { + // Required parameters + distributions: [ + { + sharedImageGalleryImageDefinitionResourceId: '' + type: 'SharedImage' + } + ] + imageSource: { + offer: 'Windows-11' + publisher: 'MicrosoftWindowsDesktop' + sku: 'win11-22h2-avd' + type: 'PlatformImage' + version: 'latest' + } + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + name: 'vmiitwaf001' + // Non-required parameters + customizationSteps: [ + { + restartTimeout: '10m' + type: 'WindowsRestart' + } + ] + location: '' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "distributions": { + "value": [ + { + "sharedImageGalleryImageDefinitionResourceId": "", + "type": "SharedImage" + } + ] + }, + "imageSource": { + "value": { + "offer": "Windows-11", + "publisher": "MicrosoftWindowsDesktop", + "sku": "win11-22h2-avd", + "type": "PlatformImage", + "version": "latest" + } + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "name": { + "value": "vmiitwaf001" + }, + // Non-required parameters + "customizationSteps": { + "value": [ + { + "restartTimeout": "10m", + "type": "WindowsRestart" + } + ] + }, + "location": { + "value": "" + }, + "subnetResourceId": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/virtual-machine-images/image-template:' + +// Required parameters +param distributions = [ + { + sharedImageGalleryImageDefinitionResourceId: '' + type: 'SharedImage' + } +] +param imageSource = { + offer: 'Windows-11' + publisher: 'MicrosoftWindowsDesktop' + sku: 'win11-22h2-avd' + type: 'PlatformImage' + version: 'latest' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param name = 'vmiitwaf001' +// Non-required parameters +param customizationSteps = [ + { + restartTimeout: '10m' + type: 'WindowsRestart' + } +] +param location = '' +param subnetResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`distributions`](#parameter-distributions) | array | The distribution targets where the image output needs to go to. | +| [`imageSource`](#parameter-imagesource) | object | Image source definition in object format. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | +| [`name`](#parameter-name) | string | The name prefix of the Image Template to be built by the Azure Image Builder service. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`autoRunState`](#parameter-autorunstate) | string | Indicates whether or not to automatically run the image template build on template creation or update. | +| [`buildTimeoutInMinutes`](#parameter-buildtimeoutinminutes) | int | The image build timeout in minutes. 0 means the default 240 minutes. | +| [`customizationSteps`](#parameter-customizationsteps) | array | Customization steps to be run when building the VM image. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`errorHandlingOnCustomizerError`](#parameter-errorhandlingoncustomizererror) | string | If there is a customizer error and this field is set to 'cleanup', the build VM and associated network resources will be cleaned up. This is the default behavior. If there is a customizer error and this field is set to 'abort', the build VM will be preserved. | +| [`errorHandlingOnValidationError`](#parameter-errorhandlingonvalidationerror) | string | If there is a validation error and this field is set to 'cleanup', the build VM and associated network resources will be cleaned up. If there is a validation error and this field is set to 'abort', the build VM will be preserved. This is the default behavior. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedResourceTags`](#parameter-managedresourcetags) | object | Tags that will be applied to the resource group and/or resources created by the service. | +| [`optimizeVmBoot`](#parameter-optimizevmboot) | string | The optimize property can be enabled while creating a VM image and allows VM optimization to improve image creation time. | +| [`osDiskSizeGB`](#parameter-osdisksizegb) | int | Specifies the size of OS disk. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`stagingResourceGroupResourceId`](#parameter-stagingresourcegroupresourceid) | string | Resource ID of the staging resource group in the same subscription and location as the image template that will be used to build the image.

If this field is empty, a resource group with a random name will be created.

If the resource group specified in this field doesn't exist, it will be created with the same name.

If the resource group specified exists, it must be empty and in the same region as the image template.

The resource group created will be deleted during template deletion if this field is empty or the resource group specified doesn't exist,

but if the resource group specified exists the resources created in the resource group will be deleted during template deletion and the resource group itself will remain. | +| [`subnetResourceId`](#parameter-subnetresourceid) | string | Resource ID of an already existing subnet, e.g.: /subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/.

If no value is provided, a new temporary VNET and subnet will be created in the staging resource group and will be deleted along with the remaining temporary resources. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`validationProcess`](#parameter-validationprocess) | object | Configuration options and list of validations to be performed on the resulting image. | +| [`vmSize`](#parameter-vmsize) | string | Specifies the size for the VM. | +| [`vmUserAssignedIdentities`](#parameter-vmuserassignedidentities) | array | List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts. Be aware, the user assigned identities specified in the 'managedIdentities' parameter must have the 'Managed Identity Operator' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM. | + +**Generated parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`baseTime`](#parameter-basetime) | string | Do not provide a value! This date is used to generate a unique image template name. | + +### Parameter: `distributions` + +The distribution targets where the image output needs to go to. + +- Required: Yes +- Type: array + +### Parameter: `imageSource` + +Image source definition in object format. + +- Required: Yes +- Type: object + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: Yes +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. | + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. + +- Required: No +- Type: array + +### Parameter: `name` + +The name prefix of the Image Template to be built by the Azure Image Builder service. + +- Required: Yes +- Type: string + +### Parameter: `autoRunState` + +Indicates whether or not to automatically run the image template build on template creation or update. + +- Required: No +- Type: string +- Default: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `buildTimeoutInMinutes` + +The image build timeout in minutes. 0 means the default 240 minutes. + +- Required: No +- Type: int +- Default: `0` +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `customizationSteps` + +Customization steps to be run when building the VM image. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `errorHandlingOnCustomizerError` + +If there is a customizer error and this field is set to 'cleanup', the build VM and associated network resources will be cleaned up. This is the default behavior. If there is a customizer error and this field is set to 'abort', the build VM will be preserved. + +- Required: No +- Type: string +- Default: `'cleanup'` +- Allowed: + ```Bicep + [ + 'abort' + 'cleanup' + ] + ``` +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `errorHandlingOnValidationError` + +If there is a validation error and this field is set to 'cleanup', the build VM and associated network resources will be cleaned up. If there is a validation error and this field is set to 'abort', the build VM will be preserved. This is the default behavior. + +- Required: No +- Type: string +- Default: `'cleanup'` +- Allowed: + ```Bicep + [ + 'abort' + 'cleanup' + ] + ``` +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 960 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `managedResourceTags` + +Tags that will be applied to the resource group and/or resources created by the service. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `optimizeVmBoot` + +The optimize property can be enabled while creating a VM image and allows VM optimization to improve image creation time. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `osDiskSizeGB` + +Specifies the size of OS disk. + +- Required: No +- Type: int +- Default: `128` +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 960 +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | 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". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `roleAssignments.condition` + +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". + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `stagingResourceGroupResourceId` + +Resource ID of the staging resource group in the same subscription and location as the image template that will be used to build the image.

If this field is empty, a resource group with a random name will be created.

If the resource group specified in this field doesn't exist, it will be created with the same name.

If the resource group specified exists, it must be empty and in the same region as the image template.

The resource group created will be deleted during template deletion if this field is empty or the resource group specified doesn't exist,

but if the resource group specified exists the resources created in the resource group will be deleted during template deletion and the resource group itself will remain. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `subnetResourceId` + +Resource ID of an already existing subnet, e.g.: /subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/.

If no value is provided, a new temporary VNET and subnet will be created in the staging resource group and will be deleted along with the remaining temporary resources. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `validationProcess` + +Configuration options and list of validations to be performed on the resulting image. + +- Required: No +- Type: object +- MinValue: 0 +- MaxValue: 960 + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`continueDistributeOnFailure`](#parameter-validationprocesscontinuedistributeonfailure) | bool | If validation fails and this field is set to false, output image(s) will not be distributed. This is the default behavior. If validation fails and this field is set to true, output image(s) will still be distributed. Please use this option with caution as it may result in bad images being distributed for use. In either case (true or false), the end to end image run will be reported as having failed in case of a validation failure. [Note: This field has no effect if validation succeeds.]. | +| [`inVMValidations`](#parameter-validationprocessinvmvalidations) | array | A list of validators that will be performed on the image. Azure Image Builder supports File, PowerShell and Shell validators. | +| [`sourceValidationOnly`](#parameter-validationprocesssourcevalidationonly) | bool | If this field is set to true, the image specified in the 'source' section will directly be validated. No separate build will be run to generate and then validate a customized image. Not supported when performing customizations, validations or distributions on the image. | + +### Parameter: `validationProcess.continueDistributeOnFailure` + +If validation fails and this field is set to false, output image(s) will not be distributed. This is the default behavior. If validation fails and this field is set to true, output image(s) will still be distributed. Please use this option with caution as it may result in bad images being distributed for use. In either case (true or false), the end to end image run will be reported as having failed in case of a validation failure. [Note: This field has no effect if validation succeeds.]. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `validationProcess.inVMValidations` + +A list of validators that will be performed on the image. Azure Image Builder supports File, PowerShell and Shell validators. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 960 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`type`](#parameter-validationprocessinvmvalidationstype) | string | The type of validation. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`destination`](#parameter-validationprocessinvmvalidationsdestination) | string | Destination of the file. | +| [`inline`](#parameter-validationprocessinvmvalidationsinline) | array | Array of commands to be run, separated by commas. | +| [`name`](#parameter-validationprocessinvmvalidationsname) | string | Friendly Name to provide context on what this validation step does. | +| [`runAsSystem`](#parameter-validationprocessinvmvalidationsrunassystem) | bool | If specified, the PowerShell script will be run with elevated privileges using the Local System user. Can only be true when the runElevated field above is set to true. | +| [`runElevated`](#parameter-validationprocessinvmvalidationsrunelevated) | bool | If specified, the PowerShell script will be run with elevated privileges. | +| [`scriptUri`](#parameter-validationprocessinvmvalidationsscripturi) | string | URI of the PowerShell script to be run for validation. It can be a github link, Azure Storage URI, etc. | +| [`sha256Checksum`](#parameter-validationprocessinvmvalidationssha256checksum) | string | Value of sha256 checksum of the file, you generate this locally, and then Image Builder will checksum and validate. | +| [`sourceUri`](#parameter-validationprocessinvmvalidationssourceuri) | string | The source URI of the file. | +| [`validExitCodes`](#parameter-validationprocessinvmvalidationsvalidexitcodes) | array | Valid codes that can be returned from the script/inline command, this avoids reported failure of the script/inline command. | + +### Parameter: `validationProcess.inVMValidations.type` + +The type of validation. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'File' + 'PowerShell' + 'Shell' + ] + ``` +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `validationProcess.inVMValidations.destination` + +Destination of the file. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `validationProcess.inVMValidations.inline` + +Array of commands to be run, separated by commas. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `validationProcess.inVMValidations.name` + +Friendly Name to provide context on what this validation step does. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `validationProcess.inVMValidations.runAsSystem` + +If specified, the PowerShell script will be run with elevated privileges using the Local System user. Can only be true when the runElevated field above is set to true. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `validationProcess.inVMValidations.runElevated` + +If specified, the PowerShell script will be run with elevated privileges. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `validationProcess.inVMValidations.scriptUri` + +URI of the PowerShell script to be run for validation. It can be a github link, Azure Storage URI, etc. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `validationProcess.inVMValidations.sha256Checksum` + +Value of sha256 checksum of the file, you generate this locally, and then Image Builder will checksum and validate. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `validationProcess.inVMValidations.sourceUri` + +The source URI of the file. + +- Required: No +- Type: string +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `validationProcess.inVMValidations.validExitCodes` + +Valid codes that can be returned from the script/inline command, this avoids reported failure of the script/inline command. + +- Required: No +- Type: array +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `validationProcess.sourceValidationOnly` + +If this field is set to true, the image specified in the 'source' section will directly be validated. No separate build will be run to generate and then validate a customized image. Not supported when performing customizations, validations or distributions on the image. + +- Required: No +- Type: bool +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `vmSize` + +Specifies the size for the VM. + +- Required: No +- Type: string +- Default: `'Standard_D2s_v3'` +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `vmUserAssignedIdentities` + +List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts. Be aware, the user assigned identities specified in the 'managedIdentities' parameter must have the 'Managed Identity Operator' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM. + +- Required: No +- Type: array +- Default: `[]` +- MinValue: 0 +- MaxValue: 960 + +### Parameter: `baseTime` + +Do not provide a value! This date is used to generate a unique image template name. + +- Required: No +- Type: string +- Default: `[utcNow('yyyy-MM-dd-HH-mm-ss')]` +- MinValue: 0 +- MaxValue: 960 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The full name of the deployed image template. | +| `namePrefix` | string | The prefix of the image template name provided as input. | +| `resourceGroupName` | string | The resource group the image template was deployed into. | +| `resourceId` | string | The resource ID of the image template. | +| `runThisCommand` | string | The command to run in order to trigger the image build. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.5.1` | Remote reference | + +## Notes + +### Parameter Usage: `imageSource` + +Tag names and tag values can be provided as needed. A tag can be left without a value. + +#### Platform Image + +
+ +Parameter JSON format + +```json +"source": { + "type": "PlatformImage", + "publisher": "MicrosoftWindowsDesktop", + "offer": "Windows-10", + "sku": "19h2-evd", + "version": "latest" +} +``` + +
+ +
+ +Bicep format + +```bicep +source: { + type: 'PlatformImage' + publisher: 'MicrosoftWindowsDesktop' + offer: 'Windows-10' + sku: '19h2-evd' + version: 'latest' +} +``` + +
+

+ +#### Managed Image + +

+ +Parameter JSON format + +```json +"source": { + "type": "ManagedImage", + "imageId": "/subscriptions//resourceGroups/{destinationResourceGroupName}/providers/Microsoft.Compute/images/" +} +``` + +
+ +
+ +Bicep format + +```bicep +source: { + type: 'ManagedImage' + imageId: '/subscriptions//resourceGroups/{destinationResourceGroupName}/providers/Microsoft.Compute/images/' +} +``` + +
+

+ +#### Shared Image + +

+ +Parameter JSON format + +```json +"source": { + "type": "SharedImageVersion", + "imageVersionID": "/subscriptions//resourceGroups//providers/Microsoft.Compute/galleries//images/" +} +``` + +
+ +
+ +Bicep format + +```bicep +source: { + type: 'SharedImageVersion' + imageVersionID: '/subscriptions//resourceGroups//providers/Microsoft.Compute/galleries//images/' +} +``` + +
+

+ +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/1.1.0/res/virtual-machine-images/image-template/main.bicep b/avm/1.1.0/res/virtual-machine-images/image-template/main.bicep new file mode 100644 index 000000000..130557ff9 --- /dev/null +++ b/avm/1.1.0/res/virtual-machine-images/image-template/main.bicep @@ -0,0 +1,387 @@ +metadata name = 'Virtual Machine Image Templates' +metadata description = 'This module deploys a Virtual Machine Image Template that can be consumed by Azure Image Builder (AIB).' + +@description('Required. The name prefix of the Image Template to be built by the Azure Image Builder service.') +param name string + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. The image build timeout in minutes. 0 means the default 240 minutes.') +@minValue(0) +@maxValue(960) +param buildTimeoutInMinutes int = 0 + +@description('Optional. Specifies the size for the VM.') +param vmSize string = 'Standard_D2s_v3' + +@description('Optional. Specifies the size of OS disk.') +param osDiskSizeGB int = 128 + +@description('Optional. Resource ID of an already existing subnet, e.g.: /subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/.

If no value is provided, a new temporary VNET and subnet will be created in the staging resource group and will be deleted along with the remaining temporary resources.') +param subnetResourceId string? + +@description('Required. Image source definition in object format.') +param imageSource object + +@description('Optional. Customization steps to be run when building the VM image.') +param customizationSteps array? + +@description('Optional. Resource ID of the staging resource group in the same subscription and location as the image template that will be used to build the image.

If this field is empty, a resource group with a random name will be created.

If the resource group specified in this field doesn\'t exist, it will be created with the same name.

If the resource group specified exists, it must be empty and in the same region as the image template.

The resource group created will be deleted during template deletion if this field is empty or the resource group specified doesn\'t exist,

but if the resource group specified exists the resources created in the resource group will be deleted during template deletion and the resource group itself will remain.') +param stagingResourceGroupResourceId string? + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Generated. Do not provide a value! This date is used to generate a unique image template name.') +param baseTime string = utcNow('yyyy-MM-dd-HH-mm-ss') + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Required. The distribution targets where the image output needs to go to.') +param distributions distributionType[] + +@description('Optional. List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts. Be aware, the user assigned identities specified in the \'managedIdentities\' parameter must have the \'Managed Identity Operator\' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM.') +param vmUserAssignedIdentities array = [] + +import { managedIdentityOnlyUserAssignedType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Required. The managed identity definition for this resource.') +param managedIdentities managedIdentityOnlyUserAssignedType + +@description('Optional. Configuration options and list of validations to be performed on the resulting image.') +param validationProcess validationProcessType? + +@allowed([ + 'Enabled' + 'Disabled' +]) +@description('Optional. The optimize property can be enabled while creating a VM image and allows VM optimization to improve image creation time.') +param optimizeVmBoot string? + +@allowed([ + 'Enabled' + 'Disabled' +]) +@description('Optional. Indicates whether or not to automatically run the image template build on template creation or update.') +param autoRunState string = 'Disabled' + +@allowed([ + 'cleanup' + 'abort' +]) +@description('Optional. If there is a customizer error and this field is set to \'cleanup\', the build VM and associated network resources will be cleaned up. This is the default behavior. If there is a customizer error and this field is set to \'abort\', the build VM will be preserved.') +param errorHandlingOnCustomizerError string = 'cleanup' + +@allowed([ + 'cleanup' + 'abort' +]) +@description('Optional. If there is a validation error and this field is set to \'cleanup\', the build VM and associated network resources will be cleaned up. If there is a validation error and this field is set to \'abort\', the build VM will be preserved. This is the default behavior.') +param errorHandlingOnValidationError string = 'cleanup' + +@description('Optional. Tags that will be applied to the resource group and/or resources created by the service.') +param managedResourceTags object? + +var identity = { + type: 'UserAssigned' + userAssignedIdentities: reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) + ) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } +} + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.virtualmachineimages-imagetemplate.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource imageTemplate 'Microsoft.VirtualMachineImages/imageTemplates@2024-02-01' = { + #disable-next-line use-stable-resource-identifiers // Disabling as ImageTemplates are not idempotent and hence always must have new name + name: '${name}-${baseTime}' + location: location + tags: tags + identity: identity + properties: { + buildTimeoutInMinutes: buildTimeoutInMinutes + vmProfile: { + vmSize: vmSize + osDiskSizeGB: osDiskSizeGB + userAssignedIdentities: vmUserAssignedIdentities + vnetConfig: !empty(subnetResourceId) + ? { + subnetId: subnetResourceId + } + : null + } + source: imageSource + ...(!empty(customizationSteps) + ? { + customize: customizationSteps + } + : {}) + stagingResourceGroup: stagingResourceGroupResourceId + distribute: map(distributions, distribution => { + type: distribution.type + artifactTags: distribution.?artifactTags ?? { + sourceType: imageSource.type + sourcePublisher: imageSource.?publisher + sourceOffer: imageSource.?offer + sourceSku: imageSource.?sku + sourceVersion: imageSource.?version + sourceImageId: imageSource.?imageId + sourceImageVersionID: imageSource.?imageVersionID + creationTime: baseTime + } + ...(distribution.type == 'ManagedImage' + ? { + runOutputName: distribution.?runOutputName ?? '${distribution.imageName}-${baseTime}-ManagedImage' + location: distribution.?location ?? location + #disable-next-line use-resource-id-functions // Disabling rule as this is an input parameter that is used inside an array. + imageId: distribution.?imageResourceId ?? '${subscription().id}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Compute/images/${distribution.imageName}-${baseTime}' + } + : {}) + ...(distribution.type == 'SharedImage' + ? { + runOutputName: distribution.?runOutputName ?? (!empty(distribution.?sharedImageGalleryImageDefinitionResourceId) + ? '${last(split((distribution.sharedImageGalleryImageDefinitionResourceId ?? '/'), '/'))}-SharedImage' + : 'SharedImage') + galleryImageId: !empty(distribution.?sharedImageGalleryImageDefinitionTargetVersion) + ? '${distribution.sharedImageGalleryImageDefinitionResourceId}/versions/${distribution.sharedImageGalleryImageDefinitionTargetVersion}' + : distribution.sharedImageGalleryImageDefinitionResourceId + excludeFromLatest: distribution.?excludeFromLatest ?? false + replicationRegions: distribution.?replicationRegions ?? [location] + storageAccountType: distribution.?storageAccountType ?? 'Standard_LRS' + } + : {}) + ...(distribution.type == 'VHD' + ? { + runOutputName: distribution.?runOutputName ?? '${distribution.imageName}-VHD' + } + : {}) + }) + #disable-next-line BCP225 // The discriminator property "type" value cannot be determined at compilation time. - which is fine + validate: validationProcess + optimize: optimizeVmBoot != null + ? { + vmBoot: { + state: optimizeVmBoot + } + } + : null + autoRun: { + state: autoRunState + } + errorHandling: { + onCustomizerError: errorHandlingOnCustomizerError + onValidationError: errorHandlingOnValidationError + } + managedResourceTags: managedResourceTags + } +} + +resource imageTemplate_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: imageTemplate +} + +resource imageTemplate_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(imageTemplate.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: imageTemplate + } +] + +@description('The resource ID of the image template.') +output resourceId string = imageTemplate.id + +@description('The resource group the image template was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The full name of the deployed image template.') +output name string = imageTemplate.name + +@description('The prefix of the image template name provided as input.') +output namePrefix string = name + +@description('The command to run in order to trigger the image build.') +output runThisCommand string = 'Invoke-AzResourceAction -ResourceName ${imageTemplate.name} -ResourceGroupName ${resourceGroup().name} -ResourceType Microsoft.VirtualMachineImages/imageTemplates -Action Run -Force' + +@description('The location the resource was deployed into.') +output location string = imageTemplate.location + +// =============== // +// Definitions // +// =============== // + +@export() +@discriminator('type') +type distributionType = sharedImageDistributionType | managedImageDistributionType | unManagedDistributionType + +@export() +type sharedImageDistributionType = { + @description('Optional. The name to be used for the associated RunOutput. If not provided, a name will be calculated.') + runOutputName: string? + + @description('Optional. Tags that will be applied to the artifact once it has been created/updated by the distributor. If not provided will set tags based on the provided image source.') + artifactTags: object? + + @description('Required. The type of distribution.') + type: 'SharedImage' + + @description('Conditional. Resource ID of Compute Gallery Image Definition to distribute image to, e.g.: /subscriptions//resourceGroups//providers/Microsoft.Compute/galleries//images/.') + sharedImageGalleryImageDefinitionResourceId: string + + @description('Optional. Version of the Compute Gallery Image. Supports the following Version Syntax: Major.Minor.Build (i.e., \'1.1.1\' or \'10.1.2\'). If not provided, a version will be calculated.') + sharedImageGalleryImageDefinitionTargetVersion: string? + + @description('Optional. The exclude from latest flag of the image. Defaults to [false].') + excludeFromLatest: bool? + + @description('Optional. The replication regions of the image. Defaults to the value of the \'location\' parameter.') + replicationRegions: string[]? + + @description('Optional. The storage account type of the image. Defaults to [Standard_LRS].') + storageAccountType: ('Standard_LRS' | 'Standard_ZRS')? +} + +@export() +type unManagedDistributionType = { + @description('Required. The type of distribution.') + type: 'VHD' + + @description('Optional. The name to be used for the associated RunOutput. If not provided, a name will be calculated.') + runOutputName: string? + + @description('Optional. Tags that will be applied to the artifact once it has been created/updated by the distributor. If not provided will set tags based on the provided image source.') + artifactTags: object? + + @description('Conditional. Name of the managed or unmanaged image that will be created.') + imageName: string +} + +@export() +type managedImageDistributionType = { + @description('Required. The type of distribution.') + type: 'ManagedImage' + + @description('Optional. The name to be used for the associated RunOutput. If not provided, a name will be calculated.') + runOutputName: string? + + @description('Optional. Tags that will be applied to the artifact once it has been created/updated by the distributor. If not provided will set tags based on the provided image source.') + artifactTags: object? + + @description('Optional. Azure location for the image, should match if image already exists. Defaults to the value of the \'location\' parameter.') + location: string? + + @description('Required. The resource ID of the managed image. Defaults to a compute image with name \'imageName-baseTime\' in the current resource group.') + imageResourceId: string? + + @description('Conditional. Name of the managed or unmanaged image that will be created.') + imageName: string +} + +@export() +type validationProcessType = { + @description('Optional. If validation fails and this field is set to false, output image(s) will not be distributed. This is the default behavior. If validation fails and this field is set to true, output image(s) will still be distributed. Please use this option with caution as it may result in bad images being distributed for use. In either case (true or false), the end to end image run will be reported as having failed in case of a validation failure. [Note: This field has no effect if validation succeeds.].') + continueDistributeOnFailure: bool? + + @description('Optional. A list of validators that will be performed on the image. Azure Image Builder supports File, PowerShell and Shell validators.') + inVMValidations: { + @description('Required. The type of validation.') + type: ('PowerShell' | 'Shell' | 'File') + + @description('Optional. Friendly Name to provide context on what this validation step does.') + name: string? + + @description('Optional. URI of the PowerShell script to be run for validation. It can be a github link, Azure Storage URI, etc.') + scriptUri: string? + + @description('Optional. Array of commands to be run, separated by commas.') + inline: string[]? + + @description('Optional. Valid codes that can be returned from the script/inline command, this avoids reported failure of the script/inline command.') + validExitCodes: int[]? + + @description('Optional. Value of sha256 checksum of the file, you generate this locally, and then Image Builder will checksum and validate.') + sha256Checksum: string? + + @description('Optional. The source URI of the file.') + sourceUri: string? + + @description('Optional. Destination of the file.') + destination: string? + + @description('Optional. If specified, the PowerShell script will be run with elevated privileges using the Local System user. Can only be true when the runElevated field above is set to true.') + runAsSystem: bool? + + @description('Optional. If specified, the PowerShell script will be run with elevated privileges.') + runElevated: bool? + }[]? + + @description('Optional. If this field is set to true, the image specified in the \'source\' section will directly be validated. No separate build will be run to generate and then validate a customized image. Not supported when performing customizations, validations or distributions on the image.') + sourceValidationOnly: bool? +} diff --git a/avm/1.1.0/res/virtual-machine-images/image-template/main.json b/avm/1.1.0/res/virtual-machine-images/image-template/main.json new file mode 100644 index 000000000..b601983e4 --- /dev/null +++ b/avm/1.1.0/res/virtual-machine-images/image-template/main.json @@ -0,0 +1,750 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.13.18514", + "templateHash": "17172875475270738165" + }, + "name": "Virtual Machine Image Templates", + "description": "This module deploys a Virtual Machine Image Template that can be consumed by Azure Image Builder (AIB)." + }, + "definitions": { + "distributionType": { + "type": "object", + "discriminator": { + "propertyName": "type", + "mapping": { + "SharedImage": { + "$ref": "#/definitions/sharedImageDistributionType" + }, + "ManagedImage": { + "$ref": "#/definitions/managedImageDistributionType" + }, + "VHD": { + "$ref": "#/definitions/unManagedDistributionType" + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "sharedImageDistributionType": { + "type": "object", + "properties": { + "runOutputName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name to be used for the associated RunOutput. If not provided, a name will be calculated." + } + }, + "artifactTags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags that will be applied to the artifact once it has been created/updated by the distributor. If not provided will set tags based on the provided image source." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "SharedImage" + ], + "metadata": { + "description": "Required. The type of distribution." + } + }, + "sharedImageGalleryImageDefinitionResourceId": { + "type": "string", + "metadata": { + "description": "Conditional. Resource ID of Compute Gallery Image Definition to distribute image to, e.g.: /subscriptions//resourceGroups//providers/Microsoft.Compute/galleries//images/." + } + }, + "sharedImageGalleryImageDefinitionTargetVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Version of the Compute Gallery Image. Supports the following Version Syntax: Major.Minor.Build (i.e., '1.1.1' or '10.1.2'). If not provided, a version will be calculated." + } + }, + "excludeFromLatest": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The exclude from latest flag of the image. Defaults to [false]." + } + }, + "replicationRegions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The replication regions of the image. Defaults to the value of the 'location' parameter." + } + }, + "storageAccountType": { + "type": "string", + "allowedValues": [ + "Standard_LRS", + "Standard_ZRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. The storage account type of the image. Defaults to [Standard_LRS]." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "unManagedDistributionType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "VHD" + ], + "metadata": { + "description": "Required. The type of distribution." + } + }, + "runOutputName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name to be used for the associated RunOutput. If not provided, a name will be calculated." + } + }, + "artifactTags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags that will be applied to the artifact once it has been created/updated by the distributor. If not provided will set tags based on the provided image source." + } + }, + "imageName": { + "type": "string", + "metadata": { + "description": "Conditional. Name of the managed or unmanaged image that will be created." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "managedImageDistributionType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "ManagedImage" + ], + "metadata": { + "description": "Required. The type of distribution." + } + }, + "runOutputName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name to be used for the associated RunOutput. If not provided, a name will be calculated." + } + }, + "artifactTags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags that will be applied to the artifact once it has been created/updated by the distributor. If not provided will set tags based on the provided image source." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Azure location for the image, should match if image already exists. Defaults to the value of the 'location' parameter." + } + }, + "imageResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The resource ID of the managed image. Defaults to a compute image with name 'imageName-baseTime' in the current resource group." + } + }, + "imageName": { + "type": "string", + "metadata": { + "description": "Conditional. Name of the managed or unmanaged image that will be created." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "validationProcessType": { + "type": "object", + "properties": { + "continueDistributeOnFailure": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If validation fails and this field is set to false, output image(s) will not be distributed. This is the default behavior. If validation fails and this field is set to true, output image(s) will still be distributed. Please use this option with caution as it may result in bad images being distributed for use. In either case (true or false), the end to end image run will be reported as having failed in case of a validation failure. [Note: This field has no effect if validation succeeds.]." + } + }, + "inVMValidations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "File", + "PowerShell", + "Shell" + ], + "metadata": { + "description": "Required. The type of validation." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Friendly Name to provide context on what this validation step does." + } + }, + "scriptUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. URI of the PowerShell script to be run for validation. It can be a github link, Azure Storage URI, etc." + } + }, + "inline": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of commands to be run, separated by commas." + } + }, + "validExitCodes": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. Valid codes that can be returned from the script/inline command, this avoids reported failure of the script/inline command." + } + }, + "sha256Checksum": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Value of sha256 checksum of the file, you generate this locally, and then Image Builder will checksum and validate." + } + }, + "sourceUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source URI of the file." + } + }, + "destination": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Destination of the file." + } + }, + "runAsSystem": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If specified, the PowerShell script will be run with elevated privileges using the Local System user. Can only be true when the runElevated field above is set to true." + } + }, + "runElevated": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If specified, the PowerShell script will be run with elevated privileges." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of validators that will be performed on the image. Azure Image Builder supports File, PowerShell and Shell validators." + } + }, + "sourceValidationOnly": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If this field is set to true, the image specified in the 'source' section will directly be validated. No separate build will be run to generate and then validate a customized image. Not supported when performing customizations, validations or distributions on the image." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "managedIdentityOnlyUserAssignedType": { + "type": "object", + "properties": { + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name prefix of the Image Template to be built by the Azure Image Builder service." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "buildTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "minValue": 0, + "maxValue": 960, + "metadata": { + "description": "Optional. The image build timeout in minutes. 0 means the default 240 minutes." + } + }, + "vmSize": { + "type": "string", + "defaultValue": "Standard_D2s_v3", + "metadata": { + "description": "Optional. Specifies the size for the VM." + } + }, + "osDiskSizeGB": { + "type": "int", + "defaultValue": 128, + "metadata": { + "description": "Optional. Specifies the size of OS disk." + } + }, + "subnetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of an already existing subnet, e.g.: /subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/.

If no value is provided, a new temporary VNET and subnet will be created in the staging resource group and will be deleted along with the remaining temporary resources." + } + }, + "imageSource": { + "type": "object", + "metadata": { + "description": "Required. Image source definition in object format." + } + }, + "customizationSteps": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Customization steps to be run when building the VM image." + } + }, + "stagingResourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the staging resource group in the same subscription and location as the image template that will be used to build the image.

If this field is empty, a resource group with a random name will be created.

If the resource group specified in this field doesn't exist, it will be created with the same name.

If the resource group specified exists, it must be empty and in the same region as the image template.

The resource group created will be deleted during template deletion if this field is empty or the resource group specified doesn't exist,

but if the resource group specified exists the resources created in the resource group will be deleted during template deletion and the resource group itself will remain." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('yyyy-MM-dd-HH-mm-ss')]", + "metadata": { + "description": "Generated. Do not provide a value! This date is used to generate a unique image template name." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "distributions": { + "type": "array", + "items": { + "$ref": "#/definitions/distributionType" + }, + "metadata": { + "description": "Required. The distribution targets where the image output needs to go to." + } + }, + "vmUserAssignedIdentities": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts. Be aware, the user assigned identities specified in the 'managedIdentities' parameter must have the 'Managed Identity Operator' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlyUserAssignedType", + "metadata": { + "description": "Required. The managed identity definition for this resource." + } + }, + "validationProcess": { + "$ref": "#/definitions/validationProcessType", + "nullable": true, + "metadata": { + "description": "Optional. Configuration options and list of validations to be performed on the resulting image." + } + }, + "optimizeVmBoot": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The optimize property can be enabled while creating a VM image and allows VM optimization to improve image creation time." + } + }, + "autoRunState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Indicates whether or not to automatically run the image template build on template creation or update." + } + }, + "errorHandlingOnCustomizerError": { + "type": "string", + "defaultValue": "cleanup", + "allowedValues": [ + "cleanup", + "abort" + ], + "metadata": { + "description": "Optional. If there is a customizer error and this field is set to 'cleanup', the build VM and associated network resources will be cleaned up. This is the default behavior. If there is a customizer error and this field is set to 'abort', the build VM will be preserved." + } + }, + "errorHandlingOnValidationError": { + "type": "string", + "defaultValue": "cleanup", + "allowedValues": [ + "cleanup", + "abort" + ], + "metadata": { + "description": "Optional. If there is a validation error and this field is set to 'cleanup', the build VM and associated network resources will be cleaned up. If there is a validation error and this field is set to 'abort', the build VM will be preserved. This is the default behavior." + } + }, + "managedResourceTags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags that will be applied to the resource group and/or resources created by the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]" + }, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.virtualmachineimages-imagetemplate.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "imageTemplate": { + "type": "Microsoft.VirtualMachineImages/imageTemplates", + "apiVersion": "2024-02-01", + "name": "[format('{0}-{1}', parameters('name'), parameters('baseTime'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": "[shallowMerge(createArray(createObject('buildTimeoutInMinutes', parameters('buildTimeoutInMinutes'), 'vmProfile', createObject('vmSize', parameters('vmSize'), 'osDiskSizeGB', parameters('osDiskSizeGB'), 'userAssignedIdentities', parameters('vmUserAssignedIdentities'), 'vnetConfig', if(not(empty(parameters('subnetResourceId'))), createObject('subnetId', parameters('subnetResourceId')), null())), 'source', parameters('imageSource')), if(not(empty(parameters('customizationSteps'))), createObject('customize', parameters('customizationSteps')), createObject()), createObject('stagingResourceGroup', parameters('stagingResourceGroupResourceId'), 'distribute', map(parameters('distributions'), lambda('distribution', shallowMerge(createArray(createObject('type', lambdaVariables('distribution').type, 'artifactTags', coalesce(tryGet(lambdaVariables('distribution'), 'artifactTags'), createObject('sourceType', parameters('imageSource').type, 'sourcePublisher', tryGet(parameters('imageSource'), 'publisher'), 'sourceOffer', tryGet(parameters('imageSource'), 'offer'), 'sourceSku', tryGet(parameters('imageSource'), 'sku'), 'sourceVersion', tryGet(parameters('imageSource'), 'version'), 'sourceImageId', tryGet(parameters('imageSource'), 'imageId'), 'sourceImageVersionID', tryGet(parameters('imageSource'), 'imageVersionID'), 'creationTime', parameters('baseTime')))), if(equals(lambdaVariables('distribution').type, 'ManagedImage'), createObject('runOutputName', coalesce(tryGet(lambdaVariables('distribution'), 'runOutputName'), format('{0}-{1}-ManagedImage', lambdaVariables('distribution').imageName, parameters('baseTime'))), 'location', coalesce(tryGet(lambdaVariables('distribution'), 'location'), parameters('location')), 'imageId', coalesce(tryGet(lambdaVariables('distribution'), 'imageResourceId'), format('{0}/resourceGroups/{1}/providers/Microsoft.Compute/images/{2}-{3}', subscription().id, resourceGroup().name, lambdaVariables('distribution').imageName, parameters('baseTime')))), createObject()), if(equals(lambdaVariables('distribution').type, 'SharedImage'), createObject('runOutputName', coalesce(tryGet(lambdaVariables('distribution'), 'runOutputName'), if(not(empty(tryGet(lambdaVariables('distribution'), 'sharedImageGalleryImageDefinitionResourceId'))), format('{0}-SharedImage', last(split(coalesce(lambdaVariables('distribution').sharedImageGalleryImageDefinitionResourceId, '/'), '/'))), 'SharedImage')), 'galleryImageId', if(not(empty(tryGet(lambdaVariables('distribution'), 'sharedImageGalleryImageDefinitionTargetVersion'))), format('{0}/versions/{1}', lambdaVariables('distribution').sharedImageGalleryImageDefinitionResourceId, lambdaVariables('distribution').sharedImageGalleryImageDefinitionTargetVersion), lambdaVariables('distribution').sharedImageGalleryImageDefinitionResourceId), 'excludeFromLatest', coalesce(tryGet(lambdaVariables('distribution'), 'excludeFromLatest'), false()), 'replicationRegions', coalesce(tryGet(lambdaVariables('distribution'), 'replicationRegions'), createArray(parameters('location'))), 'storageAccountType', coalesce(tryGet(lambdaVariables('distribution'), 'storageAccountType'), 'Standard_LRS')), createObject()), if(equals(lambdaVariables('distribution').type, 'VHD'), createObject('runOutputName', coalesce(tryGet(lambdaVariables('distribution'), 'runOutputName'), format('{0}-VHD', lambdaVariables('distribution').imageName))), createObject()))))), 'validate', parameters('validationProcess'), 'optimize', if(not(equals(parameters('optimizeVmBoot'), null())), createObject('vmBoot', createObject('state', parameters('optimizeVmBoot'))), null()), 'autoRun', createObject('state', parameters('autoRunState')), 'errorHandling', createObject('onCustomizerError', parameters('errorHandlingOnCustomizerError'), 'onValidationError', parameters('errorHandlingOnValidationError')), 'managedResourceTags', parameters('managedResourceTags'))))]" + }, + "imageTemplate_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.VirtualMachineImages/imageTemplates/{0}', format('{0}-{1}', parameters('name'), parameters('baseTime')))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "imageTemplate" + ] + }, + "imageTemplate_roleAssignments": { + "copy": { + "name": "imageTemplate_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.VirtualMachineImages/imageTemplates/{0}', format('{0}-{1}', parameters('name'), parameters('baseTime')))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.VirtualMachineImages/imageTemplates', format('{0}-{1}', parameters('name'), parameters('baseTime'))), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "imageTemplate" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the image template." + }, + "value": "[resourceId('Microsoft.VirtualMachineImages/imageTemplates', format('{0}-{1}', parameters('name'), parameters('baseTime')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the image template was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The full name of the deployed image template." + }, + "value": "[format('{0}-{1}', parameters('name'), parameters('baseTime'))]" + }, + "namePrefix": { + "type": "string", + "metadata": { + "description": "The prefix of the image template name provided as input." + }, + "value": "[parameters('name')]" + }, + "runThisCommand": { + "type": "string", + "metadata": { + "description": "The command to run in order to trigger the image build." + }, + "value": "[format('Invoke-AzResourceAction -ResourceName {0} -ResourceGroupName {1} -ResourceType Microsoft.VirtualMachineImages/imageTemplates -Action Run -Force', format('{0}-{1}', parameters('name'), parameters('baseTime')), resourceGroup().name)]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('imageTemplate', '2024-02-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/defaults/dependencies.bicep b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 000000000..1808563df --- /dev/null +++ b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,25 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource msi_roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, 'Contributor', managedIdentityName) + properties: { + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b24988ac-6180-42a0-ab88-20f7382dd24c' + ) // Contributor + principalId: managedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +@description('The resource Id of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id diff --git a/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/defaults/main.test.bicep b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/defaults/main.test.bicep new file mode 100644 index 000000000..8981813b2 --- /dev/null +++ b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,73 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-virtualmachineimages.imagetemplates-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'vmiitmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +// No idempotency test as the resource is, by design, not idempotent. +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + imageSource: { + offer: 'Windows-11' + publisher: 'MicrosoftWindowsDesktop' + sku: 'win11-23h2-ent' + type: 'PlatformImage' + version: 'latest' + } + + distributions: [ + { + imageName: '${namePrefix}-mi-${serviceShort}-001' + type: 'ManagedImage' + } + ] + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + } +} diff --git a/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/dependencies.bicep b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/dependencies.bicep new file mode 100644 index 000000000..31fd62fb2 --- /dev/null +++ b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/dependencies.bicep @@ -0,0 +1,324 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Shared Image Gallery to create.') +param galleryName string + +@description('Required. The name of the Image Definition to create in the Shared Image Gallery.') +param sigImageDefinitionName string + +@description('Required. The name of the Image Managed Identity to create.') +param imageManagedIdentityName string + +@description('Required. The name of the Deployment Script Managed Identity to create.') +param deploymentScriptManagedIdentityName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Optional. The name of the Image Virtual Network Subnet to create.') +param imageSubnetName string = 'imageSubnet' + +@description('Optional. The name of the Deployment Script Virtual Network Subnet to create.') +param deploymentScriptSubnetName string = 'deploymentScriptSubnet' + +@description('Required. The name of the Assets Storage Account to create.') +param assetStorageAccountkName string + +@description('Required. The name of the Deployment Script Storage Account to create.') +param deploymentScriptStorageAccountkName string + +@description('Required. The name of the Deployment Script used to upload files to the Assets Storage Account.') +param storageDeploymentScriptName string + +resource imageManagedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: imageManagedIdentityName + location: location +} + +resource deploymentScriptManagedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: deploymentScriptManagedIdentityName + location: location +} + +var addressPrefix = '10.0.0.0/16' + +// Roles +resource contributorRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: 'b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor + scope: tenant() +} +resource managedIdentityOperatorRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: 'f1a07417-d97a-45cb-824c-7a7467783830' // Managed Identity Operator + scope: tenant() +} +resource storageFileDataPrivilegedContributorRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: '69566ab7-960f-475b-8e7c-b3118f30c6bd' // Storage File Data Priveleged Contributor + scope: tenant() +} +resource storageBlobDataReaderRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' // Storage Blob Data Reader + scope: tenant() +} +resource storageBlobDataContributorRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' // Storage Blob Data Contributor + scope: tenant() +} + +// Resources +resource gallery 'Microsoft.Compute/galleries@2022-03-03' = { + name: galleryName + location: location + properties: {} + + resource imageDefinition 'images@2022-03-03' = { + name: sigImageDefinitionName + location: location + properties: { + architecture: 'x64' + hyperVGeneration: 'V2' + identifier: { + offer: 'devops_linux' + publisher: 'devops' + sku: 'devops_linux_az' + } + osState: 'Generalized' + osType: 'Linux' + recommended: { + memory: { + max: 16 + min: 4 + } + vCPUs: { + max: 8 + min: 2 + } + } + } + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: imageSubnetName + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + privateLinkServiceNetworkPolicies: 'Disabled' // Required if using Azure Image Builder with existing VNET + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + ] + } + } + { + name: deploymentScriptSubnetName + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 1) + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + ] + delegations: [ + { + name: 'Microsoft.ContainerInstance.containerGroups' + properties: { + serviceName: 'Microsoft.ContainerInstance/containerGroups' + } + } + ] + } + } + ] + } +} + +resource assetsStorageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { + name: assetStorageAccountkName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + allowBlobPublicAccess: false + allowSharedKeyAccess: false + } + + resource blobService 'blobServices@2023-01-01' = { + name: 'default' + properties: {} + + resource container 'containers@2023-01-01' = { + name: 'assets' + properties: { + publicAccess: 'None' + } + } + } +} + +// Assign permissions to MSI to be allowed to distribute images. Ref: https://learn.microsoft.com/en-us/azure/virtual-machines/linux/image-builder-permissions-cli#allow-vm-image-builder-to-distribute-images +resource imageContributorRbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, contributorRole.id, imageManagedIdentity.id) + properties: { + roleDefinitionId: contributorRole.id + principalId: imageManagedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +// Assign permission to allow AIB to assign the list of User Assigned Identities to the Build VM. +resource imageManagedIdentityOperatorRbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, managedIdentityOperatorRole.id, imageManagedIdentity.id) + properties: { + roleDefinitionId: managedIdentityOperatorRole.id + principalId: imageManagedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +// Allow Deployment Script MSI to access storage account container to upload files +resource storageContributorRbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid( + assetsStorageAccount::blobService::container.id, + storageBlobDataContributorRole.id, + imageManagedIdentity.id + ) + scope: assetsStorageAccount::blobService::container + properties: { + roleDefinitionId: storageBlobDataContributorRole.id + principalId: deploymentScriptManagedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +// Allow image MSI to access storage account container to read files +resource storageReaderRbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(assetsStorageAccount::blobService::container.id, storageBlobDataReaderRole.id, imageManagedIdentity.id) + scope: assetsStorageAccount::blobService::container + properties: { + roleDefinitionId: storageBlobDataReaderRole.id + principalId: imageManagedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +resource dsStorageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { + name: deploymentScriptStorageAccountkName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + allowSharedKeyAccess: true // May not be disabled to allow deployment script to access storage account files + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + virtualNetworkRules: [ + { + // Allow deployment script to use storage account for private networking of container instance + action: 'Allow' + id: resourceId( + subscription().subscriptionId, + resourceGroup().name, + 'Microsoft.Network/virtualNetworks/subnets', + virtualNetwork.name, + deploymentScriptSubnetName + ) + } + ] + } + } +} + +// Allow Deployment Script MSI to access storage account to upload files +resource storageFileContributorRbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(dsStorageAccount.id, storageFileDataPrivilegedContributorRole.id, deploymentScriptManagedIdentity.id) + scope: dsStorageAccount + properties: { + roleDefinitionId: storageFileDataPrivilegedContributorRole.id + principalId: deploymentScriptManagedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +// Upload storage account files +resource assetsStorageAccount_upload 'Microsoft.Resources/deploymentScripts@2023-08-01' = { + name: storageDeploymentScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${deploymentScriptManagedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '9.7' + retentionInterval: 'P1D' + scriptContent: loadTextContent('../../../../../../../utilities/e2e-template-assets/scripts/Set-StorageContainerContentByEnvVar.ps1') + environmentVariables: [ + { + name: '__SCRIPT__Install__LinuxPowerShell_sh' // May only be alphanumeric characters & underscores. The upload will replace '_' with '.' and '__' with '-'. + value: loadTextContent('src/Install-LinuxPowerShell.sh') + } + { + name: '__SCRIPT__Initialize__LinuxSoftware_ps1' // May only be alphanumeric characters & underscores. The upload will replace '_' with '.' and '__' with '-'. + value: loadTextContent('src/Initialize-LinuxSoftware.ps1') + } + ] + arguments: ' -StorageAccountName "${assetsStorageAccount.name}" -TargetContainer "${assetsStorageAccount::blobService::container.name}"' + timeout: 'PT30M' + cleanupPreference: 'Always' + storageAccountSettings: { + storageAccountName: dsStorageAccount.name + } + containerSettings: { + subnetIds: [ + { + id: resourceId( + subscription().subscriptionId, + resourceGroup().name, + 'Microsoft.Network/virtualNetworks/subnets', + virtualNetwork.name, + deploymentScriptSubnetName + ) + } + ] + } + } + dependsOn: [ + storageContributorRbac + storageFileContributorRbac + ] +} + +@description('The principal ID of the created Image Managed Identity.') +output managedIdentityResourceId string = imageManagedIdentity.id + +@description('The principal ID of the created Image Managed Identity.') +output managedIdentityPrincipalId string = imageManagedIdentity.properties.principalId + +@description('The resource ID of the created Image Definition.') +output sigImageDefinitionId string = gallery::imageDefinition.id + +@description('The subnet resource id of the defaultSubnet of the created Virtual Network.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The blob endpoint of the created Assets Storage Account.') +output assetsStorageAccountNameBlobEndpoint string = assetsStorageAccount.properties.primaryEndpoints.blob + +@description('The name of the created Assets Storage Account Container.') +output assetsStorageAccountContainerName string = assetsStorageAccount::blobService::container.name diff --git a/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/main.test.bicep b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/main.test.bicep new file mode 100644 index 000000000..a67d6f924 --- /dev/null +++ b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/main.test.bicep @@ -0,0 +1,177 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-virtualmachineimages.imagetemplates-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'vmiitmax' + +@description('Optional. The version of the Azure Compute Gallery Image Definition to be added.') +param sigImageVersion string = utcNow('yyyy.MM.dd') + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + imageManagedIdentityName: 'dep-${namePrefix}-imsi-${serviceShort}' + deploymentScriptManagedIdentityName: 'dep-${namePrefix}-dmsi-${serviceShort}' + sigImageDefinitionName: 'dep-${namePrefix}-imgd-${serviceShort}' + galleryName: 'dep${namePrefix}sig${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + assetStorageAccountkName: 'dep${namePrefix}ast${serviceShort}' + deploymentScriptStorageAccountkName: 'dep${namePrefix}dst${serviceShort}' + storageDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +// No idempotency test as the resource is, by design, not idempotent. +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + stagingResourceGroupResourceId: '${subscription().id}/resourcegroups/${resourceGroupName}-staging' + customizationSteps: [ + { + type: 'Shell' + name: 'PowerShell installation' + scriptUri: '${nestedDependencies.outputs.assetsStorageAccountNameBlobEndpoint}${nestedDependencies.outputs.assetsStorageAccountContainerName}/Install-LinuxPowerShell.sh' + } + { + type: 'File' + name: 'Initialize-LinuxSoftware' + sourceUri: '${nestedDependencies.outputs.assetsStorageAccountNameBlobEndpoint}${nestedDependencies.outputs.assetsStorageAccountContainerName}/Initialize-LinuxSoftware.ps1' + destination: 'Initialize-LinuxSoftware.ps1' + } + { + type: 'Shell' + name: 'Software installation' + inline: [ + 'pwsh \'Initialize-LinuxSoftware.ps1\'' + ] + } + ] + validationProcess: { + continueDistributeOnFailure: true + sourceValidationOnly: false + inVMValidations: [ + { + type: 'Shell' + name: 'Validate-Software' + inline: [ + 'echo "Software validation successful."' + ] + } + ] + } + optimizeVmBoot: 'Enabled' + imageSource: { + type: 'PlatformImage' + publisher: 'canonical' + offer: 'ubuntu-24_04-lts' + sku: 'server' + version: 'latest' + } + buildTimeoutInMinutes: 60 + subnetResourceId: nestedDependencies.outputs.subnetResourceId + osDiskSizeGB: 127 + vmSize: 'Standard_D2s_v3' + distributions: [ + { + type: 'ManagedImage' + imageName: '${namePrefix}-mi-${serviceShort}-001' + } + { + type: 'VHD' + imageName: '${namePrefix}-umi-${serviceShort}-001' + } + { + type: 'SharedImage' + sharedImageGalleryImageDefinitionResourceId: nestedDependencies.outputs.sigImageDefinitionId + sharedImageGalleryImageDefinitionTargetVersion: sigImageVersion + replicationRegions: [ + resourceLocation + ] + } + ] + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + vmUserAssignedIdentities: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + autoRunState: 'Enabled' + errorHandlingOnCustomizerError: 'cleanup' + errorHandlingOnValidationError: 'abort' + managedResourceTags: { + testKey1: 'testValue1' + testKey2: 'testValue2' + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'bb257a92-dc06-4831-9b74-ee5442d8ce0f' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} + +@description('The generated name of the image template.') +output imageTemplateName string = testDeployment.outputs.name diff --git a/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/src/Initialize-LinuxSoftware.ps1 b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/src/Initialize-LinuxSoftware.ps1 new file mode 100644 index 000000000..6bd6d4a5a --- /dev/null +++ b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/src/Initialize-LinuxSoftware.ps1 @@ -0,0 +1,93 @@ +#region Functions +function LogInfo($message) { + Log 'Info' $message +} +function LogError($message) { + Log 'Error' $message +} +function LogWarning($message) { + Log 'Warning' $message +} + +function Log { + + <# + .SYNOPSIS + Creates a log file and stores logs based on categories with tab seperation + + .PARAMETER category + Category to put into the trace + + .PARAMETER message + Message to be loged + + .EXAMPLE + Log 'Info' 'Message' + + #> + + Param ( + [Parameter(Mandatory = $false)] + [string] $category = 'Info', + + [Parameter(Mandatory = $true)] + [string] $message + ) + + $date = Get-Date + $content = "[$date]`t$category`t`t$message`n" + Write-Verbose $Content -Verbose + + $FilePath = Join-Path ([System.IO.Path]::GetTempPath()) 'log.log' + if (-not (Test-Path $FilePath)) { + Write-Verbose "Log file not found, create new in path: [$FilePath]" -Verbose + $null = New-Item -ItemType 'File' -Path $FilePath -Force + } + Add-Content -Path $FilePath -Value $content -ErrorAction 'Stop' +} +#endregion + +$StartTime = Get-Date +$progressPreference = 'SilentlyContinue' +LogInfo('#############################################') +LogInfo('# Entering Initialize-LinuxSoftware.ps1 #') +LogInfo('#############################################') + +########################### +## Install Azure CLI ## +########################### +LogInfo('Install azure cli start') +curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash +LogInfo('Install azure cli end') + +########################## +## Install Az Bicep # +########################## +LogInfo('Install az bicep exention start') +az bicep install +LogInfo('Install az bicep exention end') + +########################### +## Install BICEP CLI ## +########################### +LogInfo('Install BICEP start') + +# Fetch the latest Bicep CLI binary +curl -Lo bicep 'https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64' +# Mark it as executable +chmod +x ./bicep +# Add bicep to your PATH (requires admin) +sudo mv ./bicep /usr/local/bin/bicep + +LogInfo('Install BICEP end') + + +$elapsedTime = (Get-Date) - $StartTime +$totalTime = '{0:HH:mm:ss}' -f ([datetime]$elapsedTime.Ticks) +LogInfo("Execution took [$totalTime]") +LogInfo('############################################') +LogInfo('# Exiting Initialize-LinuxSoftware.ps1 #') +LogInfo('############################################') + +return 0 +#endregion diff --git a/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/src/Install-LinuxPowerShell.sh b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/src/Install-LinuxPowerShell.sh new file mode 100644 index 000000000..611be6983 --- /dev/null +++ b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/max/src/Install-LinuxPowerShell.sh @@ -0,0 +1,43 @@ +# Source: https://learn.microsoft.com/en-us/powershell/scripting/install/install-ubuntu?view=powershell-7.4 + +echo '###########################################' +echo '# Entering Install-LinuxPowerShell.sh #' +echo '###########################################' + +echo '1. Update the list of packages' +sudo apt-get update + +echo '2. Install pre-requisite packages' +sudo apt-get install -y wget apt-transport-https software-properties-common + +echo '3. Get the version of Ubuntu' +# . /etc/os-release - does not work (yet) for image version 23.04. The package is available, but does not contain pwsh +VERSION_ID='22.04' + +echo '4. Determine URL' +url=https://packages.microsoft.com/config/ubuntu/$VERSION_ID/packages-microsoft-prod.deb +echo " Found URL [$url]" + +echo '5. Download the Microsoft repository GPG keys' +wget -q $url + +echo '6. Register the Microsoft repository GPG keys' +sudo dpkg -i packages-microsoft-prod.deb + +echo '7. Delete the Microsoft repository keys file' +rm packages-microsoft-prod.deb + +echo '8. Update the list of products' +sudo apt-get update + +echo '9. Enable the "universe" repositories' +sudo add-apt-repository universe -y + +echo '10. Install PowerShell' +sudo apt-get install -y powershell + +echo '##########################################' +echo '# Exiting Install-LinuxPowerShell.sh #' +echo '##########################################' + +exit 0 diff --git a/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/waf-aligned/dependencies.bicep b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 000000000..5869d0216 --- /dev/null +++ b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,121 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Shared Image Gallery to create.') +param galleryName string + +@description('Required. The name of the Image Definition to create in the Shared Image Gallery.') +param sigImageDefinitionName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Optional. The name of the Virtual Network to create.') +param virtualNetworkName string + +// Roles +resource contributorRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: 'b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor + scope: tenant() +} +resource managedIdentityOperatorRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: 'f1a07417-d97a-45cb-824c-7a7467783830' // Managed Identity Operator + scope: tenant() +} + +// Resources +resource imageManagedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +var addressPrefix = '10.0.0.0/16' + +resource gallery 'Microsoft.Compute/galleries@2022-03-03' = { + name: galleryName + location: location + properties: {} +} + +resource galleryImageDefinition 'Microsoft.Compute/galleries/images@2022-03-03' = { + name: sigImageDefinitionName + location: location + parent: gallery + properties: { + architecture: 'x64' + hyperVGeneration: 'V2' + identifier: { + offer: 'Windows-11' + publisher: 'MicrosoftWindowsDesktop' + sku: 'Win11-AVD-g2' + } + osState: 'Generalized' + osType: 'Windows' + recommended: { + memory: { + max: 16 + min: 4 + } + vCPUs: { + max: 8 + min: 2 + } + } + } +} + +// Assign permissions to MSI to be allowed to distribute images. Ref: https://learn.microsoft.com/en-us/azure/virtual-machines/linux/image-builder-permissions-cli#allow-vm-image-builder-to-distribute-images +resource imageContributorRbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, contributorRole.id, imageManagedIdentity.id) + properties: { + roleDefinitionId: contributorRole.id + principalId: imageManagedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +// Assign permission to allow AIB to assign the list of User Assigned Identities to the Build VM. +resource imageManagedIdentityOperatorRbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, managedIdentityOperatorRole.id, imageManagedIdentity.id) + properties: { + roleDefinitionId: managedIdentityOperatorRole.id + principalId: imageManagedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + privateLinkServiceNetworkPolicies: 'Disabled' + } + } + ] + } +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityResourceId string = imageManagedIdentity.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = imageManagedIdentity.properties.principalId + +@description('The name of the created Managed Identity.') +output managedIdentityName string = imageManagedIdentity.name + +@description('The resource ID of the created Image Definition.') +output sigImageDefinitionId string = galleryImageDefinition.id + +@description('The subnet resource id of the defaultSubnet of the created Virtual Network.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/waf-aligned/main.test.bicep b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 000000000..25528d5fd --- /dev/null +++ b/avm/1.1.0/res/virtual-machine-images/image-template/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,87 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-virtualmachineimages.imagetemplates-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'vmiitwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + sigImageDefinitionName: 'dep-${namePrefix}-imgd-${serviceShort}' + galleryName: 'dep${namePrefix}sig${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // +// No idempotency test as the resource is, by design, not idempotent. +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + customizationSteps: [ + { + restartTimeout: '10m' + type: 'WindowsRestart' + } + ] + imageSource: { + offer: 'Windows-11' + publisher: 'MicrosoftWindowsDesktop' + sku: 'win11-22h2-avd' + type: 'PlatformImage' + version: 'latest' + } + subnetResourceId: nestedDependencies.outputs.subnetResourceId + distributions: [ + { + type: 'SharedImage' + sharedImageGalleryImageDefinitionResourceId: nestedDependencies.outputs.sigImageDefinitionId + } + ] + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +} diff --git a/avm/1.1.0/res/virtual-machine-images/image-template/version.json b/avm/1.1.0/res/virtual-machine-images/image-template/version.json new file mode 100644 index 000000000..04a0dd1a8 --- /dev/null +++ b/avm/1.1.0/res/virtual-machine-images/image-template/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.5", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/carmlVersionTracking.md b/avm/carmlVersionTracking.md index 5bd2c1f81..f1805c8a2 100644 --- a/avm/carmlVersionTracking.md +++ b/avm/carmlVersionTracking.md @@ -8,3 +8,4 @@ Mapping of AVD accelerator code and CARML module versions CARML version | Clone date | Comments ---|---|--- 1.0.0 | 06/07/2024 | intial copy for AVM migration +1.1.0 | 02/21/2025 | Update diff --git a/workload/bicep/modules/azureNetappFiles/deploy.bicep b/workload/bicep/modules/azureNetappFiles/deploy.bicep index bb85d48f8..519e975eb 100644 --- a/workload/bicep/modules/azureNetappFiles/deploy.bicep +++ b/workload/bicep/modules/azureNetappFiles/deploy.bicep @@ -14,8 +14,8 @@ param subId string @sys.description('Resource Group Name where to deploy Azure NetApp Files.') param storageObjectsRgName string -// @sys.description('Required, The service providing domain services for Azure Virtual Desktop.') -// param identityServiceProvider string +@sys.description('Required, The service providing domain services for Azure Virtual Desktop.') +param identityServiceProvider string @sys.description('ANF account name.') param anfAccountName string @@ -44,8 +44,8 @@ param kvResourceId string @sys.description('AVD session host domain join credentials.') param domainJoinUserName string -// @sys.description('AVD session host local admin credentials.') -// param vmLocalUserName string +@sys.description('AVD session host local admin credentials.') +param vmLocalUserName string @sys.description('ANF performance tier.') param anfPerformance string @@ -56,46 +56,46 @@ param capacityPoolSize int = 4 @sys.description('ANF volume quota size in GiBs.') param volumeSize int -// @sys.description('Script name for adding storage account to Active Directory.') -// param storageToDomainScript string +@sys.description('Script name for adding storage account to Active Directory.') +param storageToDomainScript string -// @sys.description('URI for the script for adding the storage account to Active Directory.') -// param storageToDomainScriptUri string +@sys.description('URI for the script for adding the storage account to Active Directory.') +param storageToDomainScriptUri string @sys.description('Tags to be applied to resources') param tags object = {} -// @sys.description('Name for management virtual machine. for tools and to join Azure Files to domain.') -// param managementVmName string +@sys.description('Name for management virtual machine. for tools and to join Azure Files to domain.') +param managementVmName string @sys.description('Do not modify, used to set unique value for resource deployment.') param time string = utcNow() +@sys.description('Storage service provider.') +param storageService string + @sys.description('Sets purpose of the storage account.') param storagePurpose string //parameters for domain join -// @sys.description('Sets location of DSC Agent.') -// param dscAgentPackageLocation string +@sys.description('Sets location of DSC Agent.') +param dscAgentPackageLocation string -// @sys.description('Custom OU path for storage.') -// param storageCustomOuPath string +@sys.description('Custom OU path for storage.') +param storageCustomOuPath string @sys.description('OU Storage Path') param ouStgPath string = '' -// @sys.description('Managed Identity Client ID') -// param managedIdentityClientId string - -// @sys.description('storage account FDQN.') -// param storageAccountFqdn string +@sys.description('Managed Identity Client ID') +param managedIdentityClientId string // =========== // // Variable declaration // // =========== // -// var varAzureCloudName = environment().name -// var varAdminUserName = (identityServiceProvider == 'EntraID') ? vmLocalUserName : domainJoinUserName -//var varStorageToDomainScriptArgs = '-DscPath ${dscAgentPackageLocation} -StorageAccountName ${storageAccountName} -StorageAccountRG ${storageObjectsRgName} -StoragePurpose ${storagePurpose} -DomainName ${identityDomainName} -IdentityServiceProvider ${identityServiceProvider} -AzureCloudEnvironment ${varAzureCloudName} -SubscriptionId ${workloadSubsId} -AdminUserName ${varAdminUserName} -CustomOuPath ${storageCustomOuPath} -OUName ${ouStgPath} -ShareName ${fileShareName} -ClientId ${managedIdentityClientId} -SecurityPrincipalName "${varSecurityPrincipalName}" -StorageAccountFqdn ${storageAccountFqdn} ' +var varAzureCloudName = environment().name +var varAdminUserName = (identityServiceProvider == 'EntraID') ? vmLocalUserName : domainJoinUserName +var varStorageToDomainScriptArgs = '-StorageService ${storageService} -DscPath ${dscAgentPackageLocation} -StoragePurpose ${storagePurpose} -DomainName ${identityDomainName} -IdentityServiceProvider ${identityServiceProvider} -AzureCloudEnvironment ${varAzureCloudName} -SubscriptionId ${workloadSubsId} -AdminUserName ${varAdminUserName} -CustomOuPath ${storageCustomOuPath} -OUName ${ouStgPath} -ShareName ${fileShareName} -ClientId ${managedIdentityClientId} -SecurityPrincipalName "${varSecurityPrincipalName}" -StorageFqdn ${StorageFqdn} ' var varKvSubId = split(kvResourceId, '/')[2] var varKvRgName = split(kvResourceId, '/')[4] var varKvName = split(kvResourceId, '/')[8] diff --git a/workload/scripts/DSCStorageScripts/1.0.3/Configuration.ps1 b/workload/scripts/DSCStorageScripts/1.0.3/Configuration.ps1 index cd600392c..670ce8d37 100644 --- a/workload/scripts/DSCStorageScripts/1.0.3/Configuration.ps1 +++ b/workload/scripts/DSCStorageScripts/1.0.3/Configuration.ps1 @@ -10,9 +10,13 @@ param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] + [string] $StorageService, + + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] [string] $StorageAccountName, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string] $StorageAccountRG, @@ -62,7 +66,7 @@ param [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [string] $StorageAccountFqdn, + [string] $StorageFqdn, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] @@ -76,9 +80,13 @@ Configuration DomainJoinFileShare ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] + [string] $StorageService, + + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] [string] $StorageAccountName, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string] $StorageAccountRG, @@ -128,7 +136,7 @@ Configuration DomainJoinFileShare [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [string] $StorageAccountFqdn, + [string] $StorageFqdn, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] @@ -163,7 +171,7 @@ Configuration DomainJoinFileShare . (Join-Path $using:ScriptPath "Logger.ps1") try { Write-Log "DSC DomainJoinStorage SetScript Domain joining storage account $Using:StorageAccountName" - & "$using:ScriptPath\Script-DomainJoinStorage.ps1" -StorageAccountName $Using:StorageAccountName -StorageAccountRG $Using:StorageAccountRG -SubscriptionId $Using:SubscriptionId -ClientId $Using:ClientId -SecurityPrincipalName $Using:SecurityPrincipalName -ShareName $Using:ShareName -DomainName $Using:DomainName -IdentityServiceProvider $Using:IdentityServiceProvider -AzureCloudEnvironment $Using:AzureCloudEnvironment -CustomOuPath $Using:CustomOuPath -OUName $Using:OUName -StoragePurpose $Using:StoragePurpose -StorageAccountFqdn $Using:StorageAccountFqdn + & "$using:ScriptPath\Script-DomainJoinStorage.ps1" -StorageAccountName $Using:StorageAccountName -StorageAccountRG $Using:StorageAccountRG -SubscriptionId $Using:SubscriptionId -ClientId $Using:ClientId -SecurityPrincipalName $Using:SecurityPrincipalName -ShareName $Using:ShareName -DomainName $Using:DomainName -IdentityServiceProvider $Using:IdentityServiceProvider -AzureCloudEnvironment $Using:AzureCloudEnvironment -CustomOuPath $Using:CustomOuPath -OUName $Using:OUName -StoragePurpose $Using:StoragePurpose -StorageFqdn $Using:StorageFqdn Write-Log "Successfully domain joined and/or NTFS permission set on Storage account" } @@ -217,4 +225,4 @@ $config = @{ ) } -DomainJoinFileShare -ConfigurationData $config -StorageAccountName $StorageAccountName -StorageAccountRG $StorageAccountRG -SubscriptionId $SubscriptionId -ShareName $ShareName -DomainName $DomainName -IdentityServiceProvider $IdentityServiceProvider -AzureCloudEnvironment $AzureCloudEnvironment -CustomOuPath $CustomOuPath -OUName $OUName -AdminUserName $AdminUserName -AdminUserPassword $AdminUserPassword -ClientId $ClientId -SecurityPrincipalName $SecurityPrincipalName -StoragePurpose $StoragePurpose -StorageAccountFqdn $StorageAccountFqdn -Verbose; \ No newline at end of file +DomainJoinFileShare -ConfigurationData $config -StorageAccountName $StorageAccountName -StorageAccountRG $StorageAccountRG -SubscriptionId $SubscriptionId -ShareName $ShareName -DomainName $DomainName -IdentityServiceProvider $IdentityServiceProvider -AzureCloudEnvironment $AzureCloudEnvironment -CustomOuPath $CustomOuPath -OUName $OUName -AdminUserName $AdminUserName -AdminUserPassword $AdminUserPassword -ClientId $ClientId -SecurityPrincipalName $SecurityPrincipalName -StoragePurpose $StoragePurpose -StorageFqdn $StorageFqdn -Verbose; \ No newline at end of file diff --git a/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 b/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 index 7b1ec5120..1b386ffba 100644 --- a/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 +++ b/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 @@ -8,9 +8,13 @@ param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] + [string] $StorageService, + + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] [string] $StorageAccountName, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string] $StorageAccountRG, @@ -52,7 +56,7 @@ param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [string] $StorageAccountFqdn, + [string] $StorageFqdn, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] @@ -81,7 +85,7 @@ Install-Module -Name Az.Storage -Force Install-Module -Name Az.Network -Force Install-Module -Name Az.Resources -Force -if ($IdentityServiceProvider -eq 'ADDS') { +if ($IdentityServiceProvider -eq 'ADDS' && $StorageService -eq 'AzureFiles') { Write-Log "Installing AzFilesHybrid module" $AzFilesZipLocation = Get-ChildItem -Path $PSScriptRoot -Filter "AzFilesHybrid*.zip" Expand-Archive $AzFilesZipLocation.FullName -DestinationPath $PSScriptRoot -Force @@ -90,7 +94,7 @@ if ($IdentityServiceProvider -eq 'ADDS') { & $AzFilesHybridPath } -if ($IdentityServiceProvider -eq 'ADDS') { +if ($IdentityServiceProvider -eq 'ADDS' && $StorageService -eq 'AzureFiles') { # Please note: ActiveDirectory powershell module is only available on AD joined machines. # To install it, RSAT administrative tools must be installed on the VM which will # install the ActiveDirectory powershell module. AzFilesHybrid module takes care of @@ -114,7 +118,7 @@ Connect-AzAccount -Identity -AccountId $ClientId Write-Log "Setting Azure subscription to $SubscriptionId" Select-AzSubscription -SubscriptionId $SubscriptionId -if ($IdentityServiceProvider -eq 'ADDS') { +if ($IdentityServiceProvider -eq 'ADDS' && $StorageService -eq 'AzureFiles') { Write-Log "Domain joining storage account $StorageAccountName in Resource group $StorageAccountRG" if ( $CustomOuPath -eq 'true') { #Join-AzStorageAccountForAuth -ResourceGroupName $StorageAccountRG -StorageAccountName $StorageAccountName -DomainAccountType 'ComputerAccount' -OrganizationalUnitDistinguishedName $OUName -OverwriteExistingADObject @@ -134,12 +138,12 @@ if ($StoragePurpose -eq 'fslogix') { if ($StoragePurpose -eq 'AppAttach') { $DriveLetter = 'X' } -Write-Log "Mounting $StoragePurpose storage account on Drive $DriveLetter" +Write-Log "Mounting $StoragePurpose storage on Drive $DriveLetter" -$FileShareLocation = '\\' + $StorageAccountFqdn + '\' + $ShareName -$connectTestResult = Test-NetConnection -ComputerName $StorageAccountFqdn -Port 445 +$FileShareLocation = '\\' + $StorageFqdn + '\' + $ShareName +$connectTestResult = Test-NetConnection -ComputerName $StorageFqdn -Port 445 -Write-Log "Test connection access to port 445 for $StorageAccountFqdn was $connectTestResult" +Write-Log "Test connection access to port 445 for $StorageFqdn was $connectTestResult" Try { Write-Log "Mounting Profile storage $StorageAccountName as a drive $DriveLetter" diff --git a/workload/scripts/Manual-DSC-Storage-Scripts.ps1 b/workload/scripts/Manual-DSC-Storage-Scripts.ps1 index 5916a7148..00c98ccc7 100644 --- a/workload/scripts/Manual-DSC-Storage-Scripts.ps1 +++ b/workload/scripts/Manual-DSC-Storage-Scripts.ps1 @@ -1,13 +1,17 @@ param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [string] $DscPath, + [string] $StorageService, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] + [string] $DscPath, + + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] [string] $StorageAccountName, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string] $StorageAccountRG, @@ -57,11 +61,12 @@ param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [string] $StorageAccountFqdn, + [string] $StorageFqdn, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] $StoragePurpose + ) if ($IdentityServiceProvider -ne 'EntraIDKerberos') { @@ -133,7 +138,7 @@ function Set-EscapeCharacters { } $AdminUserPasswordEscaped = Set-EscapeCharacters $AdminUserPassword -$DscCompileCommand = "./Configuration.ps1 -StorageAccountName """ + $StorageAccountName + """ -StorageAccountRG """ + $StorageAccountRG + """ -StoragePurpose """ + $StoragePurpose + """ -StorageAccountFqdn """ + $StorageAccountFqdn + """ -ShareName """ + $ShareName + """ -SubscriptionId """ + $SubscriptionId + """ -ClientId """ + $ClientId + """ -SecurityPrincipalName """ + $SecurityPrincipalName + """ -DomainName """ + $DomainName + """ -IdentityServiceProvider """ + $IdentityServiceProvider + """ -AzureCloudEnvironment """ + $AzureCloudEnvironment + """ -CustomOuPath " + $CustomOuPath + " -OUName """ + $OUName + """ -AdminUserName """ + $AdminUserName + """ -AdminUserPassword """ + $AdminUserPasswordEscaped + """ -Verbose" +$DscCompileCommand = "./Configuration.ps1 -StorageService """ + $StorageService + """ -StorageAccountName """ + $StorageAccountName + """ -StorageAccountRG """ + $StorageAccountRG + """ -StoragePurpose """ + $StoragePurpose + """ -StorageFqdn """ + $StorageFqdn + """ -ShareName """ + $ShareName + """ -SubscriptionId """ + $SubscriptionId + """ -ClientId """ + $ClientId + """ -SecurityPrincipalName """ + $SecurityPrincipalName + """ -DomainName """ + $DomainName + """ -IdentityServiceProvider """ + $IdentityServiceProvider + """ -AzureCloudEnvironment """ + $AzureCloudEnvironment + """ -CustomOuPath " + $CustomOuPath + " -OUName """ + $OUName + """ -AdminUserName """ + $AdminUserName + """ -AdminUserPassword """ + $AdminUserPasswordEscaped + """ -Verbose" Write-Host "Executing the command $DscCompileCommand" Invoke-Expression -Command $DscCompileCommand From b9c3af1bcd8238778cdba461b10b0bff1fe8a6e0 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Mon, 24 Mar 2025 12:38:59 -0500 Subject: [PATCH 03/55] updates --- workload/bicep/modules/azureNetappFiles/deploy.bicep | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/workload/bicep/modules/azureNetappFiles/deploy.bicep b/workload/bicep/modules/azureNetappFiles/deploy.bicep index 519e975eb..9b6f66e41 100644 --- a/workload/bicep/modules/azureNetappFiles/deploy.bicep +++ b/workload/bicep/modules/azureNetappFiles/deploy.bicep @@ -14,6 +14,9 @@ param subId string @sys.description('Resource Group Name where to deploy Azure NetApp Files.') param storageObjectsRgName string +@sys.description('Resource Group Name for management VM and keyvault.') +param serviceObjectsRgName string + @sys.description('Required, The service providing domain services for Azure Virtual Desktop.') param identityServiceProvider string @@ -159,17 +162,17 @@ module azureNetAppFiles '../../../../avm/1.1.0/res/net-app/net-app-account/main. // Custom Extension call in on the DSC script to set NTFS permissions. module addShareToDomainScript './.bicep/azureFilesDomainJoin.bicep' = { - scope: resourceGroup('${workloadSubsId}', '${serviceObjectsRgName}') + scope: resourceGroup('${subId}', '${serviceObjectsRgName}') name: 'Add-${storagePurpose}-Storage-Setup-${time}' params: { location: location virtualMachineName: managementVmName file: storageToDomainScript scriptArguments: varStorageToDomainScriptArgs - adminUserPassword: (identityServiceProvider == 'EntraID') ? avdWrklKeyVaultget.getSecret('vmLocalUserPassword') : + adminUserPassword: (identityServiceProvider == 'EntraID') ? keyVaultget.getSecret('vmLocalUserPassword') : '' baseScriptUri: storageToDomainScriptUri } dependsOn: [ - storageAndFile + azureNetAppFiles ] } From 807cf2c1effcb748751ff078151e643eaca2c134 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Mon, 24 Mar 2025 14:01:01 -0500 Subject: [PATCH 04/55] updates --- workload/bicep/deploy-baseline.bicep | 94 ++++++--- .../.bicep/managementVm.bicep | 183 ------------------ .../modules/azureNetappFiles/deploy.bicep | 37 ++-- .../managementVm.bicep | 2 +- .../smbUtilities.bicep} | 2 +- .../.bicep/azureFilesDomainJoin.bicep | 52 ----- .../modules/storageAzureFiles/deploy.bicep | 2 +- 7 files changed, 92 insertions(+), 280 deletions(-) delete mode 100644 workload/bicep/modules/azureNetappFiles/.bicep/managementVm.bicep rename workload/bicep/modules/{storageAzureFiles/.bicep => sharedModules}/managementVm.bicep (98%) rename workload/bicep/modules/{azureNetappFiles/.bicep/azureFilesDomainJoin.bicep => sharedModules/smbUtilities.bicep} (93%) delete mode 100644 workload/bicep/modules/storageAzureFiles/.bicep/azureFilesDomainJoin.bicep diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index 919e0c4e3..58d431a68 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -144,6 +144,9 @@ param existingVnetAvdSubnetResourceId string = '' @sys.description('Existing virtual network subnet for private endpoints. (Default: "")') param existingVnetPrivateEndpointSubnetResourceId string = '' +@sys.description('Existing virtual network subnet for ANF. (Default: "")') +param existingVnetAnfSubnetResourceId string = '' + @sys.description('Existing hub virtual network for perring. (Default: "")') param existingHubVnetResourceId string = '' @@ -156,6 +159,9 @@ param vNetworkAvdSubnetAddressPrefix string = '10.10.1.0/24' @sys.description('private endpoints virtual network subnet address prefix. (Default: 10.10.2.0/27)') param vNetworkPrivateEndpointSubnetAddressPrefix string = '10.10.2.0/27' +@sys.description('ANF virtual network subnet address prefix. (Default: 10.10.3.0/26)') +param vNetworkAnfSubnetAddressPrefix string = '10.10.3.0/26' + @sys.description('custom DNS servers IPs. (Default: "")') param customDnsIps string = '' @@ -187,7 +193,14 @@ param avdVnetPrivateDnsZoneKeyvaultId string = '' param vNetworkGatewayOnHub bool = false @sys.description('Deploy Fslogix setup. (Default: true)') -param createAvdFslogixDeployment bool = true +param createFslogixDeployment bool = true + +@allowed([ + 'ANF' // Azure NetApp Files + 'AzureFiles' // Storage account +]) +@sys.description('Type of storage service to deploy for FSLogix. (Default: AzureFiles)') +param smbStorageType string = 'AzureFiles' @sys.description('Deploy App Attach setup. (Default: false)') param createAppAttachDeployment bool = false @@ -255,15 +268,23 @@ param zoneRedundantStorage bool = false 'Standard' 'Premium' ]) -@sys.description('Storage account SKU for FSLogix storage. Recommended tier is Premium (Default: Premium)') -param fslogixStoragePerformance string = 'Premium' +@sys.description('SKU for FSLogix storage. Recommended tier is Premium for storage account. (Default: Premium)') +param fslogixStorageAccountPerformance string = 'Premium' + +@allowed([ + 'Standard' + 'Premium' +]) +@sys.description('SKU for App Attach storage. Recommended tier is Premium for storage account. (Default: Premium)') +param appAttachStorageAccountPerformance string = 'Premium' @allowed([ 'Standard' 'Premium' + 'Ultra' ]) -@sys.description('Storage account SKU for App Attach storage. Recommended tier is Premium. (Default: Premium)') -param appAttachStoragePerformance string = 'Premium' +@sys.description('SKU for App Attach and FSLogix ANF storage. (Default: Standard)') +param anfPerformance string = 'Standard' @sys.description('Enables a zero trust configuration on the session host disks. (Default: false)') param diskZeroTrust bool = false @@ -311,7 +332,7 @@ param avdCustomImageDefinitionId string = '' @sys.description('Management VM image SKU (Default: winServer_2022_Datacenter_smalldisk_g2)') param managementVmOsImage string = 'winServer_2022_Datacenter_smalldisk_g2' -@sys.description('OU name for Azure Storage Account. It is recommended to create a new AD Organizational Unit (OU) in AD and disable password expiration policy on computer accounts or service logon accounts accordingly. (Default: "")') +@sys.description('OU name for Azure Storage Account or Azure Netapp Files. It is recommended to create a new AD Organizational Unit (OU) in AD and disable password expiration policy on computer accounts or service logon accounts accordingly. (Default: "")') param storageOuPath string = '' // Custom Naming @@ -355,6 +376,10 @@ param avdVnetworkSubnetCustomName string = 'snet-avd-app1-dev-use2-001' @sys.description('private endpoints virtual network subnet custom name. (Default: snet-pe-app1-dev-use2-001)') param privateEndpointVnetworkSubnetCustomName string = 'snet-pe-app1-dev-use2-001' +@maxLength(80) +@sys.description('ANF virtual network subnet custom name. (Default: snet-anf-app1-dev-use2-001)') +param anfVnetworkSubnetCustomName string = 'snet-anf-app1-dev-use2-001' + @maxLength(80) @sys.description('AVD network security group custom name. (Default: nsg-avd-app1-dev-use2-001)') param avdNetworksecurityGroupCustomName string = 'nsg-avd-app1-dev-use2-001' @@ -363,6 +388,10 @@ param avdNetworksecurityGroupCustomName string = 'nsg-avd-app1-dev-use2-001' @sys.description('Private endpoint network security group custom name. (Default: nsg-pe-app1-dev-use2-001)') param privateEndpointNetworksecurityGroupCustomName string = 'nsg-pe-app1-dev-use2-001' +@maxLength(80) +@sys.description('ANF network security group custom name. (Default: nsg-anf-app1-dev-use2-001)') +param anfNetworksecurityGroupCustomName string = 'nsg-anf-app1-dev-use2-001' + @maxLength(80) @sys.description('AVD route table custom name. (Default: route-avd-app1-dev-use2-001)') param avdRouteTableCustomName string = 'route-avd-app1-dev-use2-001' @@ -415,6 +444,9 @@ param avdSessionHostCustomNamePrefix string = 'vmapp1duse2' @sys.description('AVD FSLogix and App Attach storage account prefix custom name. (Default: st)') param storageAccountPrefixCustomName string = 'st' +@sys.description('AVD FSLogix and App Attach storage account prefix custom name. (Default: anf-acc-app1-dev-use2-001)') +param anfAccountCustomName string = 'anf-acc-app1-dev-use2-001' + @sys.description('FSLogix file share name. (Default: fslogix-pc-app1-dev-001)') param fslogixFileShareCustomName string = 'fslogix-pc-app1-dev-use2-001' @@ -586,12 +618,18 @@ var varVnetAvdSubnetName = avdUseCustomNaming var varVnetPrivateEndpointSubnetName = avdUseCustomNaming ? privateEndpointVnetworkSubnetCustomName : 'snet-pe-${varComputeStorageResourcesNamingStandard}-001' +var varVnetAnfSubnetName = avdUseCustomNaming + ? anfVnetworkSubnetCustomName + : 'snet-anf-${varComputeStorageResourcesNamingStandard}-001' var varAvdNetworksecurityGroupName = avdUseCustomNaming ? avdNetworksecurityGroupCustomName : 'nsg-avd-${varComputeStorageResourcesNamingStandard}-001' var varPrivateEndpointNetworksecurityGroupName = avdUseCustomNaming ? privateEndpointNetworksecurityGroupCustomName : 'nsg-pe-${varComputeStorageResourcesNamingStandard}-001' +var varAnfNetworksecurityGroupName = avdUseCustomNaming + ? anfNetworksecurityGroupCustomName + : 'nsg-anf-${varComputeStorageResourcesNamingStandard}-001' var varAvdRouteTableName = avdUseCustomNaming ? avdRouteTableCustomName : 'route-avd-${varComputeStorageResourcesNamingStandard}-001' @@ -649,10 +687,10 @@ var varAppAttachFileShareName = avdUseCustomNaming var varFslogixStorageName = avdUseCustomNaming ? '${storageAccountPrefixCustomName}fsl${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' : 'stfsl${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' -var varFslogixStorageFqdn = createAvdFslogixDeployment - ? '${varFslogixStorageName}.file.${environment().suffixes.storage}' - : '' -var varAppAttachStorageFqdn = '${varAppAttachStorageName}.file.${environment().suffixes.storage}' +var varAnfAccountName = avdUseCustomNaming ? anfAccountCustomName : 'anf-acc-${varComputeStorageResourcesNamingStandard}-001' +var varAnfCapacityPoolName = 'anf-cpool-${varComputeStorageResourcesNamingStandard}-001' +var varFslogixStorageFqdn = createFslogixDeployment ? ((smbStorageType == 'AzureFiles') ? '${varFslogixStorageName}.file.${environment().suffixes.storage}' : (smbStorageType == 'ANF') ? '${varFslogixFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' +var varAppAttachStorageFqdn = createAppAttachDeployment ? ((smbStorageType == 'AzureFiles') ? '${varAppAttachStorageName}.file.${environment().suffixes.storage}' : (smbStorageType == 'ANF') ? '${varAppAttachFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' var varAppAttachStorageName = avdUseCustomNaming ? '${storageAccountPrefixCustomName}appa${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' : 'stappa${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' @@ -666,19 +704,19 @@ var varZtKvName = avdUseCustomNaming : 'kv-key-${varComputeStorageResourcesNamingStandard}-${varNamingUniqueStringTwoChar}' // max length limit 24 characters var varZtKvPrivateEndpointName = 'pe-${varZtKvName}-vault' // -var varFslogixSharePath = createAvdFslogixDeployment +var varFslogixSharePath = createFslogixDeployment ? '\\\\${varFslogixStorageName}.file.${environment().suffixes.storage}\\${varFslogixFileShareName}' : '' var varBaseScriptUri = 'https://raw.githubusercontent.com/azure/avdaccelerator/main/workload/' var varSessionHostConfigurationScriptUri = '${varBaseScriptUri}scripts/Set-SessionHostConfiguration.ps1' var varSessionHostConfigurationScript = 'Set-SessionHostConfiguration.ps1' -var varCreateStorageDeployment = (createAvdFslogixDeployment || varCreateAppAttachDeployment == true) ? true : false +var varCreateStorageDeployment = (createFslogixDeployment || varCreateAppAttachDeployment == true) ? true : false var varFslogixStorageSku = zoneRedundantStorage - ? '${fslogixStoragePerformance}_ZRS' - : '${fslogixStoragePerformance}_LRS' + ? '${fslogixStorageAccountPerformance}_ZRS' + : '${fslogixStorageAccountPerformance}_LRS' var varAppAttachStorageSku = zoneRedundantStorage - ? '${appAttachStoragePerformance}_ZRS' - : '${appAttachStoragePerformance}_LRS' + ? '${fslogixStorageAccountPerformance}_ZRS' + : '${fslogixStorageAccountPerformance}_LRS' var varMgmtVmSpecs = { osImage: varMarketPlaceGalleryWindows[managementVmOsImage] osDiskType: 'Standard_LRS' @@ -1095,7 +1133,7 @@ module monitoringDiagnosticSettings './modules/avdInsightsMonitoring/deploy.bice computeObjectsRgName: varComputeObjectsRgName serviceObjectsRgName: varServiceObjectsRgName dataCollectionRulesName: varDataCollectionRulesName - storageObjectsRgName: (createAvdFslogixDeployment || createAppAttachDeployment) ? varStorageObjectsRgName : '' + storageObjectsRgName: (createFslogixDeployment || createAppAttachDeployment) ? varStorageObjectsRgName : '' networkObjectsRgName: (createAvdVnet) ? varNetworkObjectsRgName : '' monitoringRgName: varMonitoringRgName deployCustomPolicyMonitoring: deployCustomPolicyMonitoring @@ -1113,11 +1151,11 @@ module monitoringDiagnosticSettings './modules/avdInsightsMonitoring/deploy.bice } // Networking -module networking './modules/networking/deploy.bicep' = if (createAvdVnet || createPrivateDnsZones || avdDeploySessionHosts || createAvdFslogixDeployment || varCreateAppAttachDeployment) { +module networking './modules/networking/deploy.bicep' = if (createAvdVnet || createPrivateDnsZones || avdDeploySessionHosts || createFslogixDeployment || varCreateAppAttachDeployment) { name: 'Networking-${time}' params: { createVnet: createAvdVnet - deployAsg: (avdDeploySessionHosts || createAvdFslogixDeployment || varCreateAppAttachDeployment) ? true : false + deployAsg: (avdDeploySessionHosts || createFslogixDeployment || varCreateAppAttachDeployment) ? true : false existingAvdSubnetResourceId: existingVnetAvdSubnetResourceId createPrivateDnsZones: (deployPrivateEndpointKeyvaultStorage || deployAvdPrivateLinkService) ? createPrivateDnsZones @@ -1126,6 +1164,7 @@ module networking './modules/networking/deploy.bicep' = if (createAvdVnet || cre computeObjectsRgName: varComputeObjectsRgName networkObjectsRgName: varNetworkObjectsRgName avdNetworksecurityGroupName: varAvdNetworksecurityGroupName + anfNetworksecurityGroupName: varAnfNetworksecurityGroupName privateEndpointNetworksecurityGroupName: varPrivateEndpointNetworksecurityGroupName avdRouteTableName: varAvdRouteTableName privateEndpointRouteTableName: varPrivateEndpointRouteTableName @@ -1135,16 +1174,19 @@ module networking './modules/networking/deploy.bicep' = if (createAvdVnet || cre remoteVnetPeeringName: varRemoteVnetPeeringName vnetAvdSubnetName: varVnetAvdSubnetName vnetPrivateEndpointSubnetName: varVnetPrivateEndpointSubnetName + vnetAnfSubnetName: varVnetAnfSubnetName createVnetPeering: varCreateVnetPeering deployDDoSNetworkProtection: deployDDoSNetworkProtection ddosProtectionPlanName: varDDosProtectionPlanName deployPrivateEndpointSubnet: (deployPrivateEndpointKeyvaultStorage || deployAvdPrivateLinkService) ? true : false //adding logic that will be used when also including AVD control plane PEs + deployAnfSubnet: smbStorageType == 'ANF' ? true : false deployAvdPrivateLinkService: deployAvdPrivateLinkService vNetworkGatewayOnHub: vNetworkGatewayOnHub existingHubVnetResourceId: existingHubVnetResourceId location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation vnetAvdSubnetAddressPrefix: vNetworkAvdSubnetAddressPrefix vnetPrivateEndpointSubnetAddressPrefix: vNetworkPrivateEndpointSubnetAddressPrefix + vnetAnfSubnetAddressPrefix: vNetworkAnfSubnetAddressPrefix workloadSubsId: avdWorkloadSubsId dnsServers: varDnsServers tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags @@ -1390,14 +1432,14 @@ module wrklKeyVault '../../avm/1.0.0/res/key-vault/vault/main.bicep' = { } // Management VM deployment -module managementVm './modules/storageAzureFiles/.bicep/managementVm.bicep' = if (avdIdentityServiceProvider != 'EntraID' && (createAvdFslogixDeployment || varCreateAppAttachDeployment)) { +module managementVm './modules/sharedModules/managementVm.bicep' = if (avdIdentityServiceProvider != 'EntraID' && (createFslogixDeployment || varCreateAppAttachDeployment)) { name: 'Storage-MGMT-VM-${time}' params: { diskEncryptionSetResourceId: diskZeroTrust ? zeroTrust.outputs.ztDiskEncryptionSetResourceId : '' identityServiceProvider: avdIdentityServiceProvider managementVmName: varManagementVmName computeTimeZone: varTimeZoneSessionHosts - applicationSecurityGroupResourceId: (avdDeploySessionHosts || createAvdFslogixDeployment || varCreateAppAttachDeployment) + applicationSecurityGroupResourceId: (avdDeploySessionHosts || createFslogixDeployment || varCreateAppAttachDeployment) ? '${networking.outputs.applicationSecurityGroupResourceId}' : '' domainJoinUserName: avdDomainJoinUserName @@ -1429,13 +1471,13 @@ module managementVm './modules/storageAzureFiles/.bicep/managementVm.bicep' = if } // FSLogix storage -module fslogixAzureFilesStorage './modules/storageAzureFiles/deploy.bicep' = if (createAvdFslogixDeployment) { +module fslogixAzureFilesStorage './modules/storageAzureFiles/deploy.bicep' = if (createFslogixDeployment) { name: 'Storage-FSLogix-${time}' params: { storagePurpose: 'fslogix' vmLocalUserName: avdVmLocalUserName fileShareName: varFslogixFileShareName - fileShareMultichannel: (fslogixStoragePerformance == 'Premium') ? true : false + fileShareMultichannel: (fslogixStorageAccountPerformance == 'Premium') ? true : false storageSku: varFslogixStorageSku fileShareQuotaSize: fslogixFileShareQuotaSize storageAccountFqdn: varFslogixStorageFqdn @@ -1490,7 +1532,7 @@ module appAttachAzureFilesStorage './modules/storageAzureFiles/deploy.bicep' = i storagePurpose: 'AppAttach' vmLocalUserName: avdVmLocalUserName fileShareName: varAppAttachFileShareName - fileShareMultichannel: (appAttachStoragePerformance == 'Premium') ? true : false + fileShareMultichannel: (fslogixStorageAccountPerformance == 'Premium') ? true : false storageSku: varAppAttachStorageSku fileShareQuotaSize: appAttachFileShareQuotaSize storageAccountFqdn: varAppAttachStorageFqdn @@ -1563,14 +1605,14 @@ module sessionHosts './modules/avdSessionHosts/deploy.bicep' = [ for i in range(1, varSessionHostBatchCount): if (avdDeploySessionHosts) { name: 'SH-Batch-${i}-${time}' params: { - asgResourceId: (avdDeploySessionHosts || createAvdFslogixDeployment || varCreateAppAttachDeployment) + asgResourceId: (avdDeploySessionHosts || createFslogixDeployment || varCreateAppAttachDeployment) ? '${networking.outputs.applicationSecurityGroupResourceId}' : '' availability: availability availabilityZones: availabilityZones batchId: i - 1 computeObjectsRgName: varComputeObjectsRgName - configureFslogix: createAvdFslogixDeployment + configureFslogix: createFslogixDeployment count: i == varSessionHostBatchCount && varMaxSessionHostsDivisionRemainderValue > 0 ? varMaxSessionHostsDivisionRemainderValue : varMaxSessionHostsPerTemplate diff --git a/workload/bicep/modules/azureNetappFiles/.bicep/managementVm.bicep b/workload/bicep/modules/azureNetappFiles/.bicep/managementVm.bicep deleted file mode 100644 index 82179e075..000000000 --- a/workload/bicep/modules/azureNetappFiles/.bicep/managementVm.bicep +++ /dev/null @@ -1,183 +0,0 @@ -targetScope = 'subscription' - -// ========== // -// Parameters // -// ========== // - -@sys.description('AVD disk encryption set resource ID to enable server side encyption.') -param diskEncryptionSetResourceId string - -@sys.description('AVD workload subscription ID, multiple subscriptions scenario.') -param workloadSubsId string - -@sys.description('Virtual machine time zone.') -param computeTimeZone string - -@sys.description('Required, The service providing domain services for Azure Virtual Desktop.') -param identityServiceProvider string - -@sys.description('Resource Group Name for Azure Files.') -param serviceObjectsRgName string - -@sys.description('AVD subnet ID.') -param subnetId string - -@sys.description('Enable accelerated networking on the session host VMs.') -param enableAcceleratedNetworking bool - -@sys.description('Specifies the securityType of the virtual machine. Must be TrustedLaunch or ConfidentialVM enable UefiSettings.') -param securityType string - -@sys.description('Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings.') -param secureBootEnabled bool - -@sys.description('Specifies whether virtual TPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings.') -param vTpmEnabled bool - -@sys.description('Location where to deploy compute services.') -param location string - -@sys.description('This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs.') -param encryptionAtHost bool - -@sys.description('Session host VM size.') -param mgmtVmSize string - -@sys.description('OS disk type for session host.') -param osDiskType string - -@sys.description('Market Place OS image') -param osImage object - -@sys.description('Storage Managed Identity Resource ID.') -param storageManagedIdentityResourceId string - -@sys.description('Local administrator username.') -param vmLocalUserName string - -@sys.description('Identity domain name.') -param identityDomainName string - -@sys.description('Keyvault name to get credentials from.') -param wrklKvName string - -@sys.description('AVD session host domain join credentials.') -param domainJoinUserName string - -@sys.description('OU path to join AVd VMs.') -param ouPath string - -@sys.description('Application Security Group (ASG) for the session hosts.') -param applicationSecurityGroupResourceId string - -@sys.description('Tags to be applied to resources') -param tags object - -@sys.description('Name for management virtual machine. for tools and to join Azure Files to domain.') -param managementVmName string - -@sys.description('Do not modify, used to set unique value for resource deployment.') -param time string = utcNow() - -// =========== // -// Variable declaration // -// =========== // - -var varManagedDisk = empty(diskEncryptionSetResourceId) ? { - storageAccountType: osDiskType -} : { - diskEncryptionSet: { - id: diskEncryptionSetResourceId - } - storageAccountType: osDiskType -} - -// =========== // -// Deployments // -// =========== // - -// Call on the KV. -resource avdWrklKeyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { - name: wrklKvName - scope: resourceGroup('${workloadSubsId}', '${serviceObjectsRgName}') -} - -// Provision temporary VM and add it to domain. -module managementVm '../../../../../avm/1.0.0/res/compute/virtual-machine/main.bicep' = { - scope: resourceGroup('${workloadSubsId}', '${serviceObjectsRgName}') - name: 'MGMT-VM-${time}' - params: { - name: managementVmName - location: location - timeZone: computeTimeZone - managedIdentities: { - systemAssigned: false - userAssignedResourceIds: [ - storageManagedIdentityResourceId - ] - } - encryptionAtHost: encryptionAtHost - zone: 0 - osType: 'Windows' - vmSize: mgmtVmSize - securityType: securityType - secureBootEnabled: secureBootEnabled - vTpmEnabled: vTpmEnabled - imageReference: osImage - osDisk: { - createOption: 'FromImage' - deleteOption: 'Delete' - caching: 'ReadWrite' - managedDisk: varManagedDisk - } - adminUsername: vmLocalUserName - adminPassword: avdWrklKeyVaultget.getSecret('vmLocalUserPassword') - nicConfigurations: [ - { - name: 'nic-01-${managementVmName}' - deleteOption: 'Delete' - enableAcceleratedNetworking: enableAcceleratedNetworking - ipConfigurations: !empty(applicationSecurityGroupResourceId) ? [ - { - name: 'ipconfig01' - subnetResourceId: subnetId - applicationSecurityGroups: [ - { - id: applicationSecurityGroupResourceId - } - ] - } - ] : [ - { - name: 'ipconfig01' - subnetResourceId: subnetId - } - ] - } - ] - // Join domain - allowExtensionOperations: true - extensionDomainJoinPassword: avdWrklKeyVaultget.getSecret('domainJoinUserPassword') - extensionDomainJoinConfig: { - enabled: (identityServiceProvider == 'EntraID') ? false: true - settings: { - name: identityDomainName - ouPath: !empty(ouPath) ? ouPath : null - user: domainJoinUserName - restart: 'true' - options: '3' - } - } - // Entra ID Join. - extensionAadJoinConfig: { - enabled: (identityServiceProvider == 'EntraID') ? true: false - } - tags: tags - } - dependsOn: [ - ] -} - -// =========== // -// Outputs // -// =========== // diff --git a/workload/bicep/modules/azureNetappFiles/deploy.bicep b/workload/bicep/modules/azureNetappFiles/deploy.bicep index 9b6f66e41..6936ca363 100644 --- a/workload/bicep/modules/azureNetappFiles/deploy.bicep +++ b/workload/bicep/modules/azureNetappFiles/deploy.bicep @@ -80,6 +80,9 @@ param storageService string @sys.description('Sets purpose of the storage account.') param storagePurpose string +@sys.description('Identity name array to grant RBAC role to access AVD application group and NTFS permissions.') +param securityPrincipalName string + //parameters for domain join @sys.description('Sets location of DSC Agent.') param dscAgentPackageLocation string @@ -98,7 +101,9 @@ param managedIdentityClientId string // =========== // var varAzureCloudName = environment().name var varAdminUserName = (identityServiceProvider == 'EntraID') ? vmLocalUserName : domainJoinUserName -var varStorageToDomainScriptArgs = '-StorageService ${storageService} -DscPath ${dscAgentPackageLocation} -StoragePurpose ${storagePurpose} -DomainName ${identityDomainName} -IdentityServiceProvider ${identityServiceProvider} -AzureCloudEnvironment ${varAzureCloudName} -SubscriptionId ${workloadSubsId} -AdminUserName ${varAdminUserName} -CustomOuPath ${storageCustomOuPath} -OUName ${ouStgPath} -ShareName ${fileShareName} -ClientId ${managedIdentityClientId} -SecurityPrincipalName "${varSecurityPrincipalName}" -StorageFqdn ${StorageFqdn} ' +var varSecurityPrincipalName = !empty(securityPrincipalName) ? securityPrincipalName : 'none' +// var varStorageFqdn = azureNetAppFiles ????????????? +// var varStorageToDomainScriptArgs = '-StorageService ${storageService} -DscPath ${dscAgentPackageLocation} -StoragePurpose ${storagePurpose} -DomainName ${identityDomainName} -IdentityServiceProvider ${identityServiceProvider} -AzureCloudEnvironment ${varAzureCloudName} -SubscriptionId ${subId} -AdminUserName ${varAdminUserName} -CustomOuPath ${storageCustomOuPath} -OUName ${ouStgPath} -ShareName ${subId} -ClientId ${managedIdentityClientId} -SecurityPrincipalName "${varSecurityPrincipalName}" -StorageFqdn ${varStorageFqdn} ' var varKvSubId = split(kvResourceId, '/')[2] var varKvRgName = split(kvResourceId, '/')[4] var varKvName = split(kvResourceId, '/')[8] @@ -161,18 +166,18 @@ module azureNetAppFiles '../../../../avm/1.1.0/res/net-app/net-app-account/main. } // Custom Extension call in on the DSC script to set NTFS permissions. -module addShareToDomainScript './.bicep/azureFilesDomainJoin.bicep' = { - scope: resourceGroup('${subId}', '${serviceObjectsRgName}') - name: 'Add-${storagePurpose}-Storage-Setup-${time}' - params: { - location: location - virtualMachineName: managementVmName - file: storageToDomainScript - scriptArguments: varStorageToDomainScriptArgs - adminUserPassword: (identityServiceProvider == 'EntraID') ? keyVaultget.getSecret('vmLocalUserPassword') : '' - baseScriptUri: storageToDomainScriptUri - } - dependsOn: [ - azureNetAppFiles - ] -} +// module addShareToDomainScript '../sharedModules/smbUtilities.bicep' = { +// scope: resourceGroup('${subId}', '${serviceObjectsRgName}') +// name: 'Add-${storagePurpose}-Storage-Setup-${time}' +// params: { +// location: location +// virtualMachineName: managementVmName +// file: storageToDomainScript +// scriptArguments: varStorageToDomainScriptArgs +// adminUserPassword: (identityServiceProvider == 'EntraID') ? keyVaultget.getSecret('vmLocalUserPassword') : '' +// baseScriptUri: storageToDomainScriptUri +// } +// dependsOn: [ +// azureNetAppFiles +// ] +// } diff --git a/workload/bicep/modules/storageAzureFiles/.bicep/managementVm.bicep b/workload/bicep/modules/sharedModules/managementVm.bicep similarity index 98% rename from workload/bicep/modules/storageAzureFiles/.bicep/managementVm.bicep rename to workload/bicep/modules/sharedModules/managementVm.bicep index 7df7aaaee..6ccdbfb07 100644 --- a/workload/bicep/modules/storageAzureFiles/.bicep/managementVm.bicep +++ b/workload/bicep/modules/sharedModules/managementVm.bicep @@ -103,7 +103,7 @@ resource avdWrklKeyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' exist } // Provision temporary VM and add it to domain. -module managementVm '../../../../../avm/1.0.0/res/compute/virtual-machine/main.bicep' = { +module managementVm '../../../../avm/1.0.0/res/compute/virtual-machine/main.bicep' = { scope: resourceGroup('${workloadSubsId}', '${serviceObjectsRgName}') name: 'MGMT-VM-${time}' params: { diff --git a/workload/bicep/modules/azureNetappFiles/.bicep/azureFilesDomainJoin.bicep b/workload/bicep/modules/sharedModules/smbUtilities.bicep similarity index 93% rename from workload/bicep/modules/azureNetappFiles/.bicep/azureFilesDomainJoin.bicep rename to workload/bicep/modules/sharedModules/smbUtilities.bicep index 915a8f45b..c85470bd5 100644 --- a/workload/bicep/modules/azureNetappFiles/.bicep/azureFilesDomainJoin.bicep +++ b/workload/bicep/modules/sharedModules/smbUtilities.bicep @@ -32,7 +32,7 @@ param time string = utcNow() // =========== // // Add Azure Files to AD DS domain. -module dscStorageScript '../../../../../avm/1.0.0/res/compute/virtual-machine/extension/main.bicep' = { +module dscStorageScript '../../../../avm/1.0.0/res/compute/virtual-machine/extension/main.bicep' = { name: 'VM-Ext-AVM-${time}' params: { name: 'AzureFilesDomainJoin' diff --git a/workload/bicep/modules/storageAzureFiles/.bicep/azureFilesDomainJoin.bicep b/workload/bicep/modules/storageAzureFiles/.bicep/azureFilesDomainJoin.bicep deleted file mode 100644 index 915a8f45b..000000000 --- a/workload/bicep/modules/storageAzureFiles/.bicep/azureFilesDomainJoin.bicep +++ /dev/null @@ -1,52 +0,0 @@ -metadata name = 'AVD LZA storage' -metadata description = 'Configures domain join settings on storage account via VM custom script extension' -metadata owner = 'Azure/avdaccelerator' - -// ========== // -// Parameters // -// ========== // - -@sys.description('Virtual machine name.') -param virtualMachineName string - -@sys.description('Location where to deploy compute services.') -param location string - -@sys.description('Location for the AVD agent installation package.') -param baseScriptUri string - -param file string - -@sys.description('Arguments for domain join script.') -param scriptArguments string - -@secure() -@sys.description('Domain join user password.') -param adminUserPassword string - -@sys.description('Do not modify, used to set unique value for resource deployment.') -param time string = utcNow() - -// =========== // -// Deployments // -// =========== // - -// Add Azure Files to AD DS domain. -module dscStorageScript '../../../../../avm/1.0.0/res/compute/virtual-machine/extension/main.bicep' = { - name: 'VM-Ext-AVM-${time}' - params: { - name: 'AzureFilesDomainJoin' - virtualMachineName: virtualMachineName - location: location - publisher: 'Microsoft.Compute' - type: 'CustomScriptExtension' - typeHandlerVersion: '1.10' - autoUpgradeMinorVersion: true - enableAutomaticUpgrade: false - settings: {} - protectedSettings: { - fileUris: array(baseScriptUri) - commandToExecute: 'powershell -ExecutionPolicy Unrestricted -File ${file} ${scriptArguments} -AdminUserPassword ${adminUserPassword} -verbose' - } - } -} diff --git a/workload/bicep/modules/storageAzureFiles/deploy.bicep b/workload/bicep/modules/storageAzureFiles/deploy.bicep index 26565300d..76394aab6 100644 --- a/workload/bicep/modules/storageAzureFiles/deploy.bicep +++ b/workload/bicep/modules/storageAzureFiles/deploy.bicep @@ -212,7 +212,7 @@ module storageAndFile '../../../../avm/1.0.0/res/storage/storage-account/main.bi } // Custom Extension call in on the DSC script to join Azure storage account to domain. -module addShareToDomainScript './.bicep/azureFilesDomainJoin.bicep' = if (identityServiceProvider != 'EntraID') { +module addShareToDomainScript '../sharedModules/smbUtilities.bicep' = if (identityServiceProvider != 'EntraID') { scope: resourceGroup('${workloadSubsId}', '${serviceObjectsRgName}') name: 'Add-${storagePurpose}-Storage-Setup-${time}' params: { From 39c06cd22272cbd3da5a5d9b9d43542c020a7647 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Mon, 24 Mar 2025 14:22:04 -0500 Subject: [PATCH 05/55] updates --- workload/bicep/deploy-baseline.bicep | 54 ++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index 58d431a68..512649f27 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -1470,7 +1470,57 @@ module managementVm './modules/sharedModules/managementVm.bicep' = if (avdIdenti ] } -// FSLogix storage +// FSLogix Azure NetApp Files +module anf './modules/azureNetappFiles/deploy.bicep' = if (createFslogixDeployment && (smbStorageType == 'ANF')) { + name: 'Storage-FSLogix-${time}' + params: { + storagePurpose: 'fslogix' + anfAccountName: varAnfAccountName + anfCapacityPoolName: varAnfCapacityPoolName + anfVolumeName: varFslogixFileShareName + dnsServers: customDnsIps + volumeSize: fslogixFileShareQuotaSize + anfPerformance: anfPerformance + anfSubnetId: createAvdVnet ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAnfSubnetName}' : existingVnetAnfSubnetResourceId + // vmLocalUserName: avdVmLocalUserName + // fileShareName: varFslogixFileShareName + // fileShareMultichannel: (fslogixStoragePerformance == 'Premium') ? true : false + // storageSku: varFslogixStorageSku + // fileShareQuotaSize: fslogixFileShareQuotaSize + // storageAccountFqdn: varFslogixStorageFqdn + // storageAccountName: varFslogixStorageName + // storageToDomainScript: varStorageToDomainScript + // storageToDomainScriptUri: varStorageToDomainScriptUri + // identityServiceProvider: avdIdentityServiceProvider + // dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation + // storageCustomOuPath: varStorageCustomOuPath + // managementVmName: varManagementVmName + // deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage + ouStgPath: varOuStgPath + // managedIdentityClientId: varCreateStorageDeployment ? identity.outputs.managedIdentityStorageClientId : '' + // securityPrincipalName: !empty(securityPrincipalName) ? securityPrincipalName : '' + domainJoinUserName: avdDomainJoinUserName + kvResourceId: wrklKeyVault.outputs.resourceId + serviceObjectsRgName: varServiceObjectsRgName + identityDomainName: identityDomainName + // identityDomainGuid: identityDomainGuid + location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation + storageObjectsRgName: varStorageObjectsRgName + subId: avdWorkloadSubsId + tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags + // alaWorkspaceResourceId: avdDeployMonitoring + // ? (deployAlaWorkspace + // ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId + // : alaExistingWorkspaceResourceId) + // : '' + } + dependsOn: [ + baselineStorageResourceGroup + managementVm + ] +} + +// FSLogix Azure Files module fslogixAzureFilesStorage './modules/storageAzureFiles/deploy.bicep' = if (createFslogixDeployment) { name: 'Storage-FSLogix-${time}' params: { @@ -1525,7 +1575,7 @@ module fslogixAzureFilesStorage './modules/storageAzureFiles/deploy.bicep' = if ] } -// App Attach storage +// App Attach Azure Files module appAttachAzureFilesStorage './modules/storageAzureFiles/deploy.bicep' = if (varCreateAppAttachDeployment) { name: 'Storage-AppA-${time}' params: { From aa9e33376eeab622b8af77d999405a49a3f500b6 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Mon, 24 Mar 2025 15:58:15 -0500 Subject: [PATCH 06/55] updates --- workload/bicep/deploy-baseline.bicep | 29 +++-- .../modules/azureNetappFiles/deploy.bicep | 8 +- .../bicep/modules/networking/deploy.bicep | 118 +++++++++++------- 3 files changed, 88 insertions(+), 67 deletions(-) diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index 512649f27..d15914eb4 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -200,7 +200,7 @@ param createFslogixDeployment bool = true 'AzureFiles' // Storage account ]) @sys.description('Type of storage service to deploy for FSLogix. (Default: AzureFiles)') -param smbStorageType string = 'AzureFiles' +param storageService string = 'AzureFiles' @sys.description('Deploy App Attach setup. (Default: false)') param createAppAttachDeployment bool = false @@ -689,8 +689,8 @@ var varFslogixStorageName = avdUseCustomNaming : 'stfsl${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' var varAnfAccountName = avdUseCustomNaming ? anfAccountCustomName : 'anf-acc-${varComputeStorageResourcesNamingStandard}-001' var varAnfCapacityPoolName = 'anf-cpool-${varComputeStorageResourcesNamingStandard}-001' -var varFslogixStorageFqdn = createFslogixDeployment ? ((smbStorageType == 'AzureFiles') ? '${varFslogixStorageName}.file.${environment().suffixes.storage}' : (smbStorageType == 'ANF') ? '${varFslogixFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' -var varAppAttachStorageFqdn = createAppAttachDeployment ? ((smbStorageType == 'AzureFiles') ? '${varAppAttachStorageName}.file.${environment().suffixes.storage}' : (smbStorageType == 'ANF') ? '${varAppAttachFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' +var varFslogixStorageFqdn = createFslogixDeployment ? ((storageService == 'AzureFiles') ? '${varFslogixStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varFslogixFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' +var varAppAttachStorageFqdn = createAppAttachDeployment ? ((storageService == 'AzureFiles') ? '${varAppAttachStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varAppAttachFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' var varAppAttachStorageName = avdUseCustomNaming ? '${storageAccountPrefixCustomName}appa${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' : 'stappa${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' @@ -1179,7 +1179,7 @@ module networking './modules/networking/deploy.bicep' = if (createAvdVnet || cre deployDDoSNetworkProtection: deployDDoSNetworkProtection ddosProtectionPlanName: varDDosProtectionPlanName deployPrivateEndpointSubnet: (deployPrivateEndpointKeyvaultStorage || deployAvdPrivateLinkService) ? true : false //adding logic that will be used when also including AVD control plane PEs - deployAnfSubnet: smbStorageType == 'ANF' ? true : false + deployAnfSubnet: storageService == 'ANF' ? true : false deployAvdPrivateLinkService: deployAvdPrivateLinkService vNetworkGatewayOnHub: vNetworkGatewayOnHub existingHubVnetResourceId: existingHubVnetResourceId @@ -1471,7 +1471,7 @@ module managementVm './modules/sharedModules/managementVm.bicep' = if (avdIdenti } // FSLogix Azure NetApp Files -module anf './modules/azureNetappFiles/deploy.bicep' = if (createFslogixDeployment && (smbStorageType == 'ANF')) { +module anf './modules/azureNetappFiles/deploy.bicep' = if (createFslogixDeployment && (storageService == 'ANF')) { name: 'Storage-FSLogix-${time}' params: { storagePurpose: 'fslogix' @@ -1487,18 +1487,17 @@ module anf './modules/azureNetappFiles/deploy.bicep' = if (createFslogixDeployme // fileShareMultichannel: (fslogixStoragePerformance == 'Premium') ? true : false // storageSku: varFslogixStorageSku // fileShareQuotaSize: fslogixFileShareQuotaSize - // storageAccountFqdn: varFslogixStorageFqdn - // storageAccountName: varFslogixStorageName - // storageToDomainScript: varStorageToDomainScript - // storageToDomainScriptUri: varStorageToDomainScriptUri - // identityServiceProvider: avdIdentityServiceProvider - // dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation - // storageCustomOuPath: varStorageCustomOuPath - // managementVmName: varManagementVmName + storageToDomainScript: varStorageToDomainScript + storageToDomainScriptUri: varStorageToDomainScriptUri + identityServiceProvider: avdIdentityServiceProvider + dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation + storageCustomOuPath: varStorageCustomOuPath + managementVmName: varManagementVmName + storageService: storageService // deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage ouStgPath: varOuStgPath - // managedIdentityClientId: varCreateStorageDeployment ? identity.outputs.managedIdentityStorageClientId : '' - // securityPrincipalName: !empty(securityPrincipalName) ? securityPrincipalName : '' + managedIdentityClientId: varCreateStorageDeployment ? identity.outputs.managedIdentityStorageClientId : '' + securityPrincipalName: !empty(varSecurityPrincipalName) ? varSecurityPrincipalName : '' domainJoinUserName: avdDomainJoinUserName kvResourceId: wrklKeyVault.outputs.resourceId serviceObjectsRgName: varServiceObjectsRgName diff --git a/workload/bicep/modules/azureNetappFiles/deploy.bicep b/workload/bicep/modules/azureNetappFiles/deploy.bicep index 6936ca363..b1f000992 100644 --- a/workload/bicep/modules/azureNetappFiles/deploy.bicep +++ b/workload/bicep/modules/azureNetappFiles/deploy.bicep @@ -47,9 +47,6 @@ param kvResourceId string @sys.description('AVD session host domain join credentials.') param domainJoinUserName string -@sys.description('AVD session host local admin credentials.') -param vmLocalUserName string - @sys.description('ANF performance tier.') param anfPerformance string @@ -100,10 +97,9 @@ param managedIdentityClientId string // Variable declaration // // =========== // var varAzureCloudName = environment().name -var varAdminUserName = (identityServiceProvider == 'EntraID') ? vmLocalUserName : domainJoinUserName var varSecurityPrincipalName = !empty(securityPrincipalName) ? securityPrincipalName : 'none' // var varStorageFqdn = azureNetAppFiles ????????????? -// var varStorageToDomainScriptArgs = '-StorageService ${storageService} -DscPath ${dscAgentPackageLocation} -StoragePurpose ${storagePurpose} -DomainName ${identityDomainName} -IdentityServiceProvider ${identityServiceProvider} -AzureCloudEnvironment ${varAzureCloudName} -SubscriptionId ${subId} -AdminUserName ${varAdminUserName} -CustomOuPath ${storageCustomOuPath} -OUName ${ouStgPath} -ShareName ${subId} -ClientId ${managedIdentityClientId} -SecurityPrincipalName "${varSecurityPrincipalName}" -StorageFqdn ${varStorageFqdn} ' +// var varStorageToDomainScriptArgs = '-StorageService ${storageService} -DscPath ${dscAgentPackageLocation} -StoragePurpose ${storagePurpose} -DomainName ${identityDomainName} -IdentityServiceProvider ${identityServiceProvider} -AzureCloudEnvironment ${varAzureCloudName} -SubscriptionId ${subId} -AdminUserName ${domainJoinUserName} -CustomOuPath ${storageCustomOuPath} -OUName ${ouStgPath} -ShareName ${subId} -ClientId ${managedIdentityClientId} -SecurityPrincipalName "${varSecurityPrincipalName}" -StorageFqdn ${varStorageFqdn} ' var varKvSubId = split(kvResourceId, '/')[2] var varKvRgName = split(kvResourceId, '/')[4] var varKvName = split(kvResourceId, '/')[8] @@ -174,7 +170,7 @@ module azureNetAppFiles '../../../../avm/1.1.0/res/net-app/net-app-account/main. // virtualMachineName: managementVmName // file: storageToDomainScript // scriptArguments: varStorageToDomainScriptArgs -// adminUserPassword: (identityServiceProvider == 'EntraID') ? keyVaultget.getSecret('vmLocalUserPassword') : '' +// adminUserPassword: keyVaultget.getSecret('domainJoinUserName') // baseScriptUri: storageToDomainScriptUri // } // dependsOn: [ diff --git a/workload/bicep/modules/networking/deploy.bicep b/workload/bicep/modules/networking/deploy.bicep index 02fdac939..73effa2cd 100644 --- a/workload/bicep/modules/networking/deploy.bicep +++ b/workload/bicep/modules/networking/deploy.bicep @@ -34,6 +34,9 @@ param avdNetworksecurityGroupName string @sys.description('Private endpoint Network Security Group Name') param privateEndpointNetworksecurityGroupName string +@sys.description('ANF Network Security Group Name') +param anfNetworksecurityGroupName string + @sys.description('Created if a new VNet for AVD is created. Application Security Group (ASG) for the session hosts.') param applicationSecurityGroupName string @@ -67,6 +70,9 @@ param deployDDoSNetworkProtection bool @sys.description('Optional. AVD Accelerator will deploy with private endpoints by default.') param deployPrivateEndpointSubnet bool +@sys.description('Deploy with ANf subnet.') +param deployAnfSubnet bool + @sys.description('Optional. Deploys private endpoints for the AVD Private Link Service. (Default: false)') param deployAvdPrivateLinkService bool @@ -79,12 +85,18 @@ param vnetAvdSubnetName string @sys.description('Private endpoint subnet Name.') param vnetPrivateEndpointSubnetName string +@sys.description('ANF subnet Name.') +param vnetAnfSubnetName string + @sys.description('AVD VNet subnet address prefix.') param vnetAvdSubnetAddressPrefix string @sys.description('Private endpoint VNet subnet address prefix.') param vnetPrivateEndpointSubnetAddressPrefix string +@sys.description('ANF VNet subnet address prefix.') +param vnetAnfSubnetAddressPrefix string + @sys.description('custom DNS servers IPs') param dnsServers array @@ -286,9 +298,7 @@ var varDefaultStaticRoutes = (varAzureCloudName == 'AzureCloud') } ] : [] - var varStaticRoutes = union(varDefaultStaticRoutes, customStaticRoutes) - var privateDnsZoneNames = { AutomationAgentService: 'privatelink.agentsvc.azure-automation.${privateDnsZoneSuffixes_AzureAutomation[environment().name]}' Automation: 'privatelink.azure-automation.${privateDnsZoneSuffixes_AzureAutomation[environment().name]}' @@ -303,7 +313,6 @@ var privateDnsZoneNames = { MonitorODS: 'privatelink.ods.opinsights.${privateDnsZoneSuffixes_Monitor[environment().name]}' MonitorOMS: 'privatelink.oms.opinsights.${privateDnsZoneSuffixes_Monitor[environment().name]}' } - var privateDnsZoneSuffixes_AzureAutomation = { AzureCloud: 'net' AzureUSGovernment: 'us' @@ -316,6 +325,50 @@ var privateDnsZoneSuffixes_Monitor = { AzureCloud: 'azure.com' AzureUSGovernment: 'azure.us' } +var varAvdSubnet = [ + { + name: vnetAvdSubnetName + addressPrefix: vnetAvdSubnetAddressPrefix + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + networkSecurityGroupResourceId: createVnet ? networksecurityGroupAvd.outputs.resourceId : '' + routeTableResourceId: createVnet ? routeTableAvd.outputs.resourceId : '' + } +] +var varPrivateEndpointSubnet = [ + { + name: vnetPrivateEndpointSubnetName + addressPrefix: vnetPrivateEndpointSubnetAddressPrefix + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + networkSecurityGroupResourceId: (createVnet && deployPrivateEndpointSubnet) + ? networksecurityGroupPrivateEndpoint.outputs.resourceId + : '' + routeTableResourceId: (createVnet && deployPrivateEndpointSubnet) + ? routeTablePrivateEndpoint.outputs.resourceId + : '' + } +] +var varAnfSubnet = [ + { + name: vnetAnfSubnetName + addressPrefix: vnetAnfSubnetAddressPrefix + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + networkSecurityGroupResourceId: (createVnet && deployAnfSubnet) + ? networksecurityGroupAnf.outputs.resourceId + : '' + delegations: [ + { + name: 'delegation' + properties: { + serviceName: 'Microsoft.NetApp/volumes' + } + } + ] + } +] +var varSubnets = createVnet ? (!(deployPrivateEndpointSubnet && deployAnfSubnet) ? varAvdSubnet : (deployPrivateEndpointSubnet && !deployAnfSubnet) ? union(varAvdSubnet,varPrivateEndpointSubnet) : (!deployPrivateEndpointSubnet && deployAnfSubnet) ? union(varAvdSubnet,varAnfSubnet) : (deployPrivateEndpointSubnet && deployAnfSubnet) ? union(varAvdSubnet, varPrivateEndpointSubnet, varAnfSubnet) : []): [] // =========== // // Deployments // @@ -476,6 +529,20 @@ module networksecurityGroupPrivateEndpoint '../../../../avm/1.0.0/res/network/ne dependsOn: [] } +// ANF network security group. +module networksecurityGroupAnf '../../../../avm/1.0.0/res/network/network-security-group/main.bicep' = if (createVnet && deployAnfSubnet) { + scope: resourceGroup('${workloadSubsId}', '${networkObjectsRgName}') + name: 'NSG-ANF-${time}' + params: { + name: anfNetworksecurityGroupName + location: location + tags: tags + diagnosticSettings: varDiagnosticSettings + securityRules: [] + } + dependsOn: [] +} + // Application security group. module applicationSecurityGroup '../../../../avm/1.0.0/res/network/application-security-group/main.bicep' = if (deployAsg) { scope: resourceGroup('${workloadSubsId}', '${computeObjectsRgName}') @@ -554,49 +621,7 @@ module virtualNetwork '../../../../avm/1.0.0/res/network/virtual-network/main.bi } ] : [] - subnets: deployPrivateEndpointSubnet - ? [ - { - name: vnetAvdSubnetName - addressPrefix: vnetAvdSubnetAddressPrefix - privateEndpointNetworkPolicies: 'Disabled' - privateLinkServiceNetworkPolicies: 'Enabled' - networkSecurityGroupResourceId: createVnet ? networksecurityGroupAvd.outputs.resourceId : '' - routeTableResourceId: createVnet ? routeTableAvd.outputs.resourceId : '' - } - { - name: vnetPrivateEndpointSubnetName - addressPrefix: vnetPrivateEndpointSubnetAddressPrefix - privateEndpointNetworkPolicies: 'Disabled' - privateLinkServiceNetworkPolicies: 'Enabled' - networkSecurityGroupResourceId: (createVnet && deployPrivateEndpointSubnet) - ? networksecurityGroupPrivateEndpoint.outputs.resourceId - : '' - routeTableResourceId: (createVnet && deployPrivateEndpointSubnet) - ? routeTablePrivateEndpoint.outputs.resourceId - : '' - } - ] - : [ - { - name: vnetAvdSubnetName - addressPrefix: vnetAvdSubnetAddressPrefix - privateEndpointNetworkPolicies: 'Disabled' - privateLinkServiceNetworkPolicies: 'Enabled' - networkSecurityGroupResourceId: createVnet ? networksecurityGroupAvd.outputs.resourceId : '' - routeTableResourceId: createVnet ? routeTableAvd.outputs.resourceId : '' - serviceEndpoints: [ - { - service: 'Microsoft.Storage' - locations: ['${location}'] - } - { - service: 'Microsoft.KeyVault' - locations: ['${location}'] - } - ] - } - ] + subnets: varSubnets ddosProtectionPlanResourceId: deployDDoSNetworkProtection ? ddosProtectionPlan.outputs.resourceId : '' tags: tags diagnosticSettings: varDiagnosticSettings @@ -605,6 +630,7 @@ module virtualNetwork '../../../../avm/1.0.0/res/network/virtual-network/main.bi ? [ networksecurityGroupAvd networksecurityGroupPrivateEndpoint + networksecurityGroupAnf routeTableAvd routeTablePrivateEndpoint ] From 2390ad96392ba4d2dc48f1651d11529a0b56e59b Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 25 Mar 2025 12:57:53 -0500 Subject: [PATCH 07/55] updates --- workload/bicep/deploy-baseline.bicep | 88 +++++++++++-------- workload/bicep/deploy-baseline.bicepparam | 1 + .../modules/azureNetappFiles/deploy.bicep | 9 +- .../bicep/modules/networking/deploy.bicep | 23 ++++- 4 files changed, 81 insertions(+), 40 deletions(-) create mode 100644 workload/bicep/deploy-baseline.bicepparam diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index d15914eb4..ea249014e 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -240,7 +240,7 @@ param avdDeploySessionHostsCount int = 1 @sys.description('The session host number to begin with for the deployment. This is important when adding virtual machines to ensure the names do not conflict. (Default: 1)') param avdSessionHostCountIndex int = 1 -@sys.description('When true VMs are distributed across availability zones, when set to false, VMs will be deployed at regional level.') +@sys.description('When set to AvailabilityZones, VMs and storage are distributed across availability zones, when set to None, VMs and storage will be deployed at regional level.') @allowed([ 'None' 'AvailabilityZones' @@ -255,9 +255,6 @@ param availability string = 'None' ]) param availabilityZones array = ['1', '2', '3'] -@sys.description('When true, Zone Redundant Storage (ZRS) is used, when set to false, Locally Redundant Storage (LRS) is used. (Default: false)') -param zoneRedundantStorage bool = false - // @sys.description('Deploys a VMSS Flex group and associates session hosts with it for availability purposes. (Default: true)') // param deployVmssFlex bool = true @@ -267,24 +264,18 @@ param zoneRedundantStorage bool = false @allowed([ 'Standard' 'Premium' + 'Ultra' ]) -@sys.description('SKU for FSLogix storage. Recommended tier is Premium for storage account. (Default: Premium)') -param fslogixStorageAccountPerformance string = 'Premium' - -@allowed([ - 'Standard' - 'Premium' -]) -@sys.description('SKU for App Attach storage. Recommended tier is Premium for storage account. (Default: Premium)') -param appAttachStorageAccountPerformance string = 'Premium' +@sys.description('SKU for FSLogix storage. Recommended tier is Premium for storage account and Standard for ANF. (Default: Premium)') +param fslogixStoragePerformance string = 'Premium' @allowed([ 'Standard' 'Premium' 'Ultra' ]) -@sys.description('SKU for App Attach and FSLogix ANF storage. (Default: Standard)') -param anfPerformance string = 'Standard' +@sys.description('SKU for App Attach storage. RRecommended tier is Premium for storage account and Standard for ANF. (Default: Premium)') +param appAttachStoragePerformance string = 'Premium' @sys.description('Enables a zero trust configuration on the session host disks. (Default: false)') param diskZeroTrust bool = false @@ -444,6 +435,7 @@ param avdSessionHostCustomNamePrefix string = 'vmapp1duse2' @sys.description('AVD FSLogix and App Attach storage account prefix custom name. (Default: st)') param storageAccountPrefixCustomName string = 'st' +//@maxLength(10) @sys.description('AVD FSLogix and App Attach storage account prefix custom name. (Default: anf-acc-app1-dev-use2-001)') param anfAccountCustomName string = 'anf-acc-app1-dev-use2-001' @@ -678,12 +670,22 @@ var varSessionHostNamePrefix = avdUseCustomNaming : 'vm${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varSessionHostLocationAcronym}' //var varVmssFlexNamePrefix = avdUseCustomNaming ? '${vmssFlexCustomNamePrefix}-${varComputeStorageResourcesNamingStandard}' : 'vmss-${varComputeStorageResourcesNamingStandard}' var varStorageManagedIdentityName = 'id-storage-${varComputeStorageResourcesNamingStandard}-001' -var varFslogixFileShareName = avdUseCustomNaming - ? fslogixFileShareCustomName - : 'fslogix-pc-${varDeploymentPrefixLowercase}-${varDeploymentEnvironmentLowercase}-${varSessionHostLocationAcronym}-001' -var varAppAttachFileShareName = avdUseCustomNaming - ? appAttachFileShareCustomName - : 'appa-${varDeploymentPrefixLowercase}-${varDeploymentEnvironmentLowercase}-${varSessionHostLocationAcronym}-001' + +var varFslogixFileShareName = storageService == 'AzureFiles' + ? (avdUseCustomNaming + ? fslogixFileShareCustomName + : 'fslogix-pc-${varDeploymentPrefixLowercase}-${varDeploymentEnvironmentLowercase}-${varSessionHostLocationAcronym}-001') + : storageService == 'ANF' + ? 'fsl${varDeploymentPrefixLowercase}01' + : '' + +var varAppAttachFileShareName = storageService == 'AzureFiles' + ? (avdUseCustomNaming + ? appAttachFileShareCustomName + : 'appa-${varDeploymentPrefixLowercase}-${varDeploymentEnvironmentLowercase}-${varSessionHostLocationAcronym}-001') + : storageService == 'ANF' + ? 'appa${varDeploymentPrefixLowercase}01' + : '' var varFslogixStorageName = avdUseCustomNaming ? '${storageAccountPrefixCustomName}fsl${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' : 'stfsl${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' @@ -711,12 +713,21 @@ var varBaseScriptUri = 'https://raw.githubusercontent.com/azure/avdaccelerator/m var varSessionHostConfigurationScriptUri = '${varBaseScriptUri}scripts/Set-SessionHostConfiguration.ps1' var varSessionHostConfigurationScript = 'Set-SessionHostConfiguration.ps1' var varCreateStorageDeployment = (createFslogixDeployment || varCreateAppAttachDeployment == true) ? true : false -var varFslogixStorageSku = zoneRedundantStorage - ? '${fslogixStorageAccountPerformance}_ZRS' - : '${fslogixStorageAccountPerformance}_LRS' -var varAppAttachStorageSku = zoneRedundantStorage - ? '${fslogixStorageAccountPerformance}_ZRS' - : '${fslogixStorageAccountPerformance}_LRS' +var varFslogixStoragePerformance = fslogixStoragePerformance =='Ultra' + ? 'Premium' + : fslogixStoragePerformance +var varAppAttachStoragePerformance = appAttachStoragePerformance =='Ultra' + ? 'Premium' + : appAttachStoragePerformance +var varStorageAccountAvailability = availability == 'AvailabilityZones' + ? true + : false +var varFslogixStorageSku = (varStorageAccountAvailability && storageService == 'AzureFiles') + ? '${varFslogixStoragePerformance}_ZRS' + : '${varFslogixStoragePerformance}_LRS' +var varAppAttachStorageSku = varStorageAccountAvailability + ? '${varAppAttachStoragePerformance}_ZRS' + : '${varAppAttachStoragePerformance}_LRS' var varMgmtVmSpecs = { osImage: varMarketPlaceGalleryWindows[managementVmOsImage] osDiskType: 'Standard_LRS' @@ -994,8 +1005,14 @@ var varMarketPlaceGalleryWindows = loadJsonContent('../variables/osMarketPlaceIm var varStorageAzureFilesDscAgentPackageLocation = 'https://github.com/Azure/avdaccelerator/raw/main/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip' var varStorageToDomainScriptUri = '${varBaseScriptUri}scripts/Manual-DSC-Storage-Scripts.ps1' var varStorageToDomainScript = './Manual-DSC-Storage-Scripts.ps1' + + + var varOuStgPath = !empty(storageOuPath) ? '"${storageOuPath}"' : '"${varDefaultStorageOuPath}"' var varDefaultStorageOuPath = (avdIdentityServiceProvider == 'EntraDS') ? 'AADDC Computers' : 'Computers' + + + var varStorageCustomOuPath = !empty(storageOuPath) ? 'true' : 'false' var varAllDnsServers = '${customDnsIps},168.63.129.16' var varDnsServers = empty(customDnsIps) ? [] : (split(varAllDnsServers, ',')) @@ -1472,15 +1489,16 @@ module managementVm './modules/sharedModules/managementVm.bicep' = if (avdIdenti // FSLogix Azure NetApp Files module anf './modules/azureNetappFiles/deploy.bicep' = if (createFslogixDeployment && (storageService == 'ANF')) { - name: 'Storage-FSLogix-${time}' + name: 'Storage-FSLogix-ANF-${time}' params: { storagePurpose: 'fslogix' anfAccountName: varAnfAccountName anfCapacityPoolName: varAnfCapacityPoolName anfVolumeName: varFslogixFileShareName + anfSmbServerNamePrefix: varFslogixFileShareName dnsServers: customDnsIps volumeSize: fslogixFileShareQuotaSize - anfPerformance: anfPerformance + anfPerformance: fslogixStoragePerformance anfSubnetId: createAvdVnet ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAnfSubnetName}' : existingVnetAnfSubnetResourceId // vmLocalUserName: avdVmLocalUserName // fileShareName: varFslogixFileShareName @@ -1495,7 +1513,7 @@ module anf './modules/azureNetappFiles/deploy.bicep' = if (createFslogixDeployme managementVmName: varManagementVmName storageService: storageService // deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage - ouStgPath: varOuStgPath + ouStgPath: !empty(storageOuPath) ? storageOuPath : varDefaultStorageOuPath managedIdentityClientId: varCreateStorageDeployment ? identity.outputs.managedIdentityStorageClientId : '' securityPrincipalName: !empty(varSecurityPrincipalName) ? varSecurityPrincipalName : '' domainJoinUserName: avdDomainJoinUserName @@ -1520,13 +1538,13 @@ module anf './modules/azureNetappFiles/deploy.bicep' = if (createFslogixDeployme } // FSLogix Azure Files -module fslogixAzureFilesStorage './modules/storageAzureFiles/deploy.bicep' = if (createFslogixDeployment) { - name: 'Storage-FSLogix-${time}' +module fslogixAzureFilesStorage './modules/storageAzureFiles/deploy.bicep' = if (createFslogixDeployment && (storageService != 'ANF')) { + name: 'Storage-FSLogix-ST-${time}' params: { storagePurpose: 'fslogix' vmLocalUserName: avdVmLocalUserName fileShareName: varFslogixFileShareName - fileShareMultichannel: (fslogixStorageAccountPerformance == 'Premium') ? true : false + fileShareMultichannel: (varFslogixStoragePerformance == 'Premium') ? true : false storageSku: varFslogixStorageSku fileShareQuotaSize: fslogixFileShareQuotaSize storageAccountFqdn: varFslogixStorageFqdn @@ -1575,13 +1593,13 @@ module fslogixAzureFilesStorage './modules/storageAzureFiles/deploy.bicep' = if } // App Attach Azure Files -module appAttachAzureFilesStorage './modules/storageAzureFiles/deploy.bicep' = if (varCreateAppAttachDeployment) { +module appAttachAzureFilesStorage './modules/storageAzureFiles/deploy.bicep' = if (createFslogixDeployment && (storageService != 'ANF')) { name: 'Storage-AppA-${time}' params: { storagePurpose: 'AppAttach' vmLocalUserName: avdVmLocalUserName fileShareName: varAppAttachFileShareName - fileShareMultichannel: (fslogixStorageAccountPerformance == 'Premium') ? true : false + fileShareMultichannel: (varAppAttachStoragePerformance == 'Premium') ? true : false storageSku: varAppAttachStorageSku fileShareQuotaSize: appAttachFileShareQuotaSize storageAccountFqdn: varAppAttachStorageFqdn diff --git a/workload/bicep/deploy-baseline.bicepparam b/workload/bicep/deploy-baseline.bicepparam new file mode 100644 index 000000000..ca77d9406 --- /dev/null +++ b/workload/bicep/deploy-baseline.bicepparam @@ -0,0 +1 @@ +using './deploy-baseline.bicep' diff --git a/workload/bicep/modules/azureNetappFiles/deploy.bicep b/workload/bicep/modules/azureNetappFiles/deploy.bicep index b1f000992..1dbe66516 100644 --- a/workload/bicep/modules/azureNetappFiles/deploy.bicep +++ b/workload/bicep/modules/azureNetappFiles/deploy.bicep @@ -29,6 +29,9 @@ param anfCapacityPoolName string @sys.description('ANF volume name.') param anfVolumeName string +@sys.description('ANF SMB prefix.') +param anfSmbServerNamePrefix string + @sys.description('ANF subnet ID.') param anfSubnetId string @@ -118,16 +121,16 @@ resource keyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { // Provision the Azure NetApp Files. module azureNetAppFiles '../../../../avm/1.1.0/res/net-app/net-app-account/main.bicep' = { scope: resourceGroup('${subId}', '${storageObjectsRgName}') - name: 'Storage-${storagePurpose}-${time}' + name: 'Storage-ANF-${storagePurpose}-${time}' params: { name: anfAccountName adName: anfAccountName domainName: identityDomainName domainJoinUser: domainJoinUserName domainJoinPassword: keyVaultget.getSecret('domainJoinUserPassword') - domainJoinOU: ouStgPath + //domainJoinOU: replace(ouStgPath, '"', '\\"') dnsServers: dnsServers - smbServerNamePrefix: anfAccountName + smbServerNamePrefix: anfSmbServerNamePrefix location: location // aesEncryption: ************* // customerManagedKey: ************* diff --git a/workload/bicep/modules/networking/deploy.bicep b/workload/bicep/modules/networking/deploy.bicep index 73effa2cd..dcb32d900 100644 --- a/workload/bicep/modules/networking/deploy.bicep +++ b/workload/bicep/modules/networking/deploy.bicep @@ -325,7 +325,7 @@ var privateDnsZoneSuffixes_Monitor = { AzureCloud: 'azure.com' AzureUSGovernment: 'azure.us' } -var varAvdSubnet = [ +var varAvdSubnet = deployPrivateEndpointSubnet ? [ { name: vnetAvdSubnetName addressPrefix: vnetAvdSubnetAddressPrefix @@ -334,6 +334,25 @@ var varAvdSubnet = [ networkSecurityGroupResourceId: createVnet ? networksecurityGroupAvd.outputs.resourceId : '' routeTableResourceId: createVnet ? routeTableAvd.outputs.resourceId : '' } +] : [ + { + name: vnetAvdSubnetName + addressPrefix: vnetAvdSubnetAddressPrefix + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + networkSecurityGroupResourceId: createVnet ? networksecurityGroupAvd.outputs.resourceId : '' + routeTableResourceId: createVnet ? routeTableAvd.outputs.resourceId : '' + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + locations: ['${location}'] + } + { + service: 'Microsoft.KeyVault' + locations: ['${location}'] + } + ] + } ] var varPrivateEndpointSubnet = [ { @@ -368,7 +387,7 @@ var varAnfSubnet = [ ] } ] -var varSubnets = createVnet ? (!(deployPrivateEndpointSubnet && deployAnfSubnet) ? varAvdSubnet : (deployPrivateEndpointSubnet && !deployAnfSubnet) ? union(varAvdSubnet,varPrivateEndpointSubnet) : (!deployPrivateEndpointSubnet && deployAnfSubnet) ? union(varAvdSubnet,varAnfSubnet) : (deployPrivateEndpointSubnet && deployAnfSubnet) ? union(varAvdSubnet, varPrivateEndpointSubnet, varAnfSubnet) : []): [] +var varSubnets = union(varAvdSubnet,(deployAnfSubnet ? varAnfSubnet : []),(deployPrivateEndpointSubnet ? varPrivateEndpointSubnet : [])) // =========== // // Deployments // From 3df6a5582e805bf356e4c766ac3957aa37708a26 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 25 Mar 2025 15:06:20 -0500 Subject: [PATCH 08/55] updates --- workload/bicep/deploy-baseline.bicep | 15 +++++++----- workload/bicep/deploy-baseline.bicepparam | 1 + .../modules/azureNetappFiles/deploy.bicep | 24 +++++++++++++++++++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index ea249014e..2470f2391 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -670,15 +670,14 @@ var varSessionHostNamePrefix = avdUseCustomNaming : 'vm${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varSessionHostLocationAcronym}' //var varVmssFlexNamePrefix = avdUseCustomNaming ? '${vmssFlexCustomNamePrefix}-${varComputeStorageResourcesNamingStandard}' : 'vmss-${varComputeStorageResourcesNamingStandard}' var varStorageManagedIdentityName = 'id-storage-${varComputeStorageResourcesNamingStandard}-001' - var varFslogixFileShareName = storageService == 'AzureFiles' ? (avdUseCustomNaming ? fslogixFileShareCustomName : 'fslogix-pc-${varDeploymentPrefixLowercase}-${varDeploymentEnvironmentLowercase}-${varSessionHostLocationAcronym}-001') : storageService == 'ANF' - ? 'fsl${varDeploymentPrefixLowercase}01' + ? 'fsl${varDeploymentPrefixLowercase}${varDeploymentEnvironmentLowercase}${varSessionHostLocationAcronym}001' : '' - +var varAnfSmbServerNamePrefix = 'anf${varDeploymentPrefixLowercase}${varDeploymentEnvironmentLowercase}' var varAppAttachFileShareName = storageService == 'AzureFiles' ? (avdUseCustomNaming ? appAttachFileShareCustomName @@ -707,8 +706,12 @@ var varZtKvName = avdUseCustomNaming var varZtKvPrivateEndpointName = 'pe-${varZtKvName}-vault' // var varFslogixSharePath = createFslogixDeployment - ? '\\\\${varFslogixStorageName}.file.${environment().suffixes.storage}\\${varFslogixFileShareName}' - : '' + ? (storageService == 'AzureFiles' + ? '\\\\${varFslogixStorageName}.file.${environment().suffixes.storage}\\${varFslogixFileShareName}' + : (storageService == 'ANF' + ? 'ddddd' + : '') ) : '' + var varBaseScriptUri = 'https://raw.githubusercontent.com/azure/avdaccelerator/main/workload/' var varSessionHostConfigurationScriptUri = '${varBaseScriptUri}scripts/Set-SessionHostConfiguration.ps1' var varSessionHostConfigurationScript = 'Set-SessionHostConfiguration.ps1' @@ -1495,7 +1498,7 @@ module anf './modules/azureNetappFiles/deploy.bicep' = if (createFslogixDeployme anfAccountName: varAnfAccountName anfCapacityPoolName: varAnfCapacityPoolName anfVolumeName: varFslogixFileShareName - anfSmbServerNamePrefix: varFslogixFileShareName + anfSmbServerNamePrefix: varAnfSmbServerNamePrefix dnsServers: customDnsIps volumeSize: fslogixFileShareQuotaSize anfPerformance: fslogixStoragePerformance diff --git a/workload/bicep/deploy-baseline.bicepparam b/workload/bicep/deploy-baseline.bicepparam index ca77d9406..977359e25 100644 --- a/workload/bicep/deploy-baseline.bicepparam +++ b/workload/bicep/deploy-baseline.bicepparam @@ -1 +1,2 @@ using './deploy-baseline.bicep' + diff --git a/workload/bicep/modules/azureNetappFiles/deploy.bicep b/workload/bicep/modules/azureNetappFiles/deploy.bicep index 1dbe66516..786439a60 100644 --- a/workload/bicep/modules/azureNetappFiles/deploy.bicep +++ b/workload/bicep/modules/azureNetappFiles/deploy.bicep @@ -180,3 +180,27 @@ module azureNetAppFiles '../../../../avm/1.1.0/res/net-app/net-app-account/main. // azureNetAppFiles // ] // } + +// =========== // +// Outputs // +// =========== // +// output resourceId string = netAppAccount.id + +// @description('The name of the Resource Group the NetApp account was created in.') +// output resourceGroupName string = resourceGroup().name + +// @description('The location the resource was deployed into.') +// output location string = netAppAccount.location + +// @description('The resource IDs of the created capacity pools & their volumes.') +// output capacityPoolResourceIds { +// resourceId: string +// volumeResourceIds: string[] +// }[] = [ +// for (capacityPools, index) in (capacityPools ?? []): { +// resourceId: netAppAccount_capacityPools[index].outputs.resourceId +// volumeResourceIds: netAppAccount_capacityPools[index].outputs.volumeResourceIds +// } +// ] + +// output volumeResourceIds array = azureNetAppFiles.outputs.capacityPools[0].volumes From 93098d25fe5f475006800ca9b527f06cffae990a Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 26 Mar 2025 14:23:13 -0500 Subject: [PATCH 09/55] updates --- workload/bicep/deploy-baseline.bicep | 75 +++++++++++++++---- .../modules/azureNetappFiles/deploy.bicep | 72 +++++------------- .../modules/storageAzureFiles/deploy.bicep | 2 +- 3 files changed, 81 insertions(+), 68 deletions(-) diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index 2470f2391..04769c15c 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -205,11 +205,11 @@ param storageService string = 'AzureFiles' @sys.description('Deploy App Attach setup. (Default: false)') param createAppAttachDeployment bool = false -@sys.description('Fslogix file share size. (Default: 1)') -param fslogixFileShareQuotaSize int = 1 +@sys.description('Fslogix file share size in GB. (Default: 100)') +param fslogixFileShareQuotaSize int = 100 -@sys.description('App Attach file share size. (Default: 1)') -param appAttachFileShareQuotaSize int = 1 +@sys.description('App Attach file share size in GB. (Default: 100)') +param appAttachFileShareQuotaSize int = 100 @sys.description('Deploy new session hosts. (Default: true)') param avdDeploySessionHosts bool = true @@ -685,6 +685,47 @@ var varAppAttachFileShareName = storageService == 'AzureFiles' : storageService == 'ANF' ? 'appa${varDeploymentPrefixLowercase}01' : '' +var varFslogixAnfVolume = createFslogixDeployment ? [ + { + name: varFslogixFileShareName + coolAccess: false + encryptionKeySource: 'Microsoft.NetApp' + zones: [] // availability == 'AvailabilityZones' + //? availabilityZones + //: [] + serviceLevel: fslogixStoragePerformance + networkFeatures: 'Standard' + usageThreshold: fslogixFileShareQuotaSize * 1073741824 // Convert GiBs to bytes + protocolTypes: [ + 'CIFS' + ] + subnetResourceId: createAvdVnet ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAnfSubnetName}' : existingVnetAnfSubnetResourceId + creationToken: varFslogixFileShareName + smbContinuouslyAvailable: true + securityStyle: 'ntfs' + } +] : [] +var varAppAttchAnfVolume = createAppAttachDeployment ? [ + { + name: varAppAttachFileShareName + coolAccess: false + encryptionKeySource: 'Microsoft.NetApp' + zones: [] // availability == 'AvailabilityZones' + //? availabilityZones + //: [] + serviceLevel: appAttachStoragePerformance + networkFeatures: 'Standard' + usageThreshold: appAttachFileShareQuotaSize * 1073741824 // Convert GiBs to bytes + protocolTypes: [ + 'CIFS' + ] + subnetResourceId: createAvdVnet ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAnfSubnetName}' : existingVnetAnfSubnetResourceId + creationToken: varAppAttachFileShareName + smbContinuouslyAvailable: true + securityStyle: 'ntfs' + } +] : [] +var varAnfVolumes = union(varFslogixAnfVolume, varAppAttchAnfVolume) var varFslogixStorageName = avdUseCustomNaming ? '${storageAccountPrefixCustomName}fsl${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' : 'stfsl${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' @@ -704,14 +745,18 @@ var varZtKvName = avdUseCustomNaming ? '${ztKvPrefixCustomName}-${varComputeStorageResourcesNamingStandard}-${varNamingUniqueStringTwoChar}' : 'kv-key-${varComputeStorageResourcesNamingStandard}-${varNamingUniqueStringTwoChar}' // max length limit 24 characters var varZtKvPrivateEndpointName = 'pe-${varZtKvName}-vault' -// var varFslogixSharePath = createFslogixDeployment ? (storageService == 'AzureFiles' ? '\\\\${varFslogixStorageName}.file.${environment().suffixes.storage}\\${varFslogixFileShareName}' : (storageService == 'ANF' - ? 'ddddd' + ? anf.outputs.anfFslogixVolumeResourceId + : '') ) : '' +var varAppAttachSharePath = createAppAttachDeployment + ? (storageService == 'AzureFiles' + ? '\\\\${varAppAttachStorageName}.file.${environment().suffixes.storage}\\${varAppAttachFileShareName}' + : (storageService == 'ANF' + ? anf.outputs.anfAppAttachVolumeResourceId : '') ) : '' - var varBaseScriptUri = 'https://raw.githubusercontent.com/azure/avdaccelerator/main/workload/' var varSessionHostConfigurationScriptUri = '${varBaseScriptUri}scripts/Set-SessionHostConfiguration.ps1' var varSessionHostConfigurationScript = 'Set-SessionHostConfiguration.ps1' @@ -1079,7 +1124,9 @@ var varResourceGroups = [ : union(varAvdDefaultTags, varAllComputeStorageTags) } ] - +var varAnfCapacityPoolSize = ((createFslogixDeployment ? fslogixFileShareQuotaSize : 0) + (createAppAttachDeployment ? appAttachFileShareQuotaSize : 0)) > 4096 + ? ((createFslogixDeployment ? fslogixFileShareQuotaSize : 0) + (createAppAttachDeployment ? appAttachFileShareQuotaSize : 0)) + : 4096 // security Principals (you can add support for more than one because it is an array. Future) var varSecurityPrincipalId = !empty(avdSecurityGroups) ? avdSecurityGroups[0].objectId : '' var varSecurityPrincipalName = !empty(avdSecurityGroups) ? avdSecurityGroups[0].displayName : '' @@ -1490,19 +1537,19 @@ module managementVm './modules/sharedModules/managementVm.bicep' = if (avdIdenti ] } -// FSLogix Azure NetApp Files -module anf './modules/azureNetappFiles/deploy.bicep' = if (createFslogixDeployment && (storageService == 'ANF')) { +// Azure NetApp Files +module anf './modules/azureNetappFiles/deploy.bicep' = if ((createFslogixDeployment || createAppAttachDeployment) && (storageService == 'ANF') && (!contains(avdIdentityServiceProvider, 'EntraID'))) { name: 'Storage-FSLogix-ANF-${time}' params: { - storagePurpose: 'fslogix' anfAccountName: varAnfAccountName anfCapacityPoolName: varAnfCapacityPoolName - anfVolumeName: varFslogixFileShareName + anfVolumes: varAnfVolumes anfSmbServerNamePrefix: varAnfSmbServerNamePrefix + capacityPoolSize: varAnfCapacityPoolSize dnsServers: customDnsIps - volumeSize: fslogixFileShareQuotaSize anfPerformance: fslogixStoragePerformance - anfSubnetId: createAvdVnet ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAnfSubnetName}' : existingVnetAnfSubnetResourceId + createFslogixStorage: createFslogixDeployment + createAppAttachStorage: createAppAttachDeployment // vmLocalUserName: avdVmLocalUserName // fileShareName: varFslogixFileShareName // fileShareMultichannel: (fslogixStoragePerformance == 'Premium') ? true : false diff --git a/workload/bicep/modules/azureNetappFiles/deploy.bicep b/workload/bicep/modules/azureNetappFiles/deploy.bicep index 786439a60..684efc034 100644 --- a/workload/bicep/modules/azureNetappFiles/deploy.bicep +++ b/workload/bicep/modules/azureNetappFiles/deploy.bicep @@ -26,15 +26,18 @@ param anfAccountName string @sys.description('Capacity pool volume name.') param anfCapacityPoolName string -@sys.description('ANF volume name.') -param anfVolumeName string +@sys.description('Capacity pool volume name.') +param createFslogixStorage bool + +@sys.description('Capacity pool volume name.') +param createAppAttachStorage bool + +@sys.description('ANF volumes.') +param anfVolumes array @sys.description('ANF SMB prefix.') param anfSmbServerNamePrefix string -@sys.description('ANF subnet ID.') -param anfSubnetId string - @sys.description('DNS servers IPs.') param dnsServers string @@ -56,9 +59,6 @@ param anfPerformance string @sys.description('ANF capacity pool size in TiBs.') param capacityPoolSize int = 4 -@sys.description('ANF volume quota size in GiBs.') -param volumeSize int - @sys.description('Script name for adding storage account to Active Directory.') param storageToDomainScript string @@ -77,9 +77,6 @@ param time string = utcNow() @sys.description('Storage service provider.') param storageService string -@sys.description('Sets purpose of the storage account.') -param storagePurpose string - @sys.description('Identity name array to grant RBAC role to access AVD application group and NTFS permissions.') param securityPrincipalName string @@ -121,7 +118,7 @@ resource keyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { // Provision the Azure NetApp Files. module azureNetAppFiles '../../../../avm/1.1.0/res/net-app/net-app-account/main.bicep' = { scope: resourceGroup('${subId}', '${storageObjectsRgName}') - name: 'Storage-ANF-${storagePurpose}-${time}' + name: 'Storage-ANF-${time}' params: { name: anfAccountName adName: anfAccountName @@ -138,32 +135,13 @@ module azureNetAppFiles '../../../../avm/1.1.0/res/net-app/net-app-account/main. { name: anfCapacityPoolName serviceLevel: anfPerformance - size: capacityPoolSize * 1099511627776 // Convert TiBs to bytes - encryptionType: 'Single' - volumes: [ - { - name: anfVolumeName - coolAccess: false - encryptionKeySource: 'Microsoft.NetApp' - zones: [] - serviceLevel: anfPerformance - networkFeatures: 'Standard' - usageThreshold: volumeSize * 1073741824 // Convert GiBs to bytes - protocolTypes: [ - 'CIFS' - ] - subnetResourceId: anfSubnetId - creationToken: anfVolumeName - smbContinuouslyAvailable: true - securityStyle: 'ntfs' - } - ] + size: capacityPoolSize * 1073741824 + volumes: anfVolumes } ] tags: tags } } - // Custom Extension call in on the DSC script to set NTFS permissions. // module addShareToDomainScript '../sharedModules/smbUtilities.bicep' = { // scope: resourceGroup('${subId}', '${serviceObjectsRgName}') @@ -184,23 +162,11 @@ module azureNetAppFiles '../../../../avm/1.1.0/res/net-app/net-app-account/main. // =========== // // Outputs // // =========== // -// output resourceId string = netAppAccount.id - -// @description('The name of the Resource Group the NetApp account was created in.') -// output resourceGroupName string = resourceGroup().name - -// @description('The location the resource was deployed into.') -// output location string = netAppAccount.location - -// @description('The resource IDs of the created capacity pools & their volumes.') -// output capacityPoolResourceIds { -// resourceId: string -// volumeResourceIds: string[] -// }[] = [ -// for (capacityPools, index) in (capacityPools ?? []): { -// resourceId: netAppAccount_capacityPools[index].outputs.resourceId -// volumeResourceIds: netAppAccount_capacityPools[index].outputs.volumeResourceIds -// } -// ] - -// output volumeResourceIds array = azureNetAppFiles.outputs.capacityPools[0].volumes +output anfFslogixVolumeResourceId string = createFslogixStorage + ? azureNetAppFiles.outputs.capacityPoolResourceIds[0].volumeResourceIds[0] + : '' +output anfAppAttachVolumeResourceId string = (createAppAttachStorage && createFslogixStorage) + ? azureNetAppFiles.outputs.capacityPoolResourceIds[1].volumeResourceIds[1] + : ((createAppAttachStorage && !createFslogixStorage) + ? azureNetAppFiles.outputs.capacityPoolResourceIds[0].volumeResourceIds[0] + : '') diff --git a/workload/bicep/modules/storageAzureFiles/deploy.bicep b/workload/bicep/modules/storageAzureFiles/deploy.bicep index 76394aab6..60a619688 100644 --- a/workload/bicep/modules/storageAzureFiles/deploy.bicep +++ b/workload/bicep/modules/storageAzureFiles/deploy.bicep @@ -178,7 +178,7 @@ module storageAndFile '../../../../avm/1.0.0/res/storage/storage-account/main.bi shares: [ { name: fileShareName - shareQuota: fileShareQuotaSize * 100 //Portal UI steps scale + shareQuota: fileShareQuotaSize } ] protocolSettings: fileShareMultichannel From 31198a5de26a4e62d3be7530274709f8a704df5d Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 26 Mar 2025 15:35:37 -0500 Subject: [PATCH 10/55] updates --- workload/bicep/deploy-baseline.bicep | 298 +----------- workload/bicep/deploy-baseline.bicepparam | 1 - .../modules/sharedModules/smbStorage.bicep | 437 ++++++++++++++++++ 3 files changed, 459 insertions(+), 277 deletions(-) create mode 100644 workload/bicep/modules/sharedModules/smbStorage.bicep diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index 04769c15c..f818c3117 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -570,7 +570,6 @@ var varDeploymentEnvironmentLowercase = toLower(deploymentEnvironment) var varDeploymentEnvironmentComputeStorage = (deploymentEnvironment == 'Dev') ? 'd' : ((deploymentEnvironment == 'Test') ? 't' : ((deploymentEnvironment == 'Prod') ? 'p' : '')) -var varNamingUniqueStringThreeChar = take('${uniqueString(avdWorkloadSubsId, varDeploymentPrefixLowercase, time)}', 3) var varNamingUniqueStringTwoChar = take('${uniqueString(avdWorkloadSubsId, varDeploymentPrefixLowercase, time)}', 2) var varSessionHostLocationAcronym = varLocations[varSessionHostLocationLowercase].acronym var varManagementPlaneLocationAcronym = varLocations[varManagementPlaneLocationLowercase].acronym @@ -670,73 +669,6 @@ var varSessionHostNamePrefix = avdUseCustomNaming : 'vm${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varSessionHostLocationAcronym}' //var varVmssFlexNamePrefix = avdUseCustomNaming ? '${vmssFlexCustomNamePrefix}-${varComputeStorageResourcesNamingStandard}' : 'vmss-${varComputeStorageResourcesNamingStandard}' var varStorageManagedIdentityName = 'id-storage-${varComputeStorageResourcesNamingStandard}-001' -var varFslogixFileShareName = storageService == 'AzureFiles' - ? (avdUseCustomNaming - ? fslogixFileShareCustomName - : 'fslogix-pc-${varDeploymentPrefixLowercase}-${varDeploymentEnvironmentLowercase}-${varSessionHostLocationAcronym}-001') - : storageService == 'ANF' - ? 'fsl${varDeploymentPrefixLowercase}${varDeploymentEnvironmentLowercase}${varSessionHostLocationAcronym}001' - : '' -var varAnfSmbServerNamePrefix = 'anf${varDeploymentPrefixLowercase}${varDeploymentEnvironmentLowercase}' -var varAppAttachFileShareName = storageService == 'AzureFiles' - ? (avdUseCustomNaming - ? appAttachFileShareCustomName - : 'appa-${varDeploymentPrefixLowercase}-${varDeploymentEnvironmentLowercase}-${varSessionHostLocationAcronym}-001') - : storageService == 'ANF' - ? 'appa${varDeploymentPrefixLowercase}01' - : '' -var varFslogixAnfVolume = createFslogixDeployment ? [ - { - name: varFslogixFileShareName - coolAccess: false - encryptionKeySource: 'Microsoft.NetApp' - zones: [] // availability == 'AvailabilityZones' - //? availabilityZones - //: [] - serviceLevel: fslogixStoragePerformance - networkFeatures: 'Standard' - usageThreshold: fslogixFileShareQuotaSize * 1073741824 // Convert GiBs to bytes - protocolTypes: [ - 'CIFS' - ] - subnetResourceId: createAvdVnet ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAnfSubnetName}' : existingVnetAnfSubnetResourceId - creationToken: varFslogixFileShareName - smbContinuouslyAvailable: true - securityStyle: 'ntfs' - } -] : [] -var varAppAttchAnfVolume = createAppAttachDeployment ? [ - { - name: varAppAttachFileShareName - coolAccess: false - encryptionKeySource: 'Microsoft.NetApp' - zones: [] // availability == 'AvailabilityZones' - //? availabilityZones - //: [] - serviceLevel: appAttachStoragePerformance - networkFeatures: 'Standard' - usageThreshold: appAttachFileShareQuotaSize * 1073741824 // Convert GiBs to bytes - protocolTypes: [ - 'CIFS' - ] - subnetResourceId: createAvdVnet ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAnfSubnetName}' : existingVnetAnfSubnetResourceId - creationToken: varAppAttachFileShareName - smbContinuouslyAvailable: true - securityStyle: 'ntfs' - } -] : [] -var varAnfVolumes = union(varFslogixAnfVolume, varAppAttchAnfVolume) -var varFslogixStorageName = avdUseCustomNaming - ? '${storageAccountPrefixCustomName}fsl${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' - : 'stfsl${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' -var varAnfAccountName = avdUseCustomNaming ? anfAccountCustomName : 'anf-acc-${varComputeStorageResourcesNamingStandard}-001' -var varAnfCapacityPoolName = 'anf-cpool-${varComputeStorageResourcesNamingStandard}-001' -var varFslogixStorageFqdn = createFslogixDeployment ? ((storageService == 'AzureFiles') ? '${varFslogixStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varFslogixFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' -var varAppAttachStorageFqdn = createAppAttachDeployment ? ((storageService == 'AzureFiles') ? '${varAppAttachStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varAppAttachFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' -var varAppAttachStorageName = avdUseCustomNaming - ? '${storageAccountPrefixCustomName}appa${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' - : 'stappa${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' -var varManagementVmName = 'vmmgmt${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varSessionHostLocationAcronym}' var varAlaWorkspaceName = avdUseCustomNaming ? avdAlaWorkspaceCustomName : 'log-avd-${varDeploymentEnvironmentLowercase}-${varManagementPlaneLocationAcronym}' @@ -745,47 +677,9 @@ var varZtKvName = avdUseCustomNaming ? '${ztKvPrefixCustomName}-${varComputeStorageResourcesNamingStandard}-${varNamingUniqueStringTwoChar}' : 'kv-key-${varComputeStorageResourcesNamingStandard}-${varNamingUniqueStringTwoChar}' // max length limit 24 characters var varZtKvPrivateEndpointName = 'pe-${varZtKvName}-vault' -var varFslogixSharePath = createFslogixDeployment - ? (storageService == 'AzureFiles' - ? '\\\\${varFslogixStorageName}.file.${environment().suffixes.storage}\\${varFslogixFileShareName}' - : (storageService == 'ANF' - ? anf.outputs.anfFslogixVolumeResourceId - : '') ) : '' -var varAppAttachSharePath = createAppAttachDeployment - ? (storageService == 'AzureFiles' - ? '\\\\${varAppAttachStorageName}.file.${environment().suffixes.storage}\\${varAppAttachFileShareName}' - : (storageService == 'ANF' - ? anf.outputs.anfAppAttachVolumeResourceId - : '') ) : '' -var varBaseScriptUri = 'https://raw.githubusercontent.com/azure/avdaccelerator/main/workload/' +var varBaseScriptUri = 'https://raw.githubusercontent.com/azure/avdaccelerator/main/workload/' var varSessionHostConfigurationScriptUri = '${varBaseScriptUri}scripts/Set-SessionHostConfiguration.ps1' var varSessionHostConfigurationScript = 'Set-SessionHostConfiguration.ps1' -var varCreateStorageDeployment = (createFslogixDeployment || varCreateAppAttachDeployment == true) ? true : false -var varFslogixStoragePerformance = fslogixStoragePerformance =='Ultra' - ? 'Premium' - : fslogixStoragePerformance -var varAppAttachStoragePerformance = appAttachStoragePerformance =='Ultra' - ? 'Premium' - : appAttachStoragePerformance -var varStorageAccountAvailability = availability == 'AvailabilityZones' - ? true - : false -var varFslogixStorageSku = (varStorageAccountAvailability && storageService == 'AzureFiles') - ? '${varFslogixStoragePerformance}_ZRS' - : '${varFslogixStoragePerformance}_LRS' -var varAppAttachStorageSku = varStorageAccountAvailability - ? '${varAppAttachStoragePerformance}_ZRS' - : '${varAppAttachStoragePerformance}_LRS' -var varMgmtVmSpecs = { - osImage: varMarketPlaceGalleryWindows[managementVmOsImage] - osDiskType: 'Standard_LRS' - mgmtVmSize: avdSessionHostsSize //'Standard_D2ads_v5' - enableAcceleratedNetworking: false - ouPath: avdOuPath - subnetId: createAvdVnet - ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAvdSubnetName}' - : existingVnetAvdSubnetResourceId -} var varMaxSessionHostsPerTemplate = 10 var varMaxSessionHostsDivisionValue = avdDeploySessionHostsCount / varMaxSessionHostsPerTemplate var varMaxSessionHostsDivisionRemainderValue = avdDeploySessionHostsCount % varMaxSessionHostsPerTemplate @@ -1049,25 +943,11 @@ var varPooledScalingPlanSchedules = [ } } ] -var varMarketPlaceGalleryWindows = loadJsonContent('../variables/osMarketPlaceImages.json') -var varStorageAzureFilesDscAgentPackageLocation = 'https://github.com/Azure/avdaccelerator/raw/main/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip' -var varStorageToDomainScriptUri = '${varBaseScriptUri}scripts/Manual-DSC-Storage-Scripts.ps1' -var varStorageToDomainScript = './Manual-DSC-Storage-Scripts.ps1' - - - -var varOuStgPath = !empty(storageOuPath) ? '"${storageOuPath}"' : '"${varDefaultStorageOuPath}"' -var varDefaultStorageOuPath = (avdIdentityServiceProvider == 'EntraDS') ? 'AADDC Computers' : 'Computers' - - - -var varStorageCustomOuPath = !empty(storageOuPath) ? 'true' : 'false' var varAllDnsServers = '${customDnsIps},168.63.129.16' var varDnsServers = empty(customDnsIps) ? [] : (split(varAllDnsServers, ',')) var varCreateVnetPeering = !empty(existingHubVnetResourceId) ? true : false // Resource tagging // Tag Exclude-${varAvdScalingPlanName} is used by scaling plans to exclude session hosts from scaling. Exmaple: Exclude-vdscal-eus2-app1-dev-001 - var varTagsWithValues = union( empty(workloadNameTag) ? {} : { WorkloadName: workloadNameTag }, empty(workloadTypeTag) ? {} : { WorkloadType: workloadTypeTag }, @@ -1124,9 +1004,6 @@ var varResourceGroups = [ : union(varAvdDefaultTags, varAllComputeStorageTags) } ] -var varAnfCapacityPoolSize = ((createFslogixDeployment ? fslogixFileShareQuotaSize : 0) + (createAppAttachDeployment ? appAttachFileShareQuotaSize : 0)) > 4096 - ? ((createFslogixDeployment ? fslogixFileShareQuotaSize : 0) + (createAppAttachDeployment ? appAttachFileShareQuotaSize : 0)) - : 4096 // security Principals (you can add support for more than one because it is an array. Future) var varSecurityPrincipalId = !empty(avdSecurityGroups) ? avdSecurityGroups[0].objectId : '' var varSecurityPrincipalName = !empty(avdSecurityGroups) ? avdSecurityGroups[0].displayName : '' @@ -1537,164 +1414,33 @@ module managementVm './modules/sharedModules/managementVm.bicep' = if (avdIdenti ] } -// Azure NetApp Files -module anf './modules/azureNetappFiles/deploy.bicep' = if ((createFslogixDeployment || createAppAttachDeployment) && (storageService == 'ANF') && (!contains(avdIdentityServiceProvider, 'EntraID'))) { - name: 'Storage-FSLogix-ANF-${time}' +// FSLogix and/or App Attach deployment +module smbStorage './modules/sharedModules/smbStorage.bicep' = if (createFslogixDeployment || createAppAttachDeployment) { + name: 'SMB-Storage-${time}' + scope: resourceGroup('${avdWorkloadSubsId}', '${varStorageObjectsRgName}') params: { - anfAccountName: varAnfAccountName - anfCapacityPoolName: varAnfCapacityPoolName - anfVolumes: varAnfVolumes - anfSmbServerNamePrefix: varAnfSmbServerNamePrefix - capacityPoolSize: varAnfCapacityPoolSize - dnsServers: customDnsIps - anfPerformance: fslogixStoragePerformance - createFslogixStorage: createFslogixDeployment - createAppAttachStorage: createAppAttachDeployment - // vmLocalUserName: avdVmLocalUserName - // fileShareName: varFslogixFileShareName - // fileShareMultichannel: (fslogixStoragePerformance == 'Premium') ? true : false - // storageSku: varFslogixStorageSku - // fileShareQuotaSize: fslogixFileShareQuotaSize - storageToDomainScript: varStorageToDomainScript - storageToDomainScriptUri: varStorageToDomainScriptUri - identityServiceProvider: avdIdentityServiceProvider - dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation - storageCustomOuPath: varStorageCustomOuPath - managementVmName: varManagementVmName + deploymentPrefix: varDeploymentPrefixLowercase + deploymentEnvironment: varDeploymentEnvironmentLowercase storageService: storageService - // deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage - ouStgPath: !empty(storageOuPath) ? storageOuPath : varDefaultStorageOuPath - managedIdentityClientId: varCreateStorageDeployment ? identity.outputs.managedIdentityStorageClientId : '' - securityPrincipalName: !empty(varSecurityPrincipalName) ? varSecurityPrincipalName : '' - domainJoinUserName: avdDomainJoinUserName - kvResourceId: wrklKeyVault.outputs.resourceId - serviceObjectsRgName: varServiceObjectsRgName - identityDomainName: identityDomainName - // identityDomainGuid: identityDomainGuid - location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation - storageObjectsRgName: varStorageObjectsRgName - subId: avdWorkloadSubsId - tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags - // alaWorkspaceResourceId: avdDeployMonitoring - // ? (deployAlaWorkspace - // ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId - // : alaExistingWorkspaceResourceId) - // : '' - } - dependsOn: [ - baselineStorageResourceGroup - managementVm - ] -} - -// FSLogix Azure Files -module fslogixAzureFilesStorage './modules/storageAzureFiles/deploy.bicep' = if (createFslogixDeployment && (storageService != 'ANF')) { - name: 'Storage-FSLogix-ST-${time}' - params: { - storagePurpose: 'fslogix' - vmLocalUserName: avdVmLocalUserName - fileShareName: varFslogixFileShareName - fileShareMultichannel: (varFslogixStoragePerformance == 'Premium') ? true : false - storageSku: varFslogixStorageSku - fileShareQuotaSize: fslogixFileShareQuotaSize - storageAccountFqdn: varFslogixStorageFqdn - storageAccountName: varFslogixStorageName - storageToDomainScript: varStorageToDomainScript - storageToDomainScriptUri: varStorageToDomainScriptUri - identityServiceProvider: avdIdentityServiceProvider - dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation - storageCustomOuPath: varStorageCustomOuPath - managementVmName: varManagementVmName - deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage - ouStgPath: varOuStgPath - managedIdentityClientId: varCreateStorageDeployment && avdIdentityServiceProvider != 'EntraID' - ? identity.outputs.managedIdentityStorageClientId - : '' - securityPrincipalName: varSecurityPrincipalName - domainJoinUserName: avdDomainJoinUserName - wrklKvName: varWrklKvName - serviceObjectsRgName: varServiceObjectsRgName - identityDomainName: identityDomainName - identityDomainGuid: identityDomainGuid + useCustomNaming: avdUseCustomNaming + fslogixFileShareCustomName: fslogixFileShareCustomName + appAttachFileShareCustomName: appAttachFileShareCustomName + fslogixFileShareQuotaSize: fslogixFileShareQuotaSize + appAttachFileShareQuotaSize: appAttachFileShareQuotaSize + fslogixStoragePerformance: fslogixStoragePerformance + appAttachStoragePerformance: appAttachStoragePerformance + anfSubnetResourceId: createAvdVnet ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAnfSubnetName}' : existingVnetAnfSubnetResourceId + vmsSubnetResourceId: createAvdVnet + ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAvdSubnetName}' + : existingVnetAvdSubnetResourceId + privateEndpointSubnetId: location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation - storageObjectsRgName: varStorageObjectsRgName - privateEndpointSubnetId: createAvdVnet - ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetPrivateEndpointSubnetName}' - : existingVnetPrivateEndpointSubnetResourceId - vmsSubnetId: createAvdVnet - ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAvdSubnetName}' - : existingVnetAvdSubnetResourceId - vnetPrivateDnsZoneFilesId: createPrivateDnsZones - ? networking.outputs.azureFilesDnsZoneResourceId - : avdVnetPrivateDnsZoneFilesId - workloadSubsId: avdWorkloadSubsId - tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags - alaWorkspaceResourceId: avdDeployMonitoring - ? (deployAlaWorkspace - ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId - : alaExistingWorkspaceResourceId) - : '' - } - dependsOn: [ - baselineStorageResourceGroup - wrklKeyVault - managementVm - ] -} + locationAcronym: avdDeploySessionHosts ? varSessionHostLocationAcronym : avdManagementPlaneLocation -// App Attach Azure Files -module appAttachAzureFilesStorage './modules/storageAzureFiles/deploy.bicep' = if (createFslogixDeployment && (storageService != 'ANF')) { - name: 'Storage-AppA-${time}' - params: { - storagePurpose: 'AppAttach' - vmLocalUserName: avdVmLocalUserName - fileShareName: varAppAttachFileShareName - fileShareMultichannel: (varAppAttachStoragePerformance == 'Premium') ? true : false - storageSku: varAppAttachStorageSku - fileShareQuotaSize: appAttachFileShareQuotaSize - storageAccountFqdn: varAppAttachStorageFqdn - storageAccountName: varAppAttachStorageName - storageToDomainScript: varStorageToDomainScript - storageToDomainScriptUri: varStorageToDomainScriptUri - identityServiceProvider: avdIdentityServiceProvider - dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation - storageCustomOuPath: varStorageCustomOuPath - managementVmName: varManagementVmName - deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage - ouStgPath: varOuStgPath - managedIdentityClientId: varCreateStorageDeployment && avdIdentityServiceProvider != 'EntraID' - ? identity.outputs.managedIdentityStorageClientId - : '' - securityPrincipalName: varSecurityPrincipalName - domainJoinUserName: avdDomainJoinUserName - wrklKvName: varWrklKvName - serviceObjectsRgName: varServiceObjectsRgName - identityDomainName: identityDomainName - identityDomainGuid: identityDomainGuid - location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation - storageObjectsRgName: varStorageObjectsRgName - privateEndpointSubnetId: createAvdVnet - ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetPrivateEndpointSubnetName}' - : existingVnetPrivateEndpointSubnetResourceId - vmsSubnetId: createAvdVnet - ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAvdSubnetName}' - : existingVnetAvdSubnetResourceId - vnetPrivateDnsZoneFilesId: createPrivateDnsZones - ? networking.outputs.azureFilesDnsZoneResourceId - : avdVnetPrivateDnsZoneFilesId - workloadSubsId: avdWorkloadSubsId - tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags - alaWorkspaceResourceId: avdDeployMonitoring - ? (deployAlaWorkspace - ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId - : alaExistingWorkspaceResourceId) - : '' } dependsOn: [ - fslogixAzureFilesStorage - baselineStorageResourceGroup - wrklKeyVault - managementVm + baselineResourceGroups + monitoringDiagnosticSettings ] } diff --git a/workload/bicep/deploy-baseline.bicepparam b/workload/bicep/deploy-baseline.bicepparam index 977359e25..ca77d9406 100644 --- a/workload/bicep/deploy-baseline.bicepparam +++ b/workload/bicep/deploy-baseline.bicepparam @@ -1,2 +1 @@ using './deploy-baseline.bicep' - diff --git a/workload/bicep/modules/sharedModules/smbStorage.bicep b/workload/bicep/modules/sharedModules/smbStorage.bicep new file mode 100644 index 000000000..793a2eef2 --- /dev/null +++ b/workload/bicep/modules/sharedModules/smbStorage.bicep @@ -0,0 +1,437 @@ +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // + +@description('The subscription ID for the AVD workload.') +param subId string = subscription().subscriptionId + +@description('The deployment prefix in lowercase.') +param deploymentPrefix string + +@description('The deployment environment in lowercase.') +param deploymentEnvironment string + +@description('The session host location acronym derived from the resource group location.') +param location string = resourceGroup().location + +@description('The session host or AVD management plane location acronym For example, "eus" for East US.') +param locationAcronym string + +@description('The storage service to use (AzureFiles or ANF).') +param storageService string + +@description('Indicates whether to use custom naming for AVD.') +param useCustomNaming bool + +@description('The custom name for the FSLogix file share.') +param fslogixFileShareCustomName string = '' + +@description('The custom name for the App Attach file share.') +param appAttachFileShareCustomName string = '' + +@description('The FSLogix file share quota size in GiBs.') +param fslogixFileShareQuotaSize int + +@description('The App Attach file share quota size in GiBs.') +param appAttachFileShareQuotaSize int + +@description('The storage performance level for FSLogix.') +param fslogixStoragePerformance string + +@description('The storage performance level for App Attach.') +param appAttachStoragePerformance string + +@description('Subnet resource ID for ANF volumes.') +param anfSubnetResourceId bool + +@description('Subnet resource ID for VMs.') +param vmsSubnetResourceId bool + +@description('Subnet resource ID for private endpoints.') +param privateEndpointSubnetResourceId bool + +@description('The existing VNet AVD subnet resource ID.') +param existingVnetAvdSubnetResourceId string = '' + +@description('The existing VNet private endpoint subnet resource ID.') +param existingVnetPrivateEndpointSubnetResourceId string = '' + +@description('The availability setting (AvailabilityZones or other).') +param availability string + +@description('The custom DNS IPs.') +param customDnsIps array = [] + +@description('The AVD identity service provider (e.g., EntraDS).') +param avdIdentityServiceProvider string + +@description('The AVD domain join username.') +param avdDomainJoinUserName string + +@description('The service objects resource group name.') +param serviceObjectsRgName string + +@description('The storage objects resource group name.') +param varStorageObjectsRgName string + +@description('The AVD session host location.') +param avdSessionHostLocation string + +@description('The AVD management plane location.') +param avdManagementPlaneLocation string + +@description('The AVD session hosts size.') +param avdSessionHostsSize string + +@description('The AVD OU path.') +param avdOuPath string + +@description('The storage OU path.') +param storageOuPath string = '' + +@description('The custom resource tags.') +param varCustomResourceTags object = {} + +@description('The AVD default tags.') +param varAvdDefaultTags object = {} + +@description('Indicates whether to create resource tags.') +param createResourceTags bool + +@description('The base script URI.') +param varBaseScriptUri string + +@description('The security principal name.') +param varSecurityPrincipalName string = '' + +@description('The identity domain name.') +param identityDomainName string + +@description('The identity domain GUID.') +param identityDomainGuid string = '' + +@description('Indicates whether to deploy private endpoints for Key Vault and storage.') +param deployPrivateEndpointKeyvaultStorage bool + +@description('Indicates whether to deploy monitoring.') +param avdDeployMonitoring bool + +@description('Indicates whether to deploy AVD session hosts.') +param avdDeploySessionHosts bool + +@description('Indicates whether to create FSLogix deployment.') +param createFslogixDeployment bool + +@description('Indicates whether to create App Attach deployment.') +param createAppAttachDeployment bool + +@description('Indicates whether to create private DNS zones.') +param createPrivateDnsZones bool + +@description('The AVD VNet private DNS zone files ID.') +param avdVnetPrivateDnsZoneFilesId string = '' + +@description('The existing ALA workspace resource ID.') +param alaExistingWorkspaceResourceId string = '' + +@description('Indicates whether to deploy ALA workspace.') +param deployAlaWorkspace bool + +@description('The deployment timestamp.') +param time string = utcNow() + +// =========== // +// Variable declaration // +// =========== // +var varNamingUniqueStringThreeChar = take('${uniqueString(subId, deploymentPrefix, time)}', 3) +var varAnfCapacityPoolSize = ((createFslogixDeployment ? fslogixFileShareQuotaSize : 0) + (createAppAttachDeployment ? appAttachFileShareQuotaSize : 0)) > 4096 + ? ((createFslogixDeployment ? fslogixFileShareQuotaSize : 0) + (createAppAttachDeployment ? appAttachFileShareQuotaSize : 0)) + : 4096 +var varFslogixFileShareName = storageService == 'AzureFiles' + ? (useCustomNaming + ? fslogixFileShareCustomName + : 'fslogix-pc-${deploymentPrefix}-${deploymentEnvironment}-${locationAcronym}-001') + : storageService == 'ANF' + ? 'fsl${deploymentPrefix}${deploymentEnvironment}${locationAcronym}001' + : '' +var varAnfSmbServerNamePrefix = 'anf${deploymentPrefix}${deploymentEnvironment}' +var varAppAttachFileShareName = storageService == 'AzureFiles' + ? (useCustomNaming + ? appAttachFileShareCustomName + : 'appa-${deploymentPrefix}-${deploymentEnvironment}-${locationAcronym}-001') + : storageService == 'ANF' + ? 'appa${deploymentPrefix}01' + : '' +var varFslogixAnfVolume = createFslogixDeployment ? [ + { + name: varFslogixFileShareName + coolAccess: false + encryptionKeySource: 'Microsoft.NetApp' + zones: [] // availability == 'AvailabilityZones' + //? availabilityZones + //: [] + serviceLevel: fslogixStoragePerformance + networkFeatures: 'Standard' + usageThreshold: fslogixFileShareQuotaSize * 1073741824 // Convert GiBs to bytes + protocolTypes: [ + 'CIFS' + ] + subnetResourceId: + creationToken: varFslogixFileShareName + smbContinuouslyAvailable: true + securityStyle: 'ntfs' + } + ] : [] +var varAppAttchAnfVolume = createAppAttachDeployment ? [ + { + name: varAppAttachFileShareName + coolAccess: false + encryptionKeySource: 'Microsoft.NetApp' + zones: [] // availability == 'AvailabilityZones' + //? availabilityZones + //: [] + serviceLevel: appAttachStoragePerformance + networkFeatures: 'Standard' + usageThreshold: appAttachFileShareQuotaSize * 1073741824 // Convert GiBs to bytes + protocolTypes: [ + 'CIFS' + ] + subnetResourceId: anfSubnetId + creationToken: varAppAttachFileShareName + smbContinuouslyAvailable: true + securityStyle: 'ntfs' + } + ] : [] +var varAnfVolumes = union(varFslogixAnfVolume, varAppAttchAnfVolume) +var varFslogixStorageName = useCustomNaming + ? '${storageAccountPrefixCustomName}fsl${deploymentPrefix}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' + : 'stfsl${deploymentPrefix}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' +var varAnfAccountName = useCustomNaming ? anfAccountCustomName : 'anf-acc-${varComputeStorageResourcesNamingStandard}-001' +var varAnfCapacityPoolName = 'anf-cpool-${varComputeStorageResourcesNamingStandard}-001' +var varFslogixStorageFqdn = createFslogixDeployment ? ((storageService == 'AzureFiles') ? '${varFslogixStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varFslogixFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' +var varAppAttachStorageFqdn = createAppAttachDeployment ? ((storageService == 'AzureFiles') ? '${varAppAttachStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varAppAttachFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' +var varAppAttachStorageName = useCustomNaming + ? '${storageAccountPrefixCustomName}appa${deploymentPrefix}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' + : 'stappa${deploymentPrefix}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' +var varManagementVmName = 'vmmgmt${deploymentPrefix}${varDeploymentEnvironmentComputeStorage}${locationAcronym}' +var varFslogixSharePath = createFslogixDeployment + ? (storageService == 'AzureFiles' + ? '\\\\${varFslogixStorageName}.file.${environment().suffixes.storage}\\${varFslogixFileShareName}' + : (storageService == 'ANF' + ? anf.outputs.anfFslogixVolumeResourceId + : '') ) : '' +var varAppAttachSharePath = createAppAttachDeployment + ? (storageService == 'AzureFiles' + ? '\\\\${varAppAttachStorageName}.file.${environment().suffixes.storage}\\${varAppAttachFileShareName}' + : (storageService == 'ANF' + ? anf.outputs.anfAppAttachVolumeResourceId + : '') ) : '' +var varCreateStorageDeployment = (createFslogixDeployment || varCreateAppAttachDeployment == true) ? true : false +var varFslogixStoragePerformance = fslogixStoragePerformance =='Ultra' + ? 'Premium' + : fslogixStoragePerformance +var varAppAttachStoragePerformance = appAttachStoragePerformance =='Ultra' + ? 'Premium' + : appAttachStoragePerformance +var varStorageAccountAvailability = availability == 'AvailabilityZones' + ? true + : false +var varFslogixStorageSku = (varStorageAccountAvailability && storageService == 'AzureFiles') + ? '${varFslogixStoragePerformance}_ZRS' + : '${varFslogixStoragePerformance}_LRS' +var varAppAttachStorageSku = varStorageAccountAvailability + ? '${varAppAttachStoragePerformance}_ZRS' + : '${varAppAttachStoragePerformance}_LRS' +var varStorageAzureFilesDscAgentPackageLocation = 'https://github.com/Azure/avdaccelerator/raw/main/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip' +var varStorageToDomainScriptUri = '${varBaseScriptUri}scripts/Manual-DSC-Storage-Scripts.ps1' +var varStorageToDomainScript = './Manual-DSC-Storage-Scripts.ps1' +var varOuStgPath = !empty(storageOuPath) ? '"${storageOuPath}"' : '"${varDefaultStorageOuPath}"' +var varDefaultStorageOuPath = (avdIdentityServiceProvider == 'EntraDS') ? 'AADDC Computers' : 'Computers' +var varMarketPlaceGalleryWindows = loadJsonContent('../variables/osMarketPlaceImages.json') +var varStorageCustomOuPath = !empty(storageOuPath) ? 'true' : 'false' + + +var varMgmtVmSpecs = { + osImage: varMarketPlaceGalleryWindows[managementVmOsImage] + osDiskType: 'Standard_LRS' + mgmtVmSize: avdSessionHostsSize //'Standard_D2ads_v5' + enableAcceleratedNetworking: false + ouPath: avdOuPath + subnetId: vmsSubnetResourceId + } +// =========== // +// Deployments // +// =========== // + +// Call on the KV. +resource avdWrklKeyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { + name: wrklKvName + scope: resourceGroup('${subId}', '${serviceObjectsRgName}') +} + +// Azure NetApp Files +module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && (!contains(avdIdentityServiceProvider, 'EntraID'))) { + name: 'Storage-FSLogix-ANF-${time}' + params: { + anfAccountName: varAnfAccountName + anfCapacityPoolName: varAnfCapacityPoolName + anfVolumes: varAnfVolumes + anfSmbServerNamePrefix: varAnfSmbServerNamePrefix + capacityPoolSize: varAnfCapacityPoolSize + dnsServers: customDnsIps + anfPerformance: fslogixStoragePerformance + createFslogixStorage: createFslogixDeployment + createAppAttachStorage: createAppAttachDeployment + // vmLocalUserName: avdVmLocalUserName + // fileShareName: varFslogixFileShareName + // fileShareMultichannel: (fslogixStoragePerformance == 'Premium') ? true : false + // storageSku: varFslogixStorageSku + // fileShareQuotaSize: fslogixFileShareQuotaSize + storageToDomainScript: varStorageToDomainScript + storageToDomainScriptUri: varStorageToDomainScriptUri + identityServiceProvider: avdIdentityServiceProvider + dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation + storageCustomOuPath: varStorageCustomOuPath + managementVmName: varManagementVmName + storageService: storageService + // deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage + ouStgPath: !empty(storageOuPath) ? storageOuPath : varDefaultStorageOuPath + managedIdentityClientId: varCreateStorageDeployment ? identity.outputs.managedIdentityStorageClientId : '' + securityPrincipalName: !empty(varSecurityPrincipalName) ? varSecurityPrincipalName : '' + domainJoinUserName: avdDomainJoinUserName + kvResourceId: wrklKeyVault.outputs.resourceId + serviceObjectsRgName: varServiceObjectsRgName + identityDomainName: identityDomainName + // identityDomainGuid: identityDomainGuid + location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation + storageObjectsRgName: varStorageObjectsRgName + subId: subId + tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags + // alaWorkspaceResourceId: avdDeployMonitoring + // ? (deployAlaWorkspace + // ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId + // : alaExistingWorkspaceResourceId) + // : '' + } + dependsOn: [ + baselineStorageResourceGroup + managementVm + ] + } + +// FSLogix Azure Files +module fslogixAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (createFslogixDeployment && (storageService != 'ANF')) { + name: 'Storage-FSLogix-ST-${time}' + params: { + storagePurpose: 'fslogix' + vmLocalUserName: avdVmLocalUserName + fileShareName: varFslogixFileShareName + fileShareMultichannel: (varFslogixStoragePerformance == 'Premium') ? true : false + storageSku: varFslogixStorageSku + fileShareQuotaSize: fslogixFileShareQuotaSize + storageAccountFqdn: varFslogixStorageFqdn + storageAccountName: varFslogixStorageName + storageToDomainScript: varStorageToDomainScript + storageToDomainScriptUri: varStorageToDomainScriptUri + identityServiceProvider: avdIdentityServiceProvider + dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation + storageCustomOuPath: varStorageCustomOuPath + managementVmName: varManagementVmName + deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage + ouStgPath: varOuStgPath + managedIdentityClientId: varCreateStorageDeployment && avdIdentityServiceProvider != 'EntraID' + ? identity.outputs.managedIdentityStorageClientId + : '' + securityPrincipalName: varSecurityPrincipalName + domainJoinUserName: avdDomainJoinUserName + wrklKvName: varWrklKvName + serviceObjectsRgName: varServiceObjectsRgName + identityDomainName: identityDomainName + identityDomainGuid: identityDomainGuid + location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation + storageObjectsRgName: varStorageObjectsRgName + privateEndpointSubnetId: createAvdVnet + ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetPrivateEndpointSubnetName}' + : existingVnetPrivateEndpointSubnetResourceId + vmsSubnetId: createAvdVnet + ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAvdSubnetName}' + : existingVnetAvdSubnetResourceId + vnetPrivateDnsZoneFilesId: createPrivateDnsZones + ? networking.outputs.azureFilesDnsZoneResourceId + : avdVnetPrivateDnsZoneFilesId + subId: subId + tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags + alaWorkspaceResourceId: avdDeployMonitoring + ? (deployAlaWorkspace + ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId + : alaExistingWorkspaceResourceId) + : '' + } + dependsOn: [ + baselineStorageResourceGroup + wrklKeyVault + managementVm + ] +} + + // App Attach Azure Files +module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (createFslogixDeployment && (storageService != 'ANF')) { + name: 'Storage-AppA-${time}' + params: { + storagePurpose: 'AppAttach' + vmLocalUserName: avdVmLocalUserName + fileShareName: varAppAttachFileShareName + fileShareMultichannel: (varAppAttachStoragePerformance == 'Premium') ? true : false + storageSku: varAppAttachStorageSku + fileShareQuotaSize: appAttachFileShareQuotaSize + storageAccountFqdn: varAppAttachStorageFqdn + storageAccountName: varAppAttachStorageName + storageToDomainScript: varStorageToDomainScript + storageToDomainScriptUri: varStorageToDomainScriptUri + identityServiceProvider: avdIdentityServiceProvider + dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation + storageCustomOuPath: varStorageCustomOuPath + managementVmName: varManagementVmName + deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage + ouStgPath: varOuStgPath + managedIdentityClientId: varCreateStorageDeployment && avdIdentityServiceProvider != 'EntraID' + ? identity.outputs.managedIdentityStorageClientId + : '' + securityPrincipalName: varSecurityPrincipalName + domainJoinUserName: avdDomainJoinUserName + wrklKvName: varWrklKvName + serviceObjectsRgName: varServiceObjectsRgName + identityDomainName: identityDomainName + identityDomainGuid: identityDomainGuid + location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation + storageObjectsRgName: varStorageObjectsRgName + privateEndpointSubnetId: createAvdVnet + ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetPrivateEndpointSubnetName}' + : existingVnetPrivateEndpointSubnetResourceId + vmsSubnetId: createAvdVnet + ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAvdSubnetName}' + : existingVnetAvdSubnetResourceId + vnetPrivateDnsZoneFilesId: createPrivateDnsZones + ? networking.outputs.azureFilesDnsZoneResourceId + : avdVnetPrivateDnsZoneFilesId + subId: subId + tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags + alaWorkspaceResourceId: avdDeployMonitoring + ? (deployAlaWorkspace + ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId + : alaExistingWorkspaceResourceId) + : '' + } + dependsOn: [ + fslogixAzureFilesStorage + baselineStorageResourceGroup + wrklKeyVault + managementVm + ] +} + +// =========== // +// Outputs // +// =========== // From dc36188c5dd0ba69c5eca5eee29111c958483186 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 26 Mar 2025 15:47:49 -0500 Subject: [PATCH 11/55] updates --- workload/bicep/deploy-baseline.bicep | 8 +++- .../modules/sharedModules/smbStorage.bicep | 44 ++++++++++++------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index f818c3117..7a3b0f4a0 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -567,7 +567,7 @@ param enableDefForArm bool = true var varDeploymentPrefixLowercase = toLower(deploymentPrefix) var varAzureCloudName = environment().name var varDeploymentEnvironmentLowercase = toLower(deploymentEnvironment) -var varDeploymentEnvironmentComputeStorage = (deploymentEnvironment == 'Dev') +var varDeploymentEnvironmentOneCharacter = (deploymentEnvironment == 'Dev') ? 'd' : ((deploymentEnvironment == 'Test') ? 't' : ((deploymentEnvironment == 'Prod') ? 'p' : '')) var varNamingUniqueStringTwoChar = take('${uniqueString(avdWorkloadSubsId, varDeploymentPrefixLowercase, time)}', 2) @@ -666,7 +666,7 @@ var varWrklKeyVaultSku = (varAzureCloudName == 'AzureCloud' || varAzureCloudName : (varAzureCloudName == 'AzureChinaCloud' ? 'standard' : null) var varSessionHostNamePrefix = avdUseCustomNaming ? avdSessionHostCustomNamePrefix - : 'vm${varDeploymentPrefixLowercase}${varDeploymentEnvironmentComputeStorage}${varSessionHostLocationAcronym}' + : 'vm${varDeploymentPrefixLowercase}${varDeploymentEnvironmentOneCharacter}${varSessionHostLocationAcronym}' //var varVmssFlexNamePrefix = avdUseCustomNaming ? '${vmssFlexCustomNamePrefix}-${varComputeStorageResourcesNamingStandard}' : 'vmss-${varComputeStorageResourcesNamingStandard}' var varStorageManagedIdentityName = 'id-storage-${varComputeStorageResourcesNamingStandard}-001' var varAlaWorkspaceName = avdUseCustomNaming @@ -1425,6 +1425,10 @@ module smbStorage './modules/sharedModules/smbStorage.bicep' = if (createFslogix useCustomNaming: avdUseCustomNaming fslogixFileShareCustomName: fslogixFileShareCustomName appAttachFileShareCustomName: appAttachFileShareCustomName + storageAccountPrefixCustomName: storageAccountPrefixCustomName + anfAccountCustomName: anfAccountCustomName + deploymentEnvironmentOneCharacter: varDeploymentEnvironmentOneCharacter + computeStorageResourcesNamingStandard: varComputeStorageResourcesNamingStandard fslogixFileShareQuotaSize: fslogixFileShareQuotaSize appAttachFileShareQuotaSize: appAttachFileShareQuotaSize fslogixStoragePerformance: fslogixStoragePerformance diff --git a/workload/bicep/modules/sharedModules/smbStorage.bicep b/workload/bicep/modules/sharedModules/smbStorage.bicep index 793a2eef2..db6768996 100644 --- a/workload/bicep/modules/sharedModules/smbStorage.bicep +++ b/workload/bicep/modules/sharedModules/smbStorage.bicep @@ -25,12 +25,25 @@ param storageService string @description('Indicates whether to use custom naming for AVD.') param useCustomNaming bool +@description('The naming standard for compute storage resources coming from the main template.') +param computeStorageResourcesNamingStandard string + @description('The custom name for the FSLogix file share.') param fslogixFileShareCustomName string = '' @description('The custom name for the App Attach file share.') param appAttachFileShareCustomName string = '' +@maxLength(2) +@sys.description('AVD FSLogix and App Attach storage account prefix custom name.') +param storageAccountPrefixCustomName string = 'st' + +@description('The custom name for the ANF account.') +param anfAccountCustomName string = '' + +@description('Deployment prefix one character.') +param deploymentEnvironmentOneCharacter string + @description('The FSLogix file share quota size in GiBs.') param fslogixFileShareQuotaSize int @@ -178,7 +191,7 @@ var varFslogixAnfVolume = createFslogixDeployment ? [ protocolTypes: [ 'CIFS' ] - subnetResourceId: + subnetResourceId: anfSubnetResourceId creationToken: varFslogixFileShareName smbContinuouslyAvailable: true securityStyle: 'ntfs' @@ -198,7 +211,7 @@ var varAppAttchAnfVolume = createAppAttachDeployment ? [ protocolTypes: [ 'CIFS' ] - subnetResourceId: anfSubnetId + subnetResourceId: anfSubnetResourceId creationToken: varAppAttachFileShareName smbContinuouslyAvailable: true securityStyle: 'ntfs' @@ -206,16 +219,16 @@ var varAppAttchAnfVolume = createAppAttachDeployment ? [ ] : [] var varAnfVolumes = union(varFslogixAnfVolume, varAppAttchAnfVolume) var varFslogixStorageName = useCustomNaming - ? '${storageAccountPrefixCustomName}fsl${deploymentPrefix}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' - : 'stfsl${deploymentPrefix}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' -var varAnfAccountName = useCustomNaming ? anfAccountCustomName : 'anf-acc-${varComputeStorageResourcesNamingStandard}-001' -var varAnfCapacityPoolName = 'anf-cpool-${varComputeStorageResourcesNamingStandard}-001' + ? '${storageAccountPrefixCustomName}fsl${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' + : 'stfsl${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' +var varAnfAccountName = useCustomNaming ? anfAccountCustomName : 'anf-acc-${computeStorageResourcesNamingStandard}-001' +var varAnfCapacityPoolName = 'anf-cpool-${computeStorageResourcesNamingStandard}-001' var varFslogixStorageFqdn = createFslogixDeployment ? ((storageService == 'AzureFiles') ? '${varFslogixStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varFslogixFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' var varAppAttachStorageFqdn = createAppAttachDeployment ? ((storageService == 'AzureFiles') ? '${varAppAttachStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varAppAttachFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' var varAppAttachStorageName = useCustomNaming - ? '${storageAccountPrefixCustomName}appa${deploymentPrefix}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' - : 'stappa${deploymentPrefix}${varDeploymentEnvironmentComputeStorage}${varNamingUniqueStringThreeChar}' -var varManagementVmName = 'vmmgmt${deploymentPrefix}${varDeploymentEnvironmentComputeStorage}${locationAcronym}' + ? '${storageAccountPrefixCustomName}appa${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' + : 'stappa${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' +var varManagementVmName = 'vmmgmt${deploymentPrefix}${deploymentEnvironmentOneCharacter}${locationAcronym}' var varFslogixSharePath = createFslogixDeployment ? (storageService == 'AzureFiles' ? '\\\\${varFslogixStorageName}.file.${environment().suffixes.storage}\\${varFslogixFileShareName}' @@ -228,7 +241,7 @@ var varAppAttachSharePath = createAppAttachDeployment : (storageService == 'ANF' ? anf.outputs.anfAppAttachVolumeResourceId : '') ) : '' -var varCreateStorageDeployment = (createFslogixDeployment || varCreateAppAttachDeployment == true) ? true : false +var varCreateStorageDeployment = (createFslogixDeployment || createAppAttachDeployment == true) ? true : false var varFslogixStoragePerformance = fslogixStoragePerformance =='Ultra' ? 'Premium' : fslogixStoragePerformance @@ -249,7 +262,6 @@ var varStorageToDomainScriptUri = '${varBaseScriptUri}scripts/Manual-DSC-Storage var varStorageToDomainScript = './Manual-DSC-Storage-Scripts.ps1' var varOuStgPath = !empty(storageOuPath) ? '"${storageOuPath}"' : '"${varDefaultStorageOuPath}"' var varDefaultStorageOuPath = (avdIdentityServiceProvider == 'EntraDS') ? 'AADDC Computers' : 'Computers' -var varMarketPlaceGalleryWindows = loadJsonContent('../variables/osMarketPlaceImages.json') var varStorageCustomOuPath = !empty(storageOuPath) ? 'true' : 'false' @@ -275,13 +287,13 @@ resource avdWrklKeyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' exist module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && (!contains(avdIdentityServiceProvider, 'EntraID'))) { name: 'Storage-FSLogix-ANF-${time}' params: { - anfAccountName: varAnfAccountName - anfCapacityPoolName: varAnfCapacityPoolName - anfVolumes: varAnfVolumes - anfSmbServerNamePrefix: varAnfSmbServerNamePrefix + accountName: varAnfAccountName + capacityPoolName: varAnfCapacityPoolName + volumes: varAnfVolumes + smbServerNamePrefix: varAnfSmbServerNamePrefix capacityPoolSize: varAnfCapacityPoolSize dnsServers: customDnsIps - anfPerformance: fslogixStoragePerformance + performance: fslogixStoragePerformance createFslogixStorage: createFslogixDeployment createAppAttachStorage: createAppAttachDeployment // vmLocalUserName: avdVmLocalUserName From 7b59dd40446749b706670de2a6079632726b4ba6 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 26 Mar 2025 16:17:38 -0500 Subject: [PATCH 12/55] updates --- workload/bicep/deploy-baseline.bicep | 62 +++------- .../modules/azureNetappFiles/deploy.bicep | 91 +++----------- .../modules/sharedModules/smbStorage.bicep | 114 ++++++++++-------- 3 files changed, 100 insertions(+), 167 deletions(-) diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index 7a3b0f4a0..065a63ae0 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -1375,76 +1375,46 @@ module wrklKeyVault '../../avm/1.0.0/res/key-vault/vault/main.bicep' = { ] } -// Management VM deployment -module managementVm './modules/sharedModules/managementVm.bicep' = if (avdIdentityServiceProvider != 'EntraID' && (createFslogixDeployment || varCreateAppAttachDeployment)) { - name: 'Storage-MGMT-VM-${time}' - params: { - diskEncryptionSetResourceId: diskZeroTrust ? zeroTrust.outputs.ztDiskEncryptionSetResourceId : '' - identityServiceProvider: avdIdentityServiceProvider - managementVmName: varManagementVmName - computeTimeZone: varTimeZoneSessionHosts - applicationSecurityGroupResourceId: (avdDeploySessionHosts || createFslogixDeployment || varCreateAppAttachDeployment) - ? '${networking.outputs.applicationSecurityGroupResourceId}' - : '' - domainJoinUserName: avdDomainJoinUserName - wrklKvName: varWrklKvName - serviceObjectsRgName: varServiceObjectsRgName - identityDomainName: identityDomainName - ouPath: varMgmtVmSpecs.ouPath - osDiskType: varMgmtVmSpecs.osDiskType - location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation - mgmtVmSize: varMgmtVmSpecs.mgmtVmSize - subnetId: varMgmtVmSpecs.subnetId - enableAcceleratedNetworking: varMgmtVmSpecs.enableAcceleratedNetworking - securityType: securityType == 'Standard' ? '' : securityType - secureBootEnabled: secureBootEnabled - vTpmEnabled: vTpmEnabled - vmLocalUserName: avdVmLocalUserName - workloadSubsId: avdWorkloadSubsId - encryptionAtHost: diskZeroTrust - storageManagedIdentityResourceId: varCreateStorageDeployment && avdIdentityServiceProvider != 'EntraID' - ? identity.outputs.managedIdentityStorageResourceId - : '' - osImage: varMgmtVmSpecs.osImage - tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags - } - dependsOn: [ - baselineStorageResourceGroup - wrklKeyVault - ] -} - // FSLogix and/or App Attach deployment module smbStorage './modules/sharedModules/smbStorage.bicep' = if (createFslogixDeployment || createAppAttachDeployment) { name: 'SMB-Storage-${time}' - scope: resourceGroup('${avdWorkloadSubsId}', '${varStorageObjectsRgName}') + scope: subscription('${avdWorkloadSubsId}') params: { deploymentPrefix: varDeploymentPrefixLowercase deploymentEnvironment: varDeploymentEnvironmentLowercase storageService: storageService useCustomNaming: avdUseCustomNaming + availability: availability + createFslogixDeployment: createFslogixDeployment + createAppAttachDeployment: createAppAttachDeployment fslogixFileShareCustomName: fslogixFileShareCustomName appAttachFileShareCustomName: appAttachFileShareCustomName storageAccountPrefixCustomName: storageAccountPrefixCustomName anfAccountCustomName: anfAccountCustomName + deployMonitoring: avdDeployMonitoring + deploymentEnvironmentOneCharacter: varDeploymentEnvironmentOneCharacter computeStorageResourcesNamingStandard: varComputeStorageResourcesNamingStandard fslogixFileShareQuotaSize: fslogixFileShareQuotaSize appAttachFileShareQuotaSize: appAttachFileShareQuotaSize fslogixStoragePerformance: fslogixStoragePerformance appAttachStoragePerformance: appAttachStoragePerformance - anfSubnetResourceId: createAvdVnet ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAnfSubnetName}' : existingVnetAnfSubnetResourceId + anfSubnetResourceId: createAvdVnet + ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAnfSubnetName}' + : existingVnetAnfSubnetResourceId vmsSubnetResourceId: createAvdVnet - ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAvdSubnetName}' + ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAvdSubnetName}' + : existingVnetAvdSubnetResourceId + privateEndpointSubnetResourceId: createAvdVnet + ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetPrivateEndpointSubnetName}' : existingVnetAvdSubnetResourceId - privateEndpointSubnetId: location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation locationAcronym: avdDeploySessionHosts ? varSessionHostLocationAcronym : avdManagementPlaneLocation - + managementVmOsImage: managementVmOsImage + keyVaultResourceId: wrklKeyVault.outputs.resourceId } dependsOn: [ - baselineResourceGroups - monitoringDiagnosticSettings + baselineStorageResourceGroup ] } diff --git a/workload/bicep/modules/azureNetappFiles/deploy.bicep b/workload/bicep/modules/azureNetappFiles/deploy.bicep index 684efc034..e5f7bba79 100644 --- a/workload/bicep/modules/azureNetappFiles/deploy.bicep +++ b/workload/bicep/modules/azureNetappFiles/deploy.bicep @@ -14,17 +14,11 @@ param subId string @sys.description('Resource Group Name where to deploy Azure NetApp Files.') param storageObjectsRgName string -@sys.description('Resource Group Name for management VM and keyvault.') -param serviceObjectsRgName string - -@sys.description('Required, The service providing domain services for Azure Virtual Desktop.') -param identityServiceProvider string - @sys.description('ANF account name.') -param anfAccountName string +param accountName string @sys.description('Capacity pool volume name.') -param anfCapacityPoolName string +param capacityPoolName string @sys.description('Capacity pool volume name.') param createFslogixStorage bool @@ -33,10 +27,10 @@ param createFslogixStorage bool param createAppAttachStorage bool @sys.description('ANF volumes.') -param anfVolumes array +param volumes array @sys.description('ANF SMB prefix.') -param anfSmbServerNamePrefix string +param smbServerNamePrefix string @sys.description('DNS servers IPs.') param dnsServers string @@ -47,62 +41,33 @@ param location string @sys.description('Identity domain name.') param identityDomainName string +@sys.description('Organizational Unit (OU) storage path for domain join.') +param ouStgPath string + @sys.description('Keyvault resource ID to get credentials from.') -param kvResourceId string +param keyVaultResourceId string @sys.description('AVD session host domain join credentials.') param domainJoinUserName string @sys.description('ANF performance tier.') -param anfPerformance string +param performance string @sys.description('ANF capacity pool size in TiBs.') param capacityPoolSize int = 4 -@sys.description('Script name for adding storage account to Active Directory.') -param storageToDomainScript string - -@sys.description('URI for the script for adding the storage account to Active Directory.') -param storageToDomainScriptUri string - @sys.description('Tags to be applied to resources') param tags object = {} -@sys.description('Name for management virtual machine. for tools and to join Azure Files to domain.') -param managementVmName string - @sys.description('Do not modify, used to set unique value for resource deployment.') param time string = utcNow() -@sys.description('Storage service provider.') -param storageService string - -@sys.description('Identity name array to grant RBAC role to access AVD application group and NTFS permissions.') -param securityPrincipalName string - -//parameters for domain join -@sys.description('Sets location of DSC Agent.') -param dscAgentPackageLocation string - -@sys.description('Custom OU path for storage.') -param storageCustomOuPath string - -@sys.description('OU Storage Path') -param ouStgPath string = '' - -@sys.description('Managed Identity Client ID') -param managedIdentityClientId string - // =========== // // Variable declaration // // =========== // -var varAzureCloudName = environment().name -var varSecurityPrincipalName = !empty(securityPrincipalName) ? securityPrincipalName : 'none' -// var varStorageFqdn = azureNetAppFiles ????????????? -// var varStorageToDomainScriptArgs = '-StorageService ${storageService} -DscPath ${dscAgentPackageLocation} -StoragePurpose ${storagePurpose} -DomainName ${identityDomainName} -IdentityServiceProvider ${identityServiceProvider} -AzureCloudEnvironment ${varAzureCloudName} -SubscriptionId ${subId} -AdminUserName ${domainJoinUserName} -CustomOuPath ${storageCustomOuPath} -OUName ${ouStgPath} -ShareName ${subId} -ClientId ${managedIdentityClientId} -SecurityPrincipalName "${varSecurityPrincipalName}" -StorageFqdn ${varStorageFqdn} ' -var varKvSubId = split(kvResourceId, '/')[2] -var varKvRgName = split(kvResourceId, '/')[4] -var varKvName = split(kvResourceId, '/')[8] +var varKeyVaultSubId = split(keyVaultResourceId, '/')[2] +var varKeyVaultRgName = split(keyVaultResourceId, '/')[4] +var varKeyVaultName = split(keyVaultResourceId, '/')[8] // =========== // @@ -111,8 +76,8 @@ var varKvName = split(kvResourceId, '/')[8] // Call on the KV. resource keyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { - name: varKvName - scope: resourceGroup('${varKvSubId}', '${varKvRgName}') + name: varKeyVaultName + scope: resourceGroup('${varKeyVaultSubId}', '${varKeyVaultRgName}') } // Provision the Azure NetApp Files. @@ -120,44 +85,28 @@ module azureNetAppFiles '../../../../avm/1.1.0/res/net-app/net-app-account/main. scope: resourceGroup('${subId}', '${storageObjectsRgName}') name: 'Storage-ANF-${time}' params: { - name: anfAccountName - adName: anfAccountName + name: accountName + adName: accountName domainName: identityDomainName domainJoinUser: domainJoinUserName domainJoinPassword: keyVaultget.getSecret('domainJoinUserPassword') //domainJoinOU: replace(ouStgPath, '"', '\\"') dnsServers: dnsServers - smbServerNamePrefix: anfSmbServerNamePrefix + smbServerNamePrefix: smbServerNamePrefix location: location // aesEncryption: ************* // customerManagedKey: ************* capacityPools:[ { - name: anfCapacityPoolName - serviceLevel: anfPerformance + name: capacityPoolName + serviceLevel: performance size: capacityPoolSize * 1073741824 - volumes: anfVolumes + volumes: volumes } ] tags: tags } } -// Custom Extension call in on the DSC script to set NTFS permissions. -// module addShareToDomainScript '../sharedModules/smbUtilities.bicep' = { -// scope: resourceGroup('${subId}', '${serviceObjectsRgName}') -// name: 'Add-${storagePurpose}-Storage-Setup-${time}' -// params: { -// location: location -// virtualMachineName: managementVmName -// file: storageToDomainScript -// scriptArguments: varStorageToDomainScriptArgs -// adminUserPassword: keyVaultget.getSecret('domainJoinUserName') -// baseScriptUri: storageToDomainScriptUri -// } -// dependsOn: [ -// azureNetAppFiles -// ] -// } // =========== // // Outputs // diff --git a/workload/bicep/modules/sharedModules/smbStorage.bicep b/workload/bicep/modules/sharedModules/smbStorage.bicep index db6768996..f2d7bedab 100644 --- a/workload/bicep/modules/sharedModules/smbStorage.bicep +++ b/workload/bicep/modules/sharedModules/smbStorage.bicep @@ -14,7 +14,7 @@ param deploymentPrefix string param deploymentEnvironment string @description('The session host location acronym derived from the resource group location.') -param location string = resourceGroup().location +param location string @description('The session host or AVD management plane location acronym For example, "eus" for East US.') param locationAcronym string @@ -34,6 +34,9 @@ param fslogixFileShareCustomName string = '' @description('The custom name for the App Attach file share.') param appAttachFileShareCustomName string = '' +@description('The OS image for the management VM.') +param managementVmOsImage string + @maxLength(2) @sys.description('AVD FSLogix and App Attach storage account prefix custom name.') param storageAccountPrefixCustomName string = 'st' @@ -44,6 +47,9 @@ param anfAccountCustomName string = '' @description('Deployment prefix one character.') param deploymentEnvironmentOneCharacter string +@description('The resource ID of the Key Vault.') +param keyVaultResourceId string + @description('The FSLogix file share quota size in GiBs.') param fslogixFileShareQuotaSize int @@ -57,25 +63,22 @@ param fslogixStoragePerformance string param appAttachStoragePerformance string @description('Subnet resource ID for ANF volumes.') -param anfSubnetResourceId bool +param anfSubnetResourceId string @description('Subnet resource ID for VMs.') -param vmsSubnetResourceId bool +param vmsSubnetResourceId string @description('Subnet resource ID for private endpoints.') -param privateEndpointSubnetResourceId bool +param privateEndpointSubnetResourceId string @description('The existing VNet AVD subnet resource ID.') param existingVnetAvdSubnetResourceId string = '' -@description('The existing VNet private endpoint subnet resource ID.') -param existingVnetPrivateEndpointSubnetResourceId string = '' - @description('The availability setting (AvailabilityZones or other).') param availability string @description('The custom DNS IPs.') -param customDnsIps array = [] +param dnsServers array = [] @description('The AVD identity service provider (e.g., EntraDS).') param avdIdentityServiceProvider string @@ -89,12 +92,6 @@ param serviceObjectsRgName string @description('The storage objects resource group name.') param varStorageObjectsRgName string -@description('The AVD session host location.') -param avdSessionHostLocation string - -@description('The AVD management plane location.') -param avdManagementPlaneLocation string - @description('The AVD session hosts size.') param avdSessionHostsSize string @@ -129,7 +126,7 @@ param identityDomainGuid string = '' param deployPrivateEndpointKeyvaultStorage bool @description('Indicates whether to deploy monitoring.') -param avdDeployMonitoring bool +param deployMonitoring bool @description('Indicates whether to deploy AVD session hosts.') param avdDeploySessionHosts bool @@ -223,8 +220,8 @@ var varFslogixStorageName = useCustomNaming : 'stfsl${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' var varAnfAccountName = useCustomNaming ? anfAccountCustomName : 'anf-acc-${computeStorageResourcesNamingStandard}-001' var varAnfCapacityPoolName = 'anf-cpool-${computeStorageResourcesNamingStandard}-001' -var varFslogixStorageFqdn = createFslogixDeployment ? ((storageService == 'AzureFiles') ? '${varFslogixStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varFslogixFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' -var varAppAttachStorageFqdn = createAppAttachDeployment ? ((storageService == 'AzureFiles') ? '${varAppAttachStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varAppAttachFileShareName}...${avdSessionHostLocation}.netapp.azure.com' : '') : '' +var varFslogixStorageFqdn = createFslogixDeployment ? ((storageService == 'AzureFiles') ? '${varFslogixStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varFslogixFileShareName}...${location}.netapp.azure.com' : '') : '' +var varAppAttachStorageFqdn = createAppAttachDeployment ? ((storageService == 'AzureFiles') ? '${varAppAttachStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varAppAttachFileShareName}...${location}.netapp.azure.com' : '') : '' var varAppAttachStorageName = useCustomNaming ? '${storageAccountPrefixCustomName}appa${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' : 'stappa${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' @@ -263,8 +260,7 @@ var varStorageToDomainScript = './Manual-DSC-Storage-Scripts.ps1' var varOuStgPath = !empty(storageOuPath) ? '"${storageOuPath}"' : '"${varDefaultStorageOuPath}"' var varDefaultStorageOuPath = (avdIdentityServiceProvider == 'EntraDS') ? 'AADDC Computers' : 'Computers' var varStorageCustomOuPath = !empty(storageOuPath) ? 'true' : 'false' - - +var varMarketPlaceGalleryWindows = loadJsonContent('../../../variables/osMarketPlaceImages.json') var varMgmtVmSpecs = { osImage: varMarketPlaceGalleryWindows[managementVmOsImage] osDiskType: 'Standard_LRS' @@ -285,51 +281,34 @@ resource avdWrklKeyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' exist // Azure NetApp Files module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && (!contains(avdIdentityServiceProvider, 'EntraID'))) { - name: 'Storage-FSLogix-ANF-${time}' + name: 'Storage-ANF-${time}' params: { accountName: varAnfAccountName capacityPoolName: varAnfCapacityPoolName volumes: varAnfVolumes smbServerNamePrefix: varAnfSmbServerNamePrefix capacityPoolSize: varAnfCapacityPoolSize - dnsServers: customDnsIps + dnsServers: dnsServers performance: fslogixStoragePerformance createFslogixStorage: createFslogixDeployment createAppAttachStorage: createAppAttachDeployment - // vmLocalUserName: avdVmLocalUserName - // fileShareName: varFslogixFileShareName - // fileShareMultichannel: (fslogixStoragePerformance == 'Premium') ? true : false - // storageSku: varFslogixStorageSku - // fileShareQuotaSize: fslogixFileShareQuotaSize - storageToDomainScript: varStorageToDomainScript - storageToDomainScriptUri: varStorageToDomainScriptUri - identityServiceProvider: avdIdentityServiceProvider - dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation - storageCustomOuPath: varStorageCustomOuPath - managementVmName: varManagementVmName - storageService: storageService - // deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage ouStgPath: !empty(storageOuPath) ? storageOuPath : varDefaultStorageOuPath - managedIdentityClientId: varCreateStorageDeployment ? identity.outputs.managedIdentityStorageClientId : '' - securityPrincipalName: !empty(varSecurityPrincipalName) ? varSecurityPrincipalName : '' domainJoinUserName: avdDomainJoinUserName - kvResourceId: wrklKeyVault.outputs.resourceId - serviceObjectsRgName: varServiceObjectsRgName + keyVaultResourceId: keyVaultResourceId identityDomainName: identityDomainName // identityDomainGuid: identityDomainGuid - location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation + location: location storageObjectsRgName: varStorageObjectsRgName subId: subId tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags - // alaWorkspaceResourceId: avdDeployMonitoring + // alaWorkspaceResourceId: deployMonitoring // ? (deployAlaWorkspace // ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId // : alaExistingWorkspaceResourceId) // : '' } dependsOn: [ - baselineStorageResourceGroup - managementVm + ] } @@ -364,9 +343,7 @@ module fslogixAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (create identityDomainGuid: identityDomainGuid location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation storageObjectsRgName: varStorageObjectsRgName - privateEndpointSubnetId: createAvdVnet - ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetPrivateEndpointSubnetName}' - : existingVnetPrivateEndpointSubnetResourceId + privateEndpointSubnetId: privateEndpointSubnetResourceId vmsSubnetId: createAvdVnet ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAvdSubnetName}' : existingVnetAvdSubnetResourceId @@ -375,7 +352,7 @@ module fslogixAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (create : avdVnetPrivateDnsZoneFilesId subId: subId tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags - alaWorkspaceResourceId: avdDeployMonitoring + alaWorkspaceResourceId: deployMonitoring ? (deployAlaWorkspace ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId : alaExistingWorkspaceResourceId) @@ -419,9 +396,7 @@ module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (crea identityDomainGuid: identityDomainGuid location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation storageObjectsRgName: varStorageObjectsRgName - privateEndpointSubnetId: createAvdVnet - ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetPrivateEndpointSubnetName}' - : existingVnetPrivateEndpointSubnetResourceId + privateEndpointSubnetId: privateEndpointSubnetResourceId vmsSubnetId: createAvdVnet ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAvdSubnetName}' : existingVnetAvdSubnetResourceId @@ -430,7 +405,7 @@ module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (crea : avdVnetPrivateDnsZoneFilesId subId: subId tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags - alaWorkspaceResourceId: avdDeployMonitoring + alaWorkspaceResourceId: deployMonitoring ? (deployAlaWorkspace ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId : alaExistingWorkspaceResourceId) @@ -444,6 +419,45 @@ module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (crea ] } +// Management VM deployment +module managementVm './modules/sharedModules/managementVm.bicep' = if (avdIdentityServiceProvider != 'EntraID' && (createFslogixDeployment || varCreateAppAttachDeployment)) { + name: 'Storage-MGMT-VM-${time}' + params: { + diskEncryptionSetResourceId: diskZeroTrust ? zeroTrust.outputs.ztDiskEncryptionSetResourceId : '' + identityServiceProvider: avdIdentityServiceProvider + managementVmName: varManagementVmName + computeTimeZone: varTimeZoneSessionHosts + applicationSecurityGroupResourceId: (avdDeploySessionHosts || createFslogixDeployment || varCreateAppAttachDeployment) + ? '${networking.outputs.applicationSecurityGroupResourceId}' + : '' + domainJoinUserName: avdDomainJoinUserName + wrklKvName: varWrklKvName + serviceObjectsRgName: varServiceObjectsRgName + identityDomainName: identityDomainName + ouPath: varMgmtVmSpecs.ouPath + osDiskType: varMgmtVmSpecs.osDiskType + location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation + mgmtVmSize: varMgmtVmSpecs.mgmtVmSize + subnetId: varMgmtVmSpecs.subnetId + enableAcceleratedNetworking: varMgmtVmSpecs.enableAcceleratedNetworking + securityType: securityType == 'Standard' ? '' : securityType + secureBootEnabled: secureBootEnabled + vTpmEnabled: vTpmEnabled + vmLocalUserName: avdVmLocalUserName + workloadSubsId: avdWorkloadSubsId + encryptionAtHost: diskZeroTrust + storageManagedIdentityResourceId: varCreateStorageDeployment && avdIdentityServiceProvider != 'EntraID' + ? identity.outputs.managedIdentityStorageResourceId + : '' + osImage: varMgmtVmSpecs.osImage + tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags + } + dependsOn: [ + baselineStorageResourceGroup + wrklKeyVault + ] + } + // =========== // // Outputs // // =========== // From 3b7fb31c9d59f2cc3af0dcaf01567a71c77b01ec Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 26 Mar 2025 16:52:13 -0500 Subject: [PATCH 13/55] updates --- workload/bicep/deploy-baseline.bicep | 13 ++- .../modules/azureNetappFiles/deploy.bicep | 1 + .../modules/sharedModules/smbStorage.bicep | 107 ++++++------------ 3 files changed, 47 insertions(+), 74 deletions(-) diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index 065a63ae0..f7ab9cc71 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -1392,7 +1392,18 @@ module smbStorage './modules/sharedModules/smbStorage.bicep' = if (createFslogix storageAccountPrefixCustomName: storageAccountPrefixCustomName anfAccountCustomName: anfAccountCustomName deployMonitoring: avdDeployMonitoring - + managedIdentityClientId: ((createFslogixDeployment || createAppAttachDeployment == true) ? true : false) && avdIdentityServiceProvider != 'EntraID' + ? identity.outputs.managedIdentityStorageClientId + : '' + privateDnsZoneFilesResourceId: createPrivateDnsZones + ? networking.outputs.azureFilesDnsZoneResourceId + : avdVnetPrivateDnsZoneFilesId + serviceObjectsRgName: varServiceObjectsRgName + alaWorkspaceResourceId: avdDeployMonitoring + ? (deployAlaWorkspace + ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId + : alaExistingWorkspaceResourceId) + : '' deploymentEnvironmentOneCharacter: varDeploymentEnvironmentOneCharacter computeStorageResourcesNamingStandard: varComputeStorageResourcesNamingStandard fslogixFileShareQuotaSize: fslogixFileShareQuotaSize diff --git a/workload/bicep/modules/azureNetappFiles/deploy.bicep b/workload/bicep/modules/azureNetappFiles/deploy.bicep index e5f7bba79..d0ed2c8fd 100644 --- a/workload/bicep/modules/azureNetappFiles/deploy.bicep +++ b/workload/bicep/modules/azureNetappFiles/deploy.bicep @@ -105,6 +105,7 @@ module azureNetAppFiles '../../../../avm/1.1.0/res/net-app/net-app-account/main. } ] tags: tags + } } diff --git a/workload/bicep/modules/sharedModules/smbStorage.bicep b/workload/bicep/modules/sharedModules/smbStorage.bicep index f2d7bedab..abf73be22 100644 --- a/workload/bicep/modules/sharedModules/smbStorage.bicep +++ b/workload/bicep/modules/sharedModules/smbStorage.bicep @@ -50,6 +50,15 @@ param deploymentEnvironmentOneCharacter string @description('The resource ID of the Key Vault.') param keyVaultResourceId string +@description('The Azure Log Analytics workspace resource ID.') +param alaWorkspaceResourceId string + +@description('The private DNS zone files resource ID.') +param privateDnsZoneFilesResourceId string + +@description('The client ID of the managed identity.') +param managedIdentityClientId string + @description('The FSLogix file share quota size in GiBs.') param fslogixFileShareQuotaSize int @@ -71,14 +80,11 @@ param vmsSubnetResourceId string @description('Subnet resource ID for private endpoints.') param privateEndpointSubnetResourceId string -@description('The existing VNet AVD subnet resource ID.') -param existingVnetAvdSubnetResourceId string = '' - @description('The availability setting (AvailabilityZones or other).') param availability string @description('The custom DNS IPs.') -param dnsServers array = [] +param dnsServers string @description('The AVD identity service provider (e.g., EntraDS).') param avdIdentityServiceProvider string @@ -86,6 +92,9 @@ param avdIdentityServiceProvider string @description('The AVD domain join username.') param avdDomainJoinUserName string +@description('The AVD VM local username.') +param vmLocalUserName string + @description('The service objects resource group name.') param serviceObjectsRgName string @@ -125,9 +134,6 @@ param identityDomainGuid string = '' @description('Indicates whether to deploy private endpoints for Key Vault and storage.') param deployPrivateEndpointKeyvaultStorage bool -@description('Indicates whether to deploy monitoring.') -param deployMonitoring bool - @description('Indicates whether to deploy AVD session hosts.') param avdDeploySessionHosts bool @@ -137,18 +143,6 @@ param createFslogixDeployment bool @description('Indicates whether to create App Attach deployment.') param createAppAttachDeployment bool -@description('Indicates whether to create private DNS zones.') -param createPrivateDnsZones bool - -@description('The AVD VNet private DNS zone files ID.') -param avdVnetPrivateDnsZoneFilesId string = '' - -@description('The existing ALA workspace resource ID.') -param alaExistingWorkspaceResourceId string = '' - -@description('Indicates whether to deploy ALA workspace.') -param deployAlaWorkspace bool - @description('The deployment timestamp.') param time string = utcNow() @@ -273,12 +267,6 @@ var varMgmtVmSpecs = { // Deployments // // =========== // -// Call on the KV. -resource avdWrklKeyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { - name: wrklKvName - scope: resourceGroup('${subId}', '${serviceObjectsRgName}') -} - // Azure NetApp Files module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && (!contains(avdIdentityServiceProvider, 'EntraID'))) { name: 'Storage-ANF-${time}' @@ -296,7 +284,6 @@ module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && domainJoinUserName: avdDomainJoinUserName keyVaultResourceId: keyVaultResourceId identityDomainName: identityDomainName - // identityDomainGuid: identityDomainGuid location: location storageObjectsRgName: varStorageObjectsRgName subId: subId @@ -308,7 +295,7 @@ module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && // : '' } dependsOn: [ - + managementVm ] } @@ -317,10 +304,10 @@ module fslogixAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (create name: 'Storage-FSLogix-ST-${time}' params: { storagePurpose: 'fslogix' - vmLocalUserName: avdVmLocalUserName + vmLocalUserName: vmLocalUserName fileShareName: varFslogixFileShareName fileShareMultichannel: (varFslogixStoragePerformance == 'Premium') ? true : false - storageSku: varFslogixStorageSku + sku: varFslogixStorageSku fileShareQuotaSize: fslogixFileShareQuotaSize storageAccountFqdn: varFslogixStorageFqdn storageAccountName: varFslogixStorageName @@ -331,36 +318,24 @@ module fslogixAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (create storageCustomOuPath: varStorageCustomOuPath managementVmName: varManagementVmName deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage + keyVaultResourceId: keyVaultResourceId ouStgPath: varOuStgPath - managedIdentityClientId: varCreateStorageDeployment && avdIdentityServiceProvider != 'EntraID' - ? identity.outputs.managedIdentityStorageClientId - : '' + managedIdentityClientId: managedIdentityClientId securityPrincipalName: varSecurityPrincipalName domainJoinUserName: avdDomainJoinUserName - wrklKvName: varWrklKvName - serviceObjectsRgName: varServiceObjectsRgName + serviceObjectsRgName: serviceObjectsRgName identityDomainName: identityDomainName identityDomainGuid: identityDomainGuid - location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation + location: location storageObjectsRgName: varStorageObjectsRgName - privateEndpointSubnetId: privateEndpointSubnetResourceId - vmsSubnetId: createAvdVnet - ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAvdSubnetName}' - : existingVnetAvdSubnetResourceId - vnetPrivateDnsZoneFilesId: createPrivateDnsZones - ? networking.outputs.azureFilesDnsZoneResourceId - : avdVnetPrivateDnsZoneFilesId + privateEndpointSubnetResourceId: privateEndpointSubnetResourceId + vmsSubnetResourceId: vmsSubnetResourceId + privateDnsZoneFilesResourceId: privateDnsZoneFilesResourceId subId: subId tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags - alaWorkspaceResourceId: deployMonitoring - ? (deployAlaWorkspace - ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId - : alaExistingWorkspaceResourceId) - : '' + alaWorkspaceResourceId: alaWorkspaceResourceId } dependsOn: [ - baselineStorageResourceGroup - wrklKeyVault managementVm ] } @@ -370,7 +345,7 @@ module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (crea name: 'Storage-AppA-${time}' params: { storagePurpose: 'AppAttach' - vmLocalUserName: avdVmLocalUserName + vmLocalUserName: vmLocalUserName fileShareName: varAppAttachFileShareName fileShareMultichannel: (varAppAttachStoragePerformance == 'Premium') ? true : false storageSku: varAppAttachStorageSku @@ -385,36 +360,22 @@ module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (crea managementVmName: varManagementVmName deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage ouStgPath: varOuStgPath - managedIdentityClientId: varCreateStorageDeployment && avdIdentityServiceProvider != 'EntraID' - ? identity.outputs.managedIdentityStorageClientId - : '' + managedIdentityClientId: managedIdentityClientId securityPrincipalName: varSecurityPrincipalName domainJoinUserName: avdDomainJoinUserName - wrklKvName: varWrklKvName - serviceObjectsRgName: varServiceObjectsRgName + keyVaultResourceId: keyVaultResourceId + serviceObjectsRgName: serviceObjectsRgName identityDomainName: identityDomainName identityDomainGuid: identityDomainGuid - location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation + location: location storageObjectsRgName: varStorageObjectsRgName - privateEndpointSubnetId: privateEndpointSubnetResourceId - vmsSubnetId: createAvdVnet - ? '${networking.outputs.virtualNetworkResourceId}/subnets/${varVnetAvdSubnetName}' - : existingVnetAvdSubnetResourceId - vnetPrivateDnsZoneFilesId: createPrivateDnsZones - ? networking.outputs.azureFilesDnsZoneResourceId - : avdVnetPrivateDnsZoneFilesId - subId: subId + privateEndpointSubnetResourceId: privateEndpointSubnetResourceId + vmsSubnetResourceId: vmsSubnetResourceId + privateDnsZoneFilesResourceId: privateDnsZoneFilesResourceId tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags - alaWorkspaceResourceId: deployMonitoring - ? (deployAlaWorkspace - ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId - : alaExistingWorkspaceResourceId) - : '' + alaWorkspaceResourceId: alaWorkspaceResourceId } dependsOn: [ - fslogixAzureFilesStorage - baselineStorageResourceGroup - wrklKeyVault managementVm ] } @@ -431,7 +392,7 @@ module managementVm './modules/sharedModules/managementVm.bicep' = if (avdIdenti ? '${networking.outputs.applicationSecurityGroupResourceId}' : '' domainJoinUserName: avdDomainJoinUserName - wrklKvName: varWrklKvName + keyVaultResourceId: keyVaultResourceId serviceObjectsRgName: varServiceObjectsRgName identityDomainName: identityDomainName ouPath: varMgmtVmSpecs.ouPath From 6cd47c39d1fcb436b7a399643a7bc7ba5ba50d9f Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 26 Mar 2025 17:21:49 -0500 Subject: [PATCH 14/55] updates --- workload/bicep/deploy-baseline.bicep | 15 ++- .../modules/sharedModules/managementVm.bicep | 39 +++--- .../modules/sharedModules/smbStorage.bicep | 123 ++++++++++-------- .../modules/storageAzureFiles/deploy.bicep | 36 ++--- 4 files changed, 124 insertions(+), 89 deletions(-) diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index f7ab9cc71..280cd97c3 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -1385,13 +1385,26 @@ module smbStorage './modules/sharedModules/smbStorage.bicep' = if (createFslogix storageService: storageService useCustomNaming: avdUseCustomNaming availability: availability + domainJoinUserName: avdDomainJoinUserName + vmLocalUserName: avdVmLocalUserName + diskEncryptionSetResourceId: diskZeroTrust ? zeroTrust.outputs.ztDiskEncryptionSetResourceId : '' + sessionHostTimeZone: varTimeZoneSessionHosts createFslogixDeployment: createFslogixDeployment + securityType: securityType == 'Standard' ? '' : securityType + secureBootEnabled: secureBootEnabled + vTpmEnabled: vTpmEnabled + encryptionAtHost: diskZeroTrust + storageManagedIdentityResourceId: ((createFslogixDeployment || createAppAttachDeployment == true) ? true : false) && avdIdentityServiceProvider != 'EntraID' + ? identity.outputs.managedIdentityStorageResourceId + : '' + applicationSecurityGroupResourceId: (avdDeploySessionHosts || createFslogixDeployment || varCreateAppAttachDeployment) + ? '${networking.outputs.applicationSecurityGroupResourceId}' + : '' createAppAttachDeployment: createAppAttachDeployment fslogixFileShareCustomName: fslogixFileShareCustomName appAttachFileShareCustomName: appAttachFileShareCustomName storageAccountPrefixCustomName: storageAccountPrefixCustomName anfAccountCustomName: anfAccountCustomName - deployMonitoring: avdDeployMonitoring managedIdentityClientId: ((createFslogixDeployment || createAppAttachDeployment == true) ? true : false) && avdIdentityServiceProvider != 'EntraID' ? identity.outputs.managedIdentityStorageClientId : '' diff --git a/workload/bicep/modules/sharedModules/managementVm.bicep b/workload/bicep/modules/sharedModules/managementVm.bicep index 6ccdbfb07..fb8350cf5 100644 --- a/workload/bicep/modules/sharedModules/managementVm.bicep +++ b/workload/bicep/modules/sharedModules/managementVm.bicep @@ -8,7 +8,7 @@ targetScope = 'subscription' param diskEncryptionSetResourceId string @sys.description('AVD workload subscription ID, multiple subscriptions scenario.') -param workloadSubsId string +param subId string @sys.description('Virtual machine time zone.') param computeTimeZone string @@ -20,7 +20,7 @@ param identityServiceProvider string param serviceObjectsRgName string @sys.description('AVD subnet ID.') -param subnetId string +param subnetResourceId string @sys.description('Enable accelerated networking on the session host VMs.') param enableAcceleratedNetworking bool @@ -41,7 +41,7 @@ param location string param encryptionAtHost bool @sys.description('Session host VM size.') -param mgmtVmSize string +param vmSize string @sys.description('OS disk type for session host.') param osDiskType string @@ -58,8 +58,8 @@ param vmLocalUserName string @sys.description('Identity domain name.') param identityDomainName string -@sys.description('Keyvault name to get credentials from.') -param wrklKvName string +@sys.description('Keyvault resource ID to get credentials from.') +param keyVaultResourceId string @sys.description('AVD session host domain join credentials.') param domainJoinUserName string @@ -74,7 +74,7 @@ param applicationSecurityGroupResourceId string param tags object @sys.description('Name for management virtual machine. for tools and to join Azure Files to domain.') -param managementVmName string +param vmName string @sys.description('Do not modify, used to set unique value for resource deployment.') param time string = utcNow() @@ -82,7 +82,9 @@ param time string = utcNow() // =========== // // Variable declaration // // =========== // - +var varKeyVaultSubId = split(keyVaultResourceId, '/')[2] +var varKeyVaultRgName = split(keyVaultResourceId, '/')[4] +var varKeyVaultName = split(keyVaultResourceId, '/')[8] var varManagedDisk = empty(diskEncryptionSetResourceId) ? { storageAccountType: osDiskType } : { @@ -97,17 +99,18 @@ var varManagedDisk = empty(diskEncryptionSetResourceId) ? { // =========== // // Call on the KV. -resource avdWrklKeyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { - name: wrklKvName - scope: resourceGroup('${workloadSubsId}', '${serviceObjectsRgName}') +resource keyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { + name: varKeyVaultName + scope: resourceGroup('${varKeyVaultSubId}', '${varKeyVaultRgName}') } + // Provision temporary VM and add it to domain. module managementVm '../../../../avm/1.0.0/res/compute/virtual-machine/main.bicep' = { - scope: resourceGroup('${workloadSubsId}', '${serviceObjectsRgName}') + scope: resourceGroup('${subId}', '${serviceObjectsRgName}') name: 'MGMT-VM-${time}' params: { - name: managementVmName + name: vmName location: location timeZone: computeTimeZone managedIdentities: { @@ -119,7 +122,7 @@ module managementVm '../../../../avm/1.0.0/res/compute/virtual-machine/main.bice encryptionAtHost: encryptionAtHost zone: 0 osType: 'Windows' - vmSize: mgmtVmSize + vmSize: vmSize securityType: securityType secureBootEnabled: secureBootEnabled vTpmEnabled: vTpmEnabled @@ -131,16 +134,16 @@ module managementVm '../../../../avm/1.0.0/res/compute/virtual-machine/main.bice managedDisk: varManagedDisk } adminUsername: vmLocalUserName - adminPassword: avdWrklKeyVaultget.getSecret('vmLocalUserPassword') + adminPassword: keyVaultget.getSecret('vmLocalUserPassword') nicConfigurations: [ { - name: 'nic-01-${managementVmName}' + name: 'nic-01-${vmName}' deleteOption: 'Delete' enableAcceleratedNetworking: enableAcceleratedNetworking ipConfigurations: !empty(applicationSecurityGroupResourceId) ? [ { name: 'ipconfig01' - subnetResourceId: subnetId + subnetResourceId: subnetResourceId applicationSecurityGroups: [ { id: applicationSecurityGroupResourceId @@ -150,14 +153,14 @@ module managementVm '../../../../avm/1.0.0/res/compute/virtual-machine/main.bice ] : [ { name: 'ipconfig01' - subnetResourceId: subnetId + subnetResourceId: subnetResourceId } ] } ] // Join domain allowExtensionOperations: true - extensionDomainJoinPassword: avdWrklKeyVaultget.getSecret('domainJoinUserPassword') + extensionDomainJoinPassword: keyVaultget.getSecret('domainJoinUserPassword') extensionDomainJoinConfig: { enabled: contains(identityServiceProvider, 'EntraID') ? false: true settings: { diff --git a/workload/bicep/modules/sharedModules/smbStorage.bicep b/workload/bicep/modules/sharedModules/smbStorage.bicep index abf73be22..7b0f5f89a 100644 --- a/workload/bicep/modules/sharedModules/smbStorage.bicep +++ b/workload/bicep/modules/sharedModules/smbStorage.bicep @@ -77,9 +77,34 @@ param anfSubnetResourceId string @description('Subnet resource ID for VMs.') param vmsSubnetResourceId string +@description('The security type for the VM (e.g., TrustedLaunch, Standard).') +param securityType string + @description('Subnet resource ID for private endpoints.') param privateEndpointSubnetResourceId string +@description('The resource ID of the disk encryption set.') +param diskEncryptionSetResourceId string + +@description('Indicates whether encryption at host is enabled for the VM.') +param encryptionAtHost bool + + +@description('The resource ID of the managed identity for storage.') +param storageManagedIdentityResourceId string + +@description('Indicates whether secure boot is enabled for the VM.') +param secureBootEnabled bool + +@description('Indicates whether vTPM is enabled for the VM.') +param vTpmEnabled bool + +@description('The time zone for the session host.') +param sessionHostTimeZone string + +@description('The resource ID of the application security group.') +param applicationSecurityGroupResourceId string + @description('The availability setting (AvailabilityZones or other).') param availability string @@ -90,7 +115,7 @@ param dnsServers string param avdIdentityServiceProvider string @description('The AVD domain join username.') -param avdDomainJoinUserName string +param domainJoinUserName string @description('The AVD VM local username.') param vmLocalUserName string @@ -214,7 +239,13 @@ var varFslogixStorageName = useCustomNaming : 'stfsl${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' var varAnfAccountName = useCustomNaming ? anfAccountCustomName : 'anf-acc-${computeStorageResourcesNamingStandard}-001' var varAnfCapacityPoolName = 'anf-cpool-${computeStorageResourcesNamingStandard}-001' -var varFslogixStorageFqdn = createFslogixDeployment ? ((storageService == 'AzureFiles') ? '${varFslogixStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varFslogixFileShareName}...${location}.netapp.azure.com' : '') : '' +var varFslogixStorageFqdn = createFslogixDeployment + ? ((storageService == 'AzureFiles') + ? '${varFslogixStorageName}.file.${environment().suffixes.storage}' + : (storageService == 'ANF') + ? '${varFslogixFileShareName}...${location}.netapp.azure.com' + : '') + : '' var varAppAttachStorageFqdn = createAppAttachDeployment ? ((storageService == 'AzureFiles') ? '${varAppAttachStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varAppAttachFileShareName}...${location}.netapp.azure.com' : '') : '' var varAppAttachStorageName = useCustomNaming ? '${storageAccountPrefixCustomName}appa${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' @@ -255,17 +286,41 @@ var varOuStgPath = !empty(storageOuPath) ? '"${storageOuPath}"' : '"${varDefault var varDefaultStorageOuPath = (avdIdentityServiceProvider == 'EntraDS') ? 'AADDC Computers' : 'Computers' var varStorageCustomOuPath = !empty(storageOuPath) ? 'true' : 'false' var varMarketPlaceGalleryWindows = loadJsonContent('../../../variables/osMarketPlaceImages.json') -var varMgmtVmSpecs = { - osImage: varMarketPlaceGalleryWindows[managementVmOsImage] - osDiskType: 'Standard_LRS' - mgmtVmSize: avdSessionHostsSize //'Standard_D2ads_v5' - enableAcceleratedNetworking: false - ouPath: avdOuPath - subnetId: vmsSubnetResourceId - } // =========== // // Deployments // // =========== // +// Management VM deployment +module managementVm './managementVm.bicep' = if (avdIdentityServiceProvider != 'EntraID' && (createFslogixDeployment || createAppAttachDeployment)) { + name: 'Storage-MGMT-VM-${time}' + params: { + diskEncryptionSetResourceId: diskEncryptionSetResourceId + identityServiceProvider: avdIdentityServiceProvider + vmName: varManagementVmName + computeTimeZone: sessionHostTimeZone + applicationSecurityGroupResourceId: applicationSecurityGroupResourceId + domainJoinUserName: domainJoinUserName + keyVaultResourceId: keyVaultResourceId + serviceObjectsRgName: serviceObjectsRgName + identityDomainName: identityDomainName + ouPath: avdOuPath + osDiskType: 'Standard_LRS' + location: location + vmSize: avdSessionHostsSize //'Standard_D2ads_v5' + subnetResourceId: vmsSubnetResourceId + enableAcceleratedNetworking: true + securityType: securityType + secureBootEnabled: secureBootEnabled + vTpmEnabled: vTpmEnabled + vmLocalUserName: vmLocalUserName + subId: subId + encryptionAtHost: encryptionAtHost + storageManagedIdentityResourceId: storageManagedIdentityResourceId + osImage: varMarketPlaceGalleryWindows[managementVmOsImage] + tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags + } + dependsOn: [ + ] +} // Azure NetApp Files module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && (!contains(avdIdentityServiceProvider, 'EntraID'))) { @@ -281,7 +336,7 @@ module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && createFslogixStorage: createFslogixDeployment createAppAttachStorage: createAppAttachDeployment ouStgPath: !empty(storageOuPath) ? storageOuPath : varDefaultStorageOuPath - domainJoinUserName: avdDomainJoinUserName + domainJoinUserName: domainJoinUserName keyVaultResourceId: keyVaultResourceId identityDomainName: identityDomainName location: location @@ -307,7 +362,7 @@ module fslogixAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (create vmLocalUserName: vmLocalUserName fileShareName: varFslogixFileShareName fileShareMultichannel: (varFslogixStoragePerformance == 'Premium') ? true : false - sku: varFslogixStorageSku + storageSku: varFslogixStorageSku fileShareQuotaSize: fslogixFileShareQuotaSize storageAccountFqdn: varFslogixStorageFqdn storageAccountName: varFslogixStorageName @@ -322,7 +377,7 @@ module fslogixAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (create ouStgPath: varOuStgPath managedIdentityClientId: managedIdentityClientId securityPrincipalName: varSecurityPrincipalName - domainJoinUserName: avdDomainJoinUserName + domainJoinUserName: domainJoinUserName serviceObjectsRgName: serviceObjectsRgName identityDomainName: identityDomainName identityDomainGuid: identityDomainGuid @@ -362,7 +417,7 @@ module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (crea ouStgPath: varOuStgPath managedIdentityClientId: managedIdentityClientId securityPrincipalName: varSecurityPrincipalName - domainJoinUserName: avdDomainJoinUserName + domainJoinUserName: domainJoinUserName keyVaultResourceId: keyVaultResourceId serviceObjectsRgName: serviceObjectsRgName identityDomainName: identityDomainName @@ -372,6 +427,7 @@ module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (crea privateEndpointSubnetResourceId: privateEndpointSubnetResourceId vmsSubnetResourceId: vmsSubnetResourceId privateDnsZoneFilesResourceId: privateDnsZoneFilesResourceId + subId: subId tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags alaWorkspaceResourceId: alaWorkspaceResourceId } @@ -380,45 +436,6 @@ module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (crea ] } -// Management VM deployment -module managementVm './modules/sharedModules/managementVm.bicep' = if (avdIdentityServiceProvider != 'EntraID' && (createFslogixDeployment || varCreateAppAttachDeployment)) { - name: 'Storage-MGMT-VM-${time}' - params: { - diskEncryptionSetResourceId: diskZeroTrust ? zeroTrust.outputs.ztDiskEncryptionSetResourceId : '' - identityServiceProvider: avdIdentityServiceProvider - managementVmName: varManagementVmName - computeTimeZone: varTimeZoneSessionHosts - applicationSecurityGroupResourceId: (avdDeploySessionHosts || createFslogixDeployment || varCreateAppAttachDeployment) - ? '${networking.outputs.applicationSecurityGroupResourceId}' - : '' - domainJoinUserName: avdDomainJoinUserName - keyVaultResourceId: keyVaultResourceId - serviceObjectsRgName: varServiceObjectsRgName - identityDomainName: identityDomainName - ouPath: varMgmtVmSpecs.ouPath - osDiskType: varMgmtVmSpecs.osDiskType - location: avdDeploySessionHosts ? avdSessionHostLocation : avdManagementPlaneLocation - mgmtVmSize: varMgmtVmSpecs.mgmtVmSize - subnetId: varMgmtVmSpecs.subnetId - enableAcceleratedNetworking: varMgmtVmSpecs.enableAcceleratedNetworking - securityType: securityType == 'Standard' ? '' : securityType - secureBootEnabled: secureBootEnabled - vTpmEnabled: vTpmEnabled - vmLocalUserName: avdVmLocalUserName - workloadSubsId: avdWorkloadSubsId - encryptionAtHost: diskZeroTrust - storageManagedIdentityResourceId: varCreateStorageDeployment && avdIdentityServiceProvider != 'EntraID' - ? identity.outputs.managedIdentityStorageResourceId - : '' - osImage: varMgmtVmSpecs.osImage - tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags - } - dependsOn: [ - baselineStorageResourceGroup - wrklKeyVault - ] - } - // =========== // // Outputs // // =========== // diff --git a/workload/bicep/modules/storageAzureFiles/deploy.bicep b/workload/bicep/modules/storageAzureFiles/deploy.bicep index 60a619688..b82c11c57 100644 --- a/workload/bicep/modules/storageAzureFiles/deploy.bicep +++ b/workload/bicep/modules/storageAzureFiles/deploy.bicep @@ -9,7 +9,7 @@ targetScope = 'subscription' // ========== // @sys.description('AVD workload subscription ID, multiple subscriptions scenario.') -param workloadSubsId string +param subId string @sys.description('Resource Group Name for Azure Files.') param storageObjectsRgName string @@ -27,10 +27,10 @@ param storageAccountName string param fileShareName string @sys.description('Private endpoint subnet ID.') -param privateEndpointSubnetId string +param privateEndpointSubnetResourceId string @sys.description('VMs subnet ID.') -param vmsSubnetId string +param vmsSubnetResourceId string @sys.description('Location where to deploy resources.') param location string @@ -44,8 +44,8 @@ param identityDomainName string @sys.description('AD domain GUID.') param identityDomainGuid string -@sys.description('Keyvault name to get credentials from.') -param wrklKvName string +@sys.description('Key Vault Resource ID.') +param keyVaultResourceId string @sys.description('AVD session host domain join credentials.') param domainJoinUserName string @@ -60,7 +60,7 @@ param storageSku string param fileShareQuotaSize int @sys.description('Use Azure private DNS zones for private endpoints.') -param vnetPrivateDnsZoneFilesId string +param privateDnsZoneFilesResourceId string @sys.description('Script name for adding storage account to Active Directory.') param storageToDomainScript string @@ -69,7 +69,7 @@ param storageToDomainScript string param storageToDomainScriptUri string @sys.description('Tags to be applied to resources') -param tags object +param tags object = {} @sys.description('Name for management virtual machine. for tools and to join Azure Files to domain.') param managementVmName string @@ -108,12 +108,14 @@ param storageAccountFqdn string // =========== // // Variable declaration // // =========== // - +var varKeyVaultSubId = split(keyVaultResourceId, '/')[2] +var varKeyVaultRgName = split(keyVaultResourceId, '/')[4] +var varKeyVaultName = split(keyVaultResourceId, '/')[8] var varAzureCloudName = environment().name var varWrklStoragePrivateEndpointName = 'pe-${storageAccountName}-file' var varSecurityPrincipalName = !empty(securityPrincipalName) ? securityPrincipalName : 'none' var varAdminUserName = contains(identityServiceProvider, 'EntraID') ? vmLocalUserName : domainJoinUserName -var varStorageToDomainScriptArgs = '-DscPath ${dscAgentPackageLocation} -StorageAccountName ${storageAccountName} -StorageAccountRG ${storageObjectsRgName} -StoragePurpose ${storagePurpose} -DomainName ${identityDomainName} -IdentityServiceProvider ${identityServiceProvider} -AzureCloudEnvironment ${varAzureCloudName} -SubscriptionId ${workloadSubsId} -AdminUserName ${varAdminUserName} -CustomOuPath ${storageCustomOuPath} -OUName ${ouStgPath} -ShareName ${fileShareName} -ClientId ${managedIdentityClientId} -SecurityPrincipalName "${varSecurityPrincipalName}" -StorageAccountFqdn ${storageAccountFqdn} ' +var varStorageToDomainScriptArgs = '-DscPath ${dscAgentPackageLocation} -StorageAccountName ${storageAccountName} -StorageAccountRG ${storageObjectsRgName} -StoragePurpose ${storagePurpose} -DomainName ${identityDomainName} -IdentityServiceProvider ${identityServiceProvider} -AzureCloudEnvironment ${varAzureCloudName} -SubscriptionId ${subId} -AdminUserName ${varAdminUserName} -CustomOuPath ${storageCustomOuPath} -OUName ${ouStgPath} -ShareName ${fileShareName} -ClientId ${managedIdentityClientId} -SecurityPrincipalName "${varSecurityPrincipalName}" -StorageAccountFqdn ${storageAccountFqdn} ' var varDiagnosticSettings = !empty(alaWorkspaceResourceId) ? [ { @@ -128,13 +130,13 @@ var varDiagnosticSettings = !empty(alaWorkspaceResourceId) // Call on the KV. resource avdWrklKeyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { - name: wrklKvName - scope: resourceGroup('${workloadSubsId}', '${serviceObjectsRgName}') + name: varKeyVaultName + scope: resourceGroup('${varKeyVaultSubId}', '${varKeyVaultRgName}') } // Provision the storage account and Azure Files. module storageAndFile '../../../../avm/1.0.0/res/storage/storage-account/main.bicep' = { - scope: resourceGroup('${workloadSubsId}', '${storageObjectsRgName}') + scope: resourceGroup('${subId}', '${storageObjectsRgName}') name: 'Storage-${storagePurpose}-${time}' params: { name: storageAccountName @@ -168,7 +170,7 @@ module storageAndFile '../../../../avm/1.0.0/res/storage/storage-account/main.bi defaultAction: 'Deny' virtualNetworkRules: [ { - id: vmsSubnetId + id: vmsSubnetResourceId action: 'Allow' } ] @@ -196,12 +198,12 @@ module storageAndFile '../../../../avm/1.0.0/res/storage/storage-account/main.bi ? [ { name: varWrklStoragePrivateEndpointName - subnetResourceId: privateEndpointSubnetId + subnetResourceId: privateEndpointSubnetResourceId customNetworkInterfaceName: 'nic-01-${varWrklStoragePrivateEndpointName}' service: 'file' - privateDnsZoneGroupName: split(vnetPrivateDnsZoneFilesId, '/')[8] + privateDnsZoneGroupName: split(privateDnsZoneFilesResourceId, '/')[8] privateDnsZoneResourceIds: [ - vnetPrivateDnsZoneFilesId + privateDnsZoneFilesResourceId ] } ] @@ -213,7 +215,7 @@ module storageAndFile '../../../../avm/1.0.0/res/storage/storage-account/main.bi // Custom Extension call in on the DSC script to join Azure storage account to domain. module addShareToDomainScript '../sharedModules/smbUtilities.bicep' = if (identityServiceProvider != 'EntraID') { - scope: resourceGroup('${workloadSubsId}', '${serviceObjectsRgName}') + scope: resourceGroup('${subId}', '${serviceObjectsRgName}') name: 'Add-${storagePurpose}-Storage-Setup-${time}' params: { location: location From 50ccaad4bd30b89686c6c67618b4306295f2871f Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Thu, 27 Mar 2025 09:01:25 -0500 Subject: [PATCH 15/55] updates --- workload/bicep/deploy-baseline.bicep | 38 ++++++++-- .../{smbStorage.bicep => storage.bicep} | 75 ++++++++++--------- 2 files changed, 69 insertions(+), 44 deletions(-) rename workload/bicep/modules/sharedModules/{smbStorage.bicep => storage.bicep} (88%) diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index 280cd97c3..943de7b61 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -1007,6 +1007,7 @@ var varResourceGroups = [ // security Principals (you can add support for more than one because it is an array. Future) var varSecurityPrincipalId = !empty(avdSecurityGroups) ? avdSecurityGroups[0].objectId : '' var varSecurityPrincipalName = !empty(avdSecurityGroups) ? avdSecurityGroups[0].displayName : '' +var varCreateStorageDeployment = (createFslogixDeployment || createAppAttachDeployment) ? true : false // =========== // // Deployments // @@ -1077,8 +1078,12 @@ module monitoringDiagnosticSettings './modules/avdInsightsMonitoring/deploy.bice computeObjectsRgName: varComputeObjectsRgName serviceObjectsRgName: varServiceObjectsRgName dataCollectionRulesName: varDataCollectionRulesName - storageObjectsRgName: (createFslogixDeployment || createAppAttachDeployment) ? varStorageObjectsRgName : '' - networkObjectsRgName: (createAvdVnet) ? varNetworkObjectsRgName : '' + storageObjectsRgName: varCreateStorageDeployment + ? varStorageObjectsRgName + : '' + networkObjectsRgName: createAvdVnet + ? varNetworkObjectsRgName + : '' monitoringRgName: varMonitoringRgName deployCustomPolicyMonitoring: deployCustomPolicyMonitoring alaWorkspaceId: deployAlaWorkspace ? '' : alaExistingWorkspaceResourceId @@ -1376,7 +1381,7 @@ module wrklKeyVault '../../avm/1.0.0/res/key-vault/vault/main.bicep' = { } // FSLogix and/or App Attach deployment -module smbStorage './modules/sharedModules/smbStorage.bicep' = if (createFslogixDeployment || createAppAttachDeployment) { +module storage './modules/sharedModules/storage.bicep' = if (varCreateStorageDeployment) { name: 'SMB-Storage-${time}' scope: subscription('${avdWorkloadSubsId}') params: { @@ -1387,6 +1392,18 @@ module smbStorage './modules/sharedModules/smbStorage.bicep' = if (createFslogix availability: availability domainJoinUserName: avdDomainJoinUserName vmLocalUserName: avdVmLocalUserName + identityServiceProvider: avdIdentityServiceProvider + avdSessionHostsOuPath: avdOuPath + storageOuPath: storageOuPath + managementVmSize: avdDeploySessionHosts + ? avdSessionHostsSize + : 'Standard_D2ads_v5' + createResourceTags: createResourceTags + deployPrivateEndpointKeyvaultStorage: deployPrivateEndpointKeyvaultStorage + dnsServers: varAllDnsServers + identityDomainName: identityDomainName + storageObjectsRgName: varStorageObjectsRgName + baseScriptUri: varBaseScriptUri diskEncryptionSetResourceId: diskZeroTrust ? zeroTrust.outputs.ztDiskEncryptionSetResourceId : '' sessionHostTimeZone: varTimeZoneSessionHosts createFslogixDeployment: createFslogixDeployment @@ -1394,7 +1411,7 @@ module smbStorage './modules/sharedModules/smbStorage.bicep' = if (createFslogix secureBootEnabled: secureBootEnabled vTpmEnabled: vTpmEnabled encryptionAtHost: diskZeroTrust - storageManagedIdentityResourceId: ((createFslogixDeployment || createAppAttachDeployment == true) ? true : false) && avdIdentityServiceProvider != 'EntraID' + storageManagedIdentityResourceId: ((varCreateStorageDeployment) && avdIdentityServiceProvider != 'EntraID') ? identity.outputs.managedIdentityStorageResourceId : '' applicationSecurityGroupResourceId: (avdDeploySessionHosts || createFslogixDeployment || varCreateAppAttachDeployment) @@ -1405,7 +1422,7 @@ module smbStorage './modules/sharedModules/smbStorage.bicep' = if (createFslogix appAttachFileShareCustomName: appAttachFileShareCustomName storageAccountPrefixCustomName: storageAccountPrefixCustomName anfAccountCustomName: anfAccountCustomName - managedIdentityClientId: ((createFslogixDeployment || createAppAttachDeployment == true) ? true : false) && avdIdentityServiceProvider != 'EntraID' + managedIdentityClientId: (varCreateStorageDeployment && avdIdentityServiceProvider != 'EntraID') ? identity.outputs.managedIdentityStorageClientId : '' privateDnsZoneFilesResourceId: createPrivateDnsZones @@ -1436,6 +1453,9 @@ module smbStorage './modules/sharedModules/smbStorage.bicep' = if (createFslogix locationAcronym: avdDeploySessionHosts ? varSessionHostLocationAcronym : avdManagementPlaneLocation managementVmOsImage: managementVmOsImage keyVaultResourceId: wrklKeyVault.outputs.resourceId + customResourceTags: varCustomResourceTags + defaultTags: varAvdDefaultTags + identityDomainGuid: identityDomainGuid } dependsOn: [ baselineStorageResourceGroup @@ -1491,9 +1511,11 @@ module sessionHosts './modules/avdSessionHosts/deploy.bicep' = [ domainJoinUserPrincipalName: avdDomainJoinUserName enableAcceleratedNetworking: enableAcceleratedNetworking encryptionAtHost: diskZeroTrust - fslogixSharePath: varFslogixSharePath - fslogixStorageAccountResourceId: avdIdentityServiceProvider == 'EntraID' - ? fslogixAzureFilesStorage.outputs.storageAccountResourceId + fslogixSharePath: createFslogixDeployment + ? storage.outputs.fslogixFileSharePath + : '' + fslogixStorageAccountResourceId: (avdIdentityServiceProvider == 'EntraID' && createFslogixDeployment) + ? storage.outputs.fslogixStorageAccountResourceId : '' hostPoolResourceId: managementPLane.outputs.hostPoolResourceId identityDomainName: identityDomainName diff --git a/workload/bicep/modules/sharedModules/smbStorage.bicep b/workload/bicep/modules/sharedModules/storage.bicep similarity index 88% rename from workload/bicep/modules/sharedModules/smbStorage.bicep rename to workload/bicep/modules/sharedModules/storage.bicep index 7b0f5f89a..b5b24067f 100644 --- a/workload/bicep/modules/sharedModules/smbStorage.bicep +++ b/workload/bicep/modules/sharedModules/storage.bicep @@ -37,7 +37,6 @@ param appAttachFileShareCustomName string = '' @description('The OS image for the management VM.') param managementVmOsImage string -@maxLength(2) @sys.description('AVD FSLogix and App Attach storage account prefix custom name.') param storageAccountPrefixCustomName string = 'st' @@ -89,7 +88,6 @@ param diskEncryptionSetResourceId string @description('Indicates whether encryption at host is enabled for the VM.') param encryptionAtHost bool - @description('The resource ID of the managed identity for storage.') param storageManagedIdentityResourceId string @@ -111,41 +109,41 @@ param availability string @description('The custom DNS IPs.') param dnsServers string -@description('The AVD identity service provider (e.g., EntraDS).') -param avdIdentityServiceProvider string +@description('The identity service provider (e.g., EntraDS).') +param identityServiceProvider string -@description('The AVD domain join username.') +@description('The domain join username.') param domainJoinUserName string -@description('The AVD VM local username.') +@description('The VM local username.') param vmLocalUserName string @description('The service objects resource group name.') param serviceObjectsRgName string @description('The storage objects resource group name.') -param varStorageObjectsRgName string +param storageObjectsRgName string -@description('The AVD session hosts size.') -param avdSessionHostsSize string +@description('The VM size for the management VM.') +param managementVmSize string -@description('The AVD OU path.') -param avdOuPath string +@description('The OU path for AVD session hosts.') +param avdSessionHostsOuPath string @description('The storage OU path.') param storageOuPath string = '' @description('The custom resource tags.') -param varCustomResourceTags object = {} +param customResourceTags object = {} @description('The AVD default tags.') -param varAvdDefaultTags object = {} +param defaultTags object = {} @description('Indicates whether to create resource tags.') param createResourceTags bool @description('The base script URI.') -param varBaseScriptUri string +param baseScriptUri string @description('The security principal name.') param varSecurityPrincipalName string = '' @@ -159,9 +157,6 @@ param identityDomainGuid string = '' @description('Indicates whether to deploy private endpoints for Key Vault and storage.') param deployPrivateEndpointKeyvaultStorage bool -@description('Indicates whether to deploy AVD session hosts.') -param avdDeploySessionHosts bool - @description('Indicates whether to create FSLogix deployment.') param createFslogixDeployment bool @@ -251,19 +246,18 @@ var varAppAttachStorageName = useCustomNaming ? '${storageAccountPrefixCustomName}appa${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' : 'stappa${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' var varManagementVmName = 'vmmgmt${deploymentPrefix}${deploymentEnvironmentOneCharacter}${locationAcronym}' -var varFslogixSharePath = createFslogixDeployment +var varFslogixFileSharePath = createFslogixDeployment ? (storageService == 'AzureFiles' ? '\\\\${varFslogixStorageName}.file.${environment().suffixes.storage}\\${varFslogixFileShareName}' : (storageService == 'ANF' ? anf.outputs.anfFslogixVolumeResourceId : '') ) : '' -var varAppAttachSharePath = createAppAttachDeployment +var varAppAttachFileSharePath = createAppAttachDeployment ? (storageService == 'AzureFiles' ? '\\\\${varAppAttachStorageName}.file.${environment().suffixes.storage}\\${varAppAttachFileShareName}' : (storageService == 'ANF' ? anf.outputs.anfAppAttachVolumeResourceId : '') ) : '' -var varCreateStorageDeployment = (createFslogixDeployment || createAppAttachDeployment == true) ? true : false var varFslogixStoragePerformance = fslogixStoragePerformance =='Ultra' ? 'Premium' : fslogixStoragePerformance @@ -280,21 +274,21 @@ var varAppAttachStorageSku = varStorageAccountAvailability ? '${varAppAttachStoragePerformance}_ZRS' : '${varAppAttachStoragePerformance}_LRS' var varStorageAzureFilesDscAgentPackageLocation = 'https://github.com/Azure/avdaccelerator/raw/main/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip' -var varStorageToDomainScriptUri = '${varBaseScriptUri}scripts/Manual-DSC-Storage-Scripts.ps1' +var varStorageToDomainScriptUri = '${baseScriptUri}scripts/Manual-DSC-Storage-Scripts.ps1' var varStorageToDomainScript = './Manual-DSC-Storage-Scripts.ps1' var varOuStgPath = !empty(storageOuPath) ? '"${storageOuPath}"' : '"${varDefaultStorageOuPath}"' -var varDefaultStorageOuPath = (avdIdentityServiceProvider == 'EntraDS') ? 'AADDC Computers' : 'Computers' +var varDefaultStorageOuPath = (identityServiceProvider == 'EntraDS') ? 'AADDC Computers' : 'Computers' var varStorageCustomOuPath = !empty(storageOuPath) ? 'true' : 'false' var varMarketPlaceGalleryWindows = loadJsonContent('../../../variables/osMarketPlaceImages.json') // =========== // // Deployments // // =========== // // Management VM deployment -module managementVm './managementVm.bicep' = if (avdIdentityServiceProvider != 'EntraID' && (createFslogixDeployment || createAppAttachDeployment)) { +module managementVm './managementVm.bicep' = if (identityServiceProvider != 'EntraID' && (createFslogixDeployment || createAppAttachDeployment)) { name: 'Storage-MGMT-VM-${time}' params: { diskEncryptionSetResourceId: diskEncryptionSetResourceId - identityServiceProvider: avdIdentityServiceProvider + identityServiceProvider: identityServiceProvider vmName: varManagementVmName computeTimeZone: sessionHostTimeZone applicationSecurityGroupResourceId: applicationSecurityGroupResourceId @@ -302,10 +296,10 @@ module managementVm './managementVm.bicep' = if (avdIdentityServiceProvider != ' keyVaultResourceId: keyVaultResourceId serviceObjectsRgName: serviceObjectsRgName identityDomainName: identityDomainName - ouPath: avdOuPath + ouPath: avdSessionHostsOuPath osDiskType: 'Standard_LRS' location: location - vmSize: avdSessionHostsSize //'Standard_D2ads_v5' + vmSize: managementVmSize subnetResourceId: vmsSubnetResourceId enableAcceleratedNetworking: true securityType: securityType @@ -316,14 +310,14 @@ module managementVm './managementVm.bicep' = if (avdIdentityServiceProvider != ' encryptionAtHost: encryptionAtHost storageManagedIdentityResourceId: storageManagedIdentityResourceId osImage: varMarketPlaceGalleryWindows[managementVmOsImage] - tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags + tags: createResourceTags ? union(customResourceTags, defaultTags) : defaultTags } dependsOn: [ ] } // Azure NetApp Files -module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && (!contains(avdIdentityServiceProvider, 'EntraID'))) { +module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && (!contains(identityServiceProvider, 'EntraID'))) { name: 'Storage-ANF-${time}' params: { accountName: varAnfAccountName @@ -340,9 +334,9 @@ module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && keyVaultResourceId: keyVaultResourceId identityDomainName: identityDomainName location: location - storageObjectsRgName: varStorageObjectsRgName + storageObjectsRgName: storageObjectsRgName subId: subId - tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags + tags: createResourceTags ? union(customResourceTags, defaultTags) : defaultTags // alaWorkspaceResourceId: deployMonitoring // ? (deployAlaWorkspace // ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId @@ -368,7 +362,7 @@ module fslogixAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (create storageAccountName: varFslogixStorageName storageToDomainScript: varStorageToDomainScript storageToDomainScriptUri: varStorageToDomainScriptUri - identityServiceProvider: avdIdentityServiceProvider + identityServiceProvider: identityServiceProvider dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation storageCustomOuPath: varStorageCustomOuPath managementVmName: varManagementVmName @@ -382,12 +376,12 @@ module fslogixAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (create identityDomainName: identityDomainName identityDomainGuid: identityDomainGuid location: location - storageObjectsRgName: varStorageObjectsRgName + storageObjectsRgName: storageObjectsRgName privateEndpointSubnetResourceId: privateEndpointSubnetResourceId vmsSubnetResourceId: vmsSubnetResourceId privateDnsZoneFilesResourceId: privateDnsZoneFilesResourceId subId: subId - tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags + tags: createResourceTags ? union(customResourceTags, defaultTags) : defaultTags alaWorkspaceResourceId: alaWorkspaceResourceId } dependsOn: [ @@ -409,7 +403,7 @@ module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (crea storageAccountName: varAppAttachStorageName storageToDomainScript: varStorageToDomainScript storageToDomainScriptUri: varStorageToDomainScriptUri - identityServiceProvider: avdIdentityServiceProvider + identityServiceProvider: identityServiceProvider dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation storageCustomOuPath: varStorageCustomOuPath managementVmName: varManagementVmName @@ -423,12 +417,12 @@ module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (crea identityDomainName: identityDomainName identityDomainGuid: identityDomainGuid location: location - storageObjectsRgName: varStorageObjectsRgName + storageObjectsRgName: storageObjectsRgName privateEndpointSubnetResourceId: privateEndpointSubnetResourceId vmsSubnetResourceId: vmsSubnetResourceId privateDnsZoneFilesResourceId: privateDnsZoneFilesResourceId subId: subId - tags: createResourceTags ? union(varCustomResourceTags, varAvdDefaultTags) : varAvdDefaultTags + tags: createResourceTags ? union(customResourceTags, defaultTags) : defaultTags alaWorkspaceResourceId: alaWorkspaceResourceId } dependsOn: [ @@ -439,3 +433,12 @@ module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (crea // =========== // // Outputs // // =========== // + +output fslogixFileSharePath string = varFslogixFileSharePath +output appAttachFileSharePath string = varFslogixFileSharePath +output fslogixStorageAccountResourceId string = createFslogixDeployment + ? fslogixAzureFilesStorage.outputs.storageAccountResourceId + : '' +output appAttachStorageAccountResourceId string = createAppAttachDeployment + ? appAttachAzureFilesStorage.outputs.storageAccountResourceId + : '' From 387b052650a7cfc9b26b3a40901f7d6f2df259bb Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Thu, 27 Mar 2025 10:20:35 -0500 Subject: [PATCH 16/55] updates --- workload/bicep/deploy-baseline.bicep | 3 +- .../modules/azureNetappFiles/deploy.bicep | 5 +- .../modules/sharedModules/managementVm.bicep | 33 +- .../bicep/modules/sharedModules/storage.bicep | 376 ++++++++++-------- .../modules/storageAzureFiles/deploy.bicep | 23 +- 5 files changed, 248 insertions(+), 192 deletions(-) diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index 943de7b61..b2d2b456c 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -147,7 +147,7 @@ param existingVnetPrivateEndpointSubnetResourceId string = '' @sys.description('Existing virtual network subnet for ANF. (Default: "")') param existingVnetAnfSubnetResourceId string = '' -@sys.description('Existing hub virtual network for perring. (Default: "")') +@sys.description('Existing hub virtual network for peering. (Default: "")') param existingHubVnetResourceId string = '' @sys.description('AVD virtual network address prefixes. (Default: 10.10.0.0/16)') @@ -1404,6 +1404,7 @@ module storage './modules/sharedModules/storage.bicep' = if (varCreateStorageDep identityDomainName: identityDomainName storageObjectsRgName: varStorageObjectsRgName baseScriptUri: varBaseScriptUri + securityPrincipalName: varSecurityPrincipalName diskEncryptionSetResourceId: diskZeroTrust ? zeroTrust.outputs.ztDiskEncryptionSetResourceId : '' sessionHostTimeZone: varTimeZoneSessionHosts createFslogixDeployment: createFslogixDeployment diff --git a/workload/bicep/modules/azureNetappFiles/deploy.bicep b/workload/bicep/modules/azureNetappFiles/deploy.bicep index d0ed2c8fd..94ab367f3 100644 --- a/workload/bicep/modules/azureNetappFiles/deploy.bicep +++ b/workload/bicep/modules/azureNetappFiles/deploy.bicep @@ -42,7 +42,7 @@ param location string param identityDomainName string @sys.description('Organizational Unit (OU) storage path for domain join.') -param ouStgPath string +param storageOuPath string @sys.description('Keyvault resource ID to get credentials from.') param keyVaultResourceId string @@ -69,7 +69,6 @@ var varKeyVaultSubId = split(keyVaultResourceId, '/')[2] var varKeyVaultRgName = split(keyVaultResourceId, '/')[4] var varKeyVaultName = split(keyVaultResourceId, '/')[8] - // =========== // // Deployments // // =========== // @@ -90,7 +89,7 @@ module azureNetAppFiles '../../../../avm/1.1.0/res/net-app/net-app-account/main. domainName: identityDomainName domainJoinUser: domainJoinUserName domainJoinPassword: keyVaultget.getSecret('domainJoinUserPassword') - //domainJoinOU: replace(ouStgPath, '"', '\\"') + //domainJoinOU: replace(storageOuPath, '"', '\\"') dnsServers: dnsServers smbServerNamePrefix: smbServerNamePrefix location: location diff --git a/workload/bicep/modules/sharedModules/managementVm.bicep b/workload/bicep/modules/sharedModules/managementVm.bicep index fb8350cf5..e65b173cb 100644 --- a/workload/bicep/modules/sharedModules/managementVm.bicep +++ b/workload/bicep/modules/sharedModules/managementVm.bicep @@ -1,4 +1,7 @@ targetScope = 'subscription' +metadata name = 'AVD LZA storage management VM' +metadata description = 'This module deploys a management VM to join Azure Files to domain and for tools.' +metadata owner = 'Azure/avdaccelerator' // ========== // // Parameters // @@ -19,7 +22,7 @@ param identityServiceProvider string @sys.description('Resource Group Name for Azure Files.') param serviceObjectsRgName string -@sys.description('AVD subnet ID.') +@sys.description('Subnet resource ID.') param subnetResourceId string @sys.description('Enable accelerated networking on the session host VMs.') @@ -85,14 +88,15 @@ param time string = utcNow() var varKeyVaultSubId = split(keyVaultResourceId, '/')[2] var varKeyVaultRgName = split(keyVaultResourceId, '/')[4] var varKeyVaultName = split(keyVaultResourceId, '/')[8] -var varManagedDisk = empty(diskEncryptionSetResourceId) ? { - storageAccountType: osDiskType -} : { - diskEncryptionSet: { - id: diskEncryptionSetResourceId +var varManagedDisk = empty(diskEncryptionSetResourceId) + ? { + storageAccountType: osDiskType + } : { + diskEncryptionSet: { + id: diskEncryptionSetResourceId + } + storageAccountType: osDiskType } - storageAccountType: osDiskType -} // =========== // // Deployments // @@ -104,7 +108,6 @@ resource keyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { scope: resourceGroup('${varKeyVaultSubId}', '${varKeyVaultRgName}') } - // Provision temporary VM and add it to domain. module managementVm '../../../../avm/1.0.0/res/compute/virtual-machine/main.bicep' = { scope: resourceGroup('${subId}', '${serviceObjectsRgName}') @@ -162,10 +165,14 @@ module managementVm '../../../../avm/1.0.0/res/compute/virtual-machine/main.bice allowExtensionOperations: true extensionDomainJoinPassword: keyVaultget.getSecret('domainJoinUserPassword') extensionDomainJoinConfig: { - enabled: contains(identityServiceProvider, 'EntraID') ? false: true + enabled: contains(identityServiceProvider, 'EntraID') + ? false + : true settings: { name: identityDomainName - ouPath: !empty(ouPath) ? ouPath : null + ouPath: !empty(ouPath) + ? ouPath + : null user: domainJoinUserName restart: 'true' options: '3' @@ -173,7 +180,9 @@ module managementVm '../../../../avm/1.0.0/res/compute/virtual-machine/main.bice } // Entra ID Join. extensionAadJoinConfig: { - enabled: contains(identityServiceProvider, 'EntraID') ? true: false + enabled: contains(identityServiceProvider, 'EntraID') + ? true + : false } tags: tags } diff --git a/workload/bicep/modules/sharedModules/storage.bicep b/workload/bicep/modules/sharedModules/storage.bicep index b5b24067f..af4e0554a 100644 --- a/workload/bicep/modules/sharedModules/storage.bicep +++ b/workload/bicep/modules/sharedModules/storage.bicep @@ -146,7 +146,7 @@ param createResourceTags bool param baseScriptUri string @description('The security principal name.') -param varSecurityPrincipalName string = '' +param securityPrincipalName string = '' @description('The identity domain name.') param identityDomainName string @@ -170,26 +170,27 @@ param time string = utcNow() // Variable declaration // // =========== // var varNamingUniqueStringThreeChar = take('${uniqueString(subId, deploymentPrefix, time)}', 3) -var varAnfCapacityPoolSize = ((createFslogixDeployment ? fslogixFileShareQuotaSize : 0) + (createAppAttachDeployment ? appAttachFileShareQuotaSize : 0)) > 4096 - ? ((createFslogixDeployment ? fslogixFileShareQuotaSize : 0) + (createAppAttachDeployment ? appAttachFileShareQuotaSize : 0)) +var varAnfCapacityPoolSize = ((createFslogixDeployment ? fslogixFileShareQuotaSize : 0) + (createAppAttachDeployment + ? appAttachFileShareQuotaSize + : 0)) > 4096 + ? ((createFslogixDeployment ? fslogixFileShareQuotaSize : 0) + (createAppAttachDeployment + ? appAttachFileShareQuotaSize + : 0)) : 4096 var varFslogixFileShareName = storageService == 'AzureFiles' - ? (useCustomNaming + ? (useCustomNaming ? fslogixFileShareCustomName : 'fslogix-pc-${deploymentPrefix}-${deploymentEnvironment}-${locationAcronym}-001') - : storageService == 'ANF' - ? 'fsl${deploymentPrefix}${deploymentEnvironment}${locationAcronym}001' - : '' + : storageService == 'ANF' ? 'fsl${deploymentPrefix}${deploymentEnvironment}${locationAcronym}001' : '' var varAnfSmbServerNamePrefix = 'anf${deploymentPrefix}${deploymentEnvironment}' var varAppAttachFileShareName = storageService == 'AzureFiles' - ? (useCustomNaming - ? appAttachFileShareCustomName - : 'appa-${deploymentPrefix}-${deploymentEnvironment}-${locationAcronym}-001') - : storageService == 'ANF' - ? 'appa${deploymentPrefix}01' - : '' -var varFslogixAnfVolume = createFslogixDeployment ? [ - { + ? (useCustomNaming + ? appAttachFileShareCustomName + : 'appa-${deploymentPrefix}-${deploymentEnvironment}-${locationAcronym}-001') + : storageService == 'ANF' ? 'appa${deploymentPrefix}01' : '' +var varFslogixAnfVolume = createFslogixDeployment + ? [ + { name: varFslogixFileShareName coolAccess: false encryptionKeySource: 'Microsoft.NetApp' @@ -200,16 +201,18 @@ var varFslogixAnfVolume = createFslogixDeployment ? [ networkFeatures: 'Standard' usageThreshold: fslogixFileShareQuotaSize * 1073741824 // Convert GiBs to bytes protocolTypes: [ - 'CIFS' + 'CIFS' ] subnetResourceId: anfSubnetResourceId creationToken: varFslogixFileShareName smbContinuouslyAvailable: true securityStyle: 'ntfs' - } - ] : [] -var varAppAttchAnfVolume = createAppAttachDeployment ? [ - { + } + ] + : [] +var varAppAttchAnfVolume = createAppAttachDeployment + ? [ + { name: varAppAttachFileShareName coolAccess: false encryptionKeySource: 'Microsoft.NetApp' @@ -220,65 +223,82 @@ var varAppAttchAnfVolume = createAppAttachDeployment ? [ networkFeatures: 'Standard' usageThreshold: appAttachFileShareQuotaSize * 1073741824 // Convert GiBs to bytes protocolTypes: [ - 'CIFS' + 'CIFS' ] subnetResourceId: anfSubnetResourceId creationToken: varAppAttachFileShareName smbContinuouslyAvailable: true securityStyle: 'ntfs' - } - ] : [] + } + ] + : [] var varAnfVolumes = union(varFslogixAnfVolume, varAppAttchAnfVolume) var varFslogixStorageName = useCustomNaming ? '${storageAccountPrefixCustomName}fsl${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' : 'stfsl${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' -var varAnfAccountName = useCustomNaming ? anfAccountCustomName : 'anf-acc-${computeStorageResourcesNamingStandard}-001' +var varAnfAccountName = useCustomNaming + ? anfAccountCustomName + : 'anf-acc-${computeStorageResourcesNamingStandard}-001' var varAnfCapacityPoolName = 'anf-cpool-${computeStorageResourcesNamingStandard}-001' -var varFslogixStorageFqdn = createFslogixDeployment - ? ((storageService == 'AzureFiles') - ? '${varFslogixStorageName}.file.${environment().suffixes.storage}' - : (storageService == 'ANF') - ? '${varFslogixFileShareName}...${location}.netapp.azure.com' - : '') +var varFslogixStorageFqdn = createFslogixDeployment + ? ((storageService == 'AzureFiles') + ? '${varFslogixStorageName}.file.${environment().suffixes.storage}' + : (storageService == 'ANF') + ? '${varFslogixFileShareName}...${location}.netapp.azure.com' + : '') + : '' +var varAppAttachStorageFqdn = createAppAttachDeployment + ? ((storageService == 'AzureFiles') + ? '${varAppAttachStorageName}.file.${environment().suffixes.storage}' + : (storageService == 'ANF') + ? '${varAppAttachFileShareName}...${location}.netapp.azure.com' + : '') : '' -var varAppAttachStorageFqdn = createAppAttachDeployment ? ((storageService == 'AzureFiles') ? '${varAppAttachStorageName}.file.${environment().suffixes.storage}' : (storageService == 'ANF') ? '${varAppAttachFileShareName}...${location}.netapp.azure.com' : '') : '' var varAppAttachStorageName = useCustomNaming ? '${storageAccountPrefixCustomName}appa${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' : 'stappa${deploymentPrefix}${deploymentEnvironmentOneCharacter}${varNamingUniqueStringThreeChar}' var varManagementVmName = 'vmmgmt${deploymentPrefix}${deploymentEnvironmentOneCharacter}${locationAcronym}' var varFslogixFileSharePath = createFslogixDeployment - ? (storageService == 'AzureFiles' - ? '\\\\${varFslogixStorageName}.file.${environment().suffixes.storage}\\${varFslogixFileShareName}' - : (storageService == 'ANF' - ? anf.outputs.anfFslogixVolumeResourceId - : '') ) : '' + ? (storageService == 'AzureFiles' + ? '\\\\${varFslogixStorageName}.file.${environment().suffixes.storage}\\${varFslogixFileShareName}' + : (storageService == 'ANF' + ? anf.outputs.anfFslogixVolumeResourceId + : '')) + : '' var varAppAttachFileSharePath = createAppAttachDeployment - ? (storageService == 'AzureFiles' - ? '\\\\${varAppAttachStorageName}.file.${environment().suffixes.storage}\\${varAppAttachFileShareName}' - : (storageService == 'ANF' - ? anf.outputs.anfAppAttachVolumeResourceId - : '') ) : '' -var varFslogixStoragePerformance = fslogixStoragePerformance =='Ultra' - ? 'Premium' - : fslogixStoragePerformance -var varAppAttachStoragePerformance = appAttachStoragePerformance =='Ultra' - ? 'Premium' - : appAttachStoragePerformance -var varStorageAccountAvailability = availability == 'AvailabilityZones' - ? true - : false + ? (storageService == 'AzureFiles' + ? '\\\\${varAppAttachStorageName}.file.${environment().suffixes.storage}\\${varAppAttachFileShareName}' + : (storageService == 'ANF' + ? anf.outputs.anfAppAttachVolumeResourceId + : '')) + : '' +var varFslogixStoragePerformance = fslogixStoragePerformance == 'Ultra' + ? 'Premium' + : fslogixStoragePerformance +var varAppAttachStoragePerformance = appAttachStoragePerformance == 'Ultra' + ? 'Premium' + : appAttachStoragePerformance +var varStorageAccountAvailability = availability == 'AvailabilityZones' + ? true + : false var varFslogixStorageSku = (varStorageAccountAvailability && storageService == 'AzureFiles') - ? '${varFslogixStoragePerformance}_ZRS' - : '${varFslogixStoragePerformance}_LRS' + ? '${varFslogixStoragePerformance}_ZRS' + : '${varFslogixStoragePerformance}_LRS' var varAppAttachStorageSku = varStorageAccountAvailability - ? '${varAppAttachStoragePerformance}_ZRS' - : '${varAppAttachStoragePerformance}_LRS' + ? '${varAppAttachStoragePerformance}_ZRS' + : '${varAppAttachStoragePerformance}_LRS' var varStorageAzureFilesDscAgentPackageLocation = 'https://github.com/Azure/avdaccelerator/raw/main/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip' var varStorageToDomainScriptUri = '${baseScriptUri}scripts/Manual-DSC-Storage-Scripts.ps1' var varStorageToDomainScript = './Manual-DSC-Storage-Scripts.ps1' -var varOuStgPath = !empty(storageOuPath) ? '"${storageOuPath}"' : '"${varDefaultStorageOuPath}"' -var varDefaultStorageOuPath = (identityServiceProvider == 'EntraDS') ? 'AADDC Computers' : 'Computers' -var varStorageCustomOuPath = !empty(storageOuPath) ? 'true' : 'false' +var varOuStgPath = !empty(storageOuPath) + ? '"${storageOuPath}"' + : '"${varDefaultStorageOuPath}"' +var varDefaultStorageOuPath = (identityServiceProvider == 'EntraDS') + ? 'AADDC Computers' + : 'Computers' +var varStorageCustomOuPath = !empty(storageOuPath) + ? 'true' + : 'false' var varMarketPlaceGalleryWindows = loadJsonContent('../../../variables/osMarketPlaceImages.json') // =========== // // Deployments // @@ -310,124 +330,140 @@ module managementVm './managementVm.bicep' = if (identityServiceProvider != 'Ent encryptionAtHost: encryptionAtHost storageManagedIdentityResourceId: storageManagedIdentityResourceId osImage: varMarketPlaceGalleryWindows[managementVmOsImage] - tags: createResourceTags ? union(customResourceTags, defaultTags) : defaultTags + tags: createResourceTags + ? union(customResourceTags, defaultTags) + : defaultTags } - dependsOn: [ - ] + dependsOn: [] } // Azure NetApp Files -module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && (!contains(identityServiceProvider, 'EntraID'))) { - name: 'Storage-ANF-${time}' - params: { - accountName: varAnfAccountName - capacityPoolName: varAnfCapacityPoolName - volumes: varAnfVolumes - smbServerNamePrefix: varAnfSmbServerNamePrefix - capacityPoolSize: varAnfCapacityPoolSize - dnsServers: dnsServers - performance: fslogixStoragePerformance - createFslogixStorage: createFslogixDeployment - createAppAttachStorage: createAppAttachDeployment - ouStgPath: !empty(storageOuPath) ? storageOuPath : varDefaultStorageOuPath - domainJoinUserName: domainJoinUserName - keyVaultResourceId: keyVaultResourceId - identityDomainName: identityDomainName - location: location - storageObjectsRgName: storageObjectsRgName - subId: subId - tags: createResourceTags ? union(customResourceTags, defaultTags) : defaultTags - // alaWorkspaceResourceId: deployMonitoring - // ? (deployAlaWorkspace - // ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId - // : alaExistingWorkspaceResourceId) - // : '' - } - dependsOn: [ - managementVm - ] +module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && (!contains( + identityServiceProvider, + 'EntraID' +))) { + name: 'Storage-ANF-${time}' + params: { + accountName: varAnfAccountName + capacityPoolName: varAnfCapacityPoolName + volumes: varAnfVolumes + smbServerNamePrefix: varAnfSmbServerNamePrefix + capacityPoolSize: varAnfCapacityPoolSize + dnsServers: dnsServers + performance: fslogixStoragePerformance + createFslogixStorage: createFslogixDeployment + createAppAttachStorage: createAppAttachDeployment + storageOuPath: !empty(storageOuPath) + ? storageOuPath + : varDefaultStorageOuPath + domainJoinUserName: domainJoinUserName + keyVaultResourceId: keyVaultResourceId + identityDomainName: identityDomainName + location: location + storageObjectsRgName: storageObjectsRgName + subId: subId + tags: createResourceTags + ? union(customResourceTags, defaultTags) + : defaultTags + // alaWorkspaceResourceId: deployMonitoring + // ? (deployAlaWorkspace + // ? monitoringDiagnosticSettings.outputs.avdAlaWorkspaceResourceId + // : alaExistingWorkspaceResourceId) + // : '' } + dependsOn: [ + managementVm + ] +} // FSLogix Azure Files module fslogixAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (createFslogixDeployment && (storageService != 'ANF')) { - name: 'Storage-FSLogix-ST-${time}' - params: { - storagePurpose: 'fslogix' - vmLocalUserName: vmLocalUserName - fileShareName: varFslogixFileShareName - fileShareMultichannel: (varFslogixStoragePerformance == 'Premium') ? true : false - storageSku: varFslogixStorageSku - fileShareQuotaSize: fslogixFileShareQuotaSize - storageAccountFqdn: varFslogixStorageFqdn - storageAccountName: varFslogixStorageName - storageToDomainScript: varStorageToDomainScript - storageToDomainScriptUri: varStorageToDomainScriptUri - identityServiceProvider: identityServiceProvider - dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation - storageCustomOuPath: varStorageCustomOuPath - managementVmName: varManagementVmName - deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage - keyVaultResourceId: keyVaultResourceId - ouStgPath: varOuStgPath - managedIdentityClientId: managedIdentityClientId - securityPrincipalName: varSecurityPrincipalName - domainJoinUserName: domainJoinUserName - serviceObjectsRgName: serviceObjectsRgName - identityDomainName: identityDomainName - identityDomainGuid: identityDomainGuid - location: location - storageObjectsRgName: storageObjectsRgName - privateEndpointSubnetResourceId: privateEndpointSubnetResourceId - vmsSubnetResourceId: vmsSubnetResourceId - privateDnsZoneFilesResourceId: privateDnsZoneFilesResourceId - subId: subId - tags: createResourceTags ? union(customResourceTags, defaultTags) : defaultTags - alaWorkspaceResourceId: alaWorkspaceResourceId - } - dependsOn: [ - managementVm - ] + name: 'Storage-FSLogix-ST-${time}' + params: { + storagePurpose: 'fslogix' + vmLocalUserName: vmLocalUserName + fileShareName: varFslogixFileShareName + fileShareMultichannel: (varFslogixStoragePerformance == 'Premium') + ? true + : false + storageSku: varFslogixStorageSku + fileShareQuotaSize: fslogixFileShareQuotaSize + storageAccountFqdn: varFslogixStorageFqdn + storageAccountName: varFslogixStorageName + storageToDomainScript: varStorageToDomainScript + storageToDomainScriptUri: varStorageToDomainScriptUri + identityServiceProvider: identityServiceProvider + dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation + storageCustomOuPath: varStorageCustomOuPath + managementVmName: varManagementVmName + deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage + keyVaultResourceId: keyVaultResourceId + storageOuPath: varOuStgPath + managedIdentityClientId: managedIdentityClientId + securityPrincipalName: securityPrincipalName + domainJoinUserName: domainJoinUserName + serviceObjectsRgName: serviceObjectsRgName + identityDomainName: identityDomainName + identityDomainGuid: identityDomainGuid + location: location + storageObjectsRgName: storageObjectsRgName + privateEndpointSubnetResourceId: privateEndpointSubnetResourceId + vmsSubnetResourceId: vmsSubnetResourceId + privateDnsZoneFilesResourceId: privateDnsZoneFilesResourceId + subId: subId + tags: createResourceTags + ? union(customResourceTags, defaultTags) + : defaultTags + alaWorkspaceResourceId: alaWorkspaceResourceId + } + dependsOn: [ + managementVm + ] } - - // App Attach Azure Files + +// App Attach Azure Files module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (createFslogixDeployment && (storageService != 'ANF')) { - name: 'Storage-AppA-${time}' - params: { - storagePurpose: 'AppAttach' - vmLocalUserName: vmLocalUserName - fileShareName: varAppAttachFileShareName - fileShareMultichannel: (varAppAttachStoragePerformance == 'Premium') ? true : false - storageSku: varAppAttachStorageSku - fileShareQuotaSize: appAttachFileShareQuotaSize - storageAccountFqdn: varAppAttachStorageFqdn - storageAccountName: varAppAttachStorageName - storageToDomainScript: varStorageToDomainScript - storageToDomainScriptUri: varStorageToDomainScriptUri - identityServiceProvider: identityServiceProvider - dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation - storageCustomOuPath: varStorageCustomOuPath - managementVmName: varManagementVmName - deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage - ouStgPath: varOuStgPath - managedIdentityClientId: managedIdentityClientId - securityPrincipalName: varSecurityPrincipalName - domainJoinUserName: domainJoinUserName - keyVaultResourceId: keyVaultResourceId - serviceObjectsRgName: serviceObjectsRgName - identityDomainName: identityDomainName - identityDomainGuid: identityDomainGuid - location: location - storageObjectsRgName: storageObjectsRgName - privateEndpointSubnetResourceId: privateEndpointSubnetResourceId - vmsSubnetResourceId: vmsSubnetResourceId - privateDnsZoneFilesResourceId: privateDnsZoneFilesResourceId - subId: subId - tags: createResourceTags ? union(customResourceTags, defaultTags) : defaultTags - alaWorkspaceResourceId: alaWorkspaceResourceId - } - dependsOn: [ - managementVm - ] + name: 'Storage-AppA-${time}' + params: { + storagePurpose: 'AppAttach' + vmLocalUserName: vmLocalUserName + fileShareName: varAppAttachFileShareName + fileShareMultichannel: (varAppAttachStoragePerformance == 'Premium') + ? true + : false + storageSku: varAppAttachStorageSku + fileShareQuotaSize: appAttachFileShareQuotaSize + storageAccountFqdn: varAppAttachStorageFqdn + storageAccountName: varAppAttachStorageName + storageToDomainScript: varStorageToDomainScript + storageToDomainScriptUri: varStorageToDomainScriptUri + identityServiceProvider: identityServiceProvider + dscAgentPackageLocation: varStorageAzureFilesDscAgentPackageLocation + storageCustomOuPath: varStorageCustomOuPath + managementVmName: varManagementVmName + deployPrivateEndpoint: deployPrivateEndpointKeyvaultStorage + storageOuPath: varOuStgPath + managedIdentityClientId: managedIdentityClientId + securityPrincipalName: securityPrincipalName + domainJoinUserName: domainJoinUserName + keyVaultResourceId: keyVaultResourceId + serviceObjectsRgName: serviceObjectsRgName + identityDomainName: identityDomainName + identityDomainGuid: identityDomainGuid + location: location + storageObjectsRgName: storageObjectsRgName + privateEndpointSubnetResourceId: privateEndpointSubnetResourceId + vmsSubnetResourceId: vmsSubnetResourceId + privateDnsZoneFilesResourceId: privateDnsZoneFilesResourceId + subId: subId + tags: createResourceTags + ? union(customResourceTags, defaultTags) + : defaultTags + alaWorkspaceResourceId: alaWorkspaceResourceId + } + dependsOn: [ + managementVm + ] } // =========== // @@ -435,10 +471,10 @@ module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (crea // =========== // output fslogixFileSharePath string = varFslogixFileSharePath -output appAttachFileSharePath string = varFslogixFileSharePath -output fslogixStorageAccountResourceId string = createFslogixDeployment - ? fslogixAzureFilesStorage.outputs.storageAccountResourceId +output appAttachFileSharePath string = varAppAttachFileSharePath +output fslogixStorageAccountResourceId string = createFslogixDeployment + ? fslogixAzureFilesStorage.outputs.storageAccountResourceId : '' -output appAttachStorageAccountResourceId string = createAppAttachDeployment - ? appAttachAzureFilesStorage.outputs.storageAccountResourceId +output appAttachStorageAccountResourceId string = createAppAttachDeployment + ? appAttachAzureFilesStorage.outputs.storageAccountResourceId : '' diff --git a/workload/bicep/modules/storageAzureFiles/deploy.bicep b/workload/bicep/modules/storageAzureFiles/deploy.bicep index b82c11c57..f83474a99 100644 --- a/workload/bicep/modules/storageAzureFiles/deploy.bicep +++ b/workload/bicep/modules/storageAzureFiles/deploy.bicep @@ -94,7 +94,7 @@ param dscAgentPackageLocation string param storageCustomOuPath string @sys.description('OU Storage Path') -param ouStgPath string +param storageOuPath string @sys.description('Managed Identity Client ID') param managedIdentityClientId string @@ -108,14 +108,17 @@ param storageAccountFqdn string // =========== // // Variable declaration // // =========== // + var varKeyVaultSubId = split(keyVaultResourceId, '/')[2] var varKeyVaultRgName = split(keyVaultResourceId, '/')[4] var varKeyVaultName = split(keyVaultResourceId, '/')[8] var varAzureCloudName = environment().name var varWrklStoragePrivateEndpointName = 'pe-${storageAccountName}-file' var varSecurityPrincipalName = !empty(securityPrincipalName) ? securityPrincipalName : 'none' -var varAdminUserName = contains(identityServiceProvider, 'EntraID') ? vmLocalUserName : domainJoinUserName -var varStorageToDomainScriptArgs = '-DscPath ${dscAgentPackageLocation} -StorageAccountName ${storageAccountName} -StorageAccountRG ${storageObjectsRgName} -StoragePurpose ${storagePurpose} -DomainName ${identityDomainName} -IdentityServiceProvider ${identityServiceProvider} -AzureCloudEnvironment ${varAzureCloudName} -SubscriptionId ${subId} -AdminUserName ${varAdminUserName} -CustomOuPath ${storageCustomOuPath} -OUName ${ouStgPath} -ShareName ${fileShareName} -ClientId ${managedIdentityClientId} -SecurityPrincipalName "${varSecurityPrincipalName}" -StorageAccountFqdn ${storageAccountFqdn} ' +var varAdminUserName = contains(identityServiceProvider, 'EntraID') + ? vmLocalUserName + : domainJoinUserName +var varStorageToDomainScriptArgs = '-DscPath ${dscAgentPackageLocation} -StorageAccountName ${storageAccountName} -StorageAccountRG ${storageObjectsRgName} -StoragePurpose ${storagePurpose} -DomainName ${identityDomainName} -IdentityServiceProvider ${identityServiceProvider} -AzureCloudEnvironment ${varAzureCloudName} -SubscriptionId ${subId} -AdminUserName ${varAdminUserName} -CustomOuPath ${storageCustomOuPath} -OUName ${storageOuPath} -ShareName ${fileShareName} -ClientId ${managedIdentityClientId} -SecurityPrincipalName "${varSecurityPrincipalName}" -StorageAccountFqdn ${storageAccountFqdn} ' var varDiagnosticSettings = !empty(alaWorkspaceResourceId) ? [ { @@ -124,6 +127,7 @@ var varDiagnosticSettings = !empty(alaWorkspaceResourceId) } ] : [] + // =========== // // Deployments // // =========== // @@ -143,9 +147,15 @@ module storageAndFile '../../../../avm/1.0.0/res/storage/storage-account/main.bi location: location skuName: storageSku allowBlobPublicAccess: false - publicNetworkAccess: deployPrivateEndpoint ? 'Disabled' : 'Enabled' - kind: ((storageSku == 'Premium_LRS') || (storageSku == 'Premium_ZRS')) ? 'FileStorage' : 'StorageV2' - largeFileSharesState: (storageSku == 'Standard_LRS') || (storageSku == 'Standard_ZRS') ? 'Enabled' : 'Disabled' + publicNetworkAccess: deployPrivateEndpoint + ? 'Disabled' + : 'Enabled' + kind: (storageSku == 'Premium_LRS' || storageSku == 'Premium_ZRS') + ? 'FileStorage' + : 'StorageV2' + largeFileSharesState: (storageSku == 'Standard_LRS' || storageSku == 'Standard_ZRS') + ? 'Enabled' + : 'Disabled' azureFilesIdentityBasedAuthentication: identityServiceProvider != 'EntraID' ? { directoryServiceOptions: identityServiceProvider == 'EntraDS' @@ -235,4 +245,5 @@ module addShareToDomainScript '../sharedModules/smbUtilities.bicep' = if (identi // =========== // // Outputs // // =========== // + output storageAccountResourceId string = storageAndFile.outputs.resourceId From fe70a1b43164ecfca49e57cb406bc1735682e761 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Thu, 27 Mar 2025 12:38:40 -0500 Subject: [PATCH 17/55] updates --- workload/bicep/deploy-baseline.bicep | 2 +- workload/bicep/modules/sharedModules/storage.bicep | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index b2d2b456c..4b4fa539d 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -1400,7 +1400,7 @@ module storage './modules/sharedModules/storage.bicep' = if (varCreateStorageDep : 'Standard_D2ads_v5' createResourceTags: createResourceTags deployPrivateEndpointKeyvaultStorage: deployPrivateEndpointKeyvaultStorage - dnsServers: varAllDnsServers + dnsServers: customDnsIps identityDomainName: identityDomainName storageObjectsRgName: varStorageObjectsRgName baseScriptUri: varBaseScriptUri diff --git a/workload/bicep/modules/sharedModules/storage.bicep b/workload/bicep/modules/sharedModules/storage.bicep index af4e0554a..2b905b695 100644 --- a/workload/bicep/modules/sharedModules/storage.bicep +++ b/workload/bicep/modules/sharedModules/storage.bicep @@ -472,9 +472,9 @@ module appAttachAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (crea output fslogixFileSharePath string = varFslogixFileSharePath output appAttachFileSharePath string = varAppAttachFileSharePath -output fslogixStorageAccountResourceId string = createFslogixDeployment +output fslogixStorageAccountResourceId string = (createFslogixDeployment && (storageService == 'AzureFiles')) ? fslogixAzureFilesStorage.outputs.storageAccountResourceId : '' -output appAttachStorageAccountResourceId string = createAppAttachDeployment +output appAttachStorageAccountResourceId string = (createAppAttachDeployment && (storageService == 'AzureFiles')) ? appAttachAzureFilesStorage.outputs.storageAccountResourceId : '' From 59c8d7b1bbce444fae2f354a52c5516e199badfc Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Mon, 31 Mar 2025 12:41:07 -0500 Subject: [PATCH 18/55] updates --- workload/bicep/deploy-custom-image.bicep | 4 ++- .../.bicep/getNetAppVolumeSmbServerFqdn.bicep | 36 +++++++++++++++++++ .../modules/azureNetappFiles/deploy.bicep | 7 ++-- .../bicep/modules/sharedModules/storage.bicep | 22 ++++++++---- 4 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 workload/bicep/modules/azureNetappFiles/.bicep/getNetAppVolumeSmbServerFqdn.bicep diff --git a/workload/bicep/deploy-custom-image.bicep b/workload/bicep/deploy-custom-image.bicep index 7255f53f0..478f2953d 100644 --- a/workload/bicep/deploy-custom-image.bicep +++ b/workload/bicep/deploy-custom-image.bicep @@ -764,10 +764,12 @@ module automationAccount '../../avm/1.0.0/res/automation/automation-account/main scope: resourceGroup(sharedServicesSubId, varResourceGroupName) name: 'Automation-Account-${time}' params: { - diagnosticSettings: [ + diagnosticSettings: enableMonitoringAlerts ? [ { workspaceResourceId: empty(alertsDistributionGroup) ? '' : empty(existingLogAnalyticsWorkspaceResourceId) ? workspace.outputs.resourceId : existingLogAnalyticsWorkspaceResourceId } + ] : [ + ] name: varAutomationAccountName jobSchedules: [ diff --git a/workload/bicep/modules/azureNetappFiles/.bicep/getNetAppVolumeSmbServerFqdn.bicep b/workload/bicep/modules/azureNetappFiles/.bicep/getNetAppVolumeSmbServerFqdn.bicep new file mode 100644 index 000000000..8005fe344 --- /dev/null +++ b/workload/bicep/modules/azureNetappFiles/.bicep/getNetAppVolumeSmbServerFqdn.bicep @@ -0,0 +1,36 @@ +metadata name = 'AVD LZA storage ANF volume SMB server FQDN' +metadata description = 'This module returns the SMB server FQDN of an ANF volume.' +metadata owner = 'Azure/avdaccelerator' + +targetScope = 'subscription' + +// ========== // +// Parameters // +// ========== // + +param netAppVolumeResourceId string + +// =========== // +// Variable declaration // +// =========== // + +// =========== // +// Deployments // +// =========== // + +// Call on ANF account and volume to get the SMB server FQDN. +resource netAppAccount 'Microsoft.NetApp/netAppAccounts@2024-09-01' existing = { + name: split(netAppVolumeResourceId, '/')[8] + scope: resourceGroup(split(netAppVolumeResourceId, '/')[2], split(netAppVolumeResourceId, '/')[4]) + resource capacityPool 'capacityPools' existing = { + name: split(netAppVolumeResourceId, '/')[10] + resource volume 'volumes' existing = { + name: last(split(netAppVolumeResourceId, '/')) + } + } + } + +// =========== // +// Outputs // +// =========== // +output anfSmbServerFqdn string = netAppAccount::capacityPool::volume.properties.mountTargets[0].smbServerFqdn diff --git a/workload/bicep/modules/azureNetappFiles/deploy.bicep b/workload/bicep/modules/azureNetappFiles/deploy.bicep index 94ab367f3..ad03f49d1 100644 --- a/workload/bicep/modules/azureNetappFiles/deploy.bicep +++ b/workload/bicep/modules/azureNetappFiles/deploy.bicep @@ -74,7 +74,7 @@ var varKeyVaultName = split(keyVaultResourceId, '/')[8] // =========== // // Call on the KV. -resource keyVaultget 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { +resource keyVaultGet 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { name: varKeyVaultName scope: resourceGroup('${varKeyVaultSubId}', '${varKeyVaultRgName}') } @@ -88,8 +88,9 @@ module azureNetAppFiles '../../../../avm/1.1.0/res/net-app/net-app-account/main. adName: accountName domainName: identityDomainName domainJoinUser: domainJoinUserName - domainJoinPassword: keyVaultget.getSecret('domainJoinUserPassword') - //domainJoinOU: replace(storageOuPath, '"', '\\"') + domainJoinPassword: keyVaultGet.getSecret('domainJoinUserPassword') + //domainJoinOU: 'CN="${replace(storageOuPath, '"', '\\"')}"' + domainJoinOU: 'CN=${storageOuPath}' dnsServers: dnsServers smbServerNamePrefix: smbServerNamePrefix location: location diff --git a/workload/bicep/modules/sharedModules/storage.bicep b/workload/bicep/modules/sharedModules/storage.bicep index 2b905b695..9563a72d1 100644 --- a/workload/bicep/modules/sharedModules/storage.bicep +++ b/workload/bicep/modules/sharedModules/storage.bicep @@ -262,14 +262,14 @@ var varFslogixFileSharePath = createFslogixDeployment ? (storageService == 'AzureFiles' ? '\\\\${varFslogixStorageName}.file.${environment().suffixes.storage}\\${varFslogixFileShareName}' : (storageService == 'ANF' - ? anf.outputs.anfFslogixVolumeResourceId + ? '\\\\${netAppAccountGet.outputs.anfSmbServerFqdn}\\${last(split(azureNetAppFiles.outputs.anfFslogixVolumeResourceId, '/'))}' : '')) : '' var varAppAttachFileSharePath = createAppAttachDeployment ? (storageService == 'AzureFiles' ? '\\\\${varAppAttachStorageName}.file.${environment().suffixes.storage}\\${varAppAttachFileShareName}' : (storageService == 'ANF' - ? anf.outputs.anfAppAttachVolumeResourceId + ? '\\\\${netAppAccountGet.outputs.anfSmbServerFqdn}\\${last(split(azureNetAppFiles.outputs.anfAppAttachVolumeResourceId, '/'))}' : '')) : '' var varFslogixStoragePerformance = fslogixStoragePerformance == 'Ultra' @@ -300,6 +300,10 @@ var varStorageCustomOuPath = !empty(storageOuPath) ? 'true' : 'false' var varMarketPlaceGalleryWindows = loadJsonContent('../../../variables/osMarketPlaceImages.json') +var varAnfVolumeResourceIdGet = (createFslogixDeployment && (storageService == 'ANF')) + ? azureNetAppFiles.outputs.anfFslogixVolumeResourceId + : ((createAppAttachDeployment && (storageService == 'ANF')) ? azureNetAppFiles.outputs.anfAppAttachVolumeResourceId + : '') // =========== // // Deployments // // =========== // @@ -338,10 +342,7 @@ module managementVm './managementVm.bicep' = if (identityServiceProvider != 'Ent } // Azure NetApp Files -module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && (!contains( - identityServiceProvider, - 'EntraID' -))) { +module azureNetAppFiles '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && (!contains(identityServiceProvider,'EntraID'))) { name: 'Storage-ANF-${time}' params: { accountName: varAnfAccountName @@ -376,6 +377,15 @@ module anf '../azureNetappFiles/deploy.bicep' = if ((storageService == 'ANF') && ] } + +// Call on ANF account and volume to get the SMB server FQDN. +module netAppAccountGet '../azureNetappFiles/.bicep/getNetAppVolumeSmbServerFqdn.bicep' = if (storageService == 'ANF') { + name: 'Get-ANF-SMB-Server-FQDN-${time}' + params: { + netAppVolumeResourceId: varAnfVolumeResourceIdGet + } +} + // FSLogix Azure Files module fslogixAzureFilesStorage '../storageAzureFiles/deploy.bicep' = if (createFslogixDeployment && (storageService != 'ANF')) { name: 'Storage-FSLogix-ST-${time}' From 52b8c3edb1b1ab225006c2fc34e96321983b8a19 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Mon, 31 Mar 2025 16:55:01 -0500 Subject: [PATCH 19/55] updates --- .../DSCStorageScripts/1.0.3/Configuration.ps1 | 2 +- .../1.0.3/Script-DomainJoinStorage.ps1 | 57 +- workload/scripts/Set-NtfsPermissions.ps1 | 529 ++++++++++++++++++ .../Set-SessionHostConfiguration copy.ps1 | 502 +++++++++++++++++ 4 files changed, 1072 insertions(+), 18 deletions(-) create mode 100644 workload/scripts/Set-NtfsPermissions.ps1 create mode 100644 workload/scripts/Set-SessionHostConfiguration copy.ps1 diff --git a/workload/scripts/DSCStorageScripts/1.0.3/Configuration.ps1 b/workload/scripts/DSCStorageScripts/1.0.3/Configuration.ps1 index 670ce8d37..21807734c 100644 --- a/workload/scripts/DSCStorageScripts/1.0.3/Configuration.ps1 +++ b/workload/scripts/DSCStorageScripts/1.0.3/Configuration.ps1 @@ -225,4 +225,4 @@ $config = @{ ) } -DomainJoinFileShare -ConfigurationData $config -StorageAccountName $StorageAccountName -StorageAccountRG $StorageAccountRG -SubscriptionId $SubscriptionId -ShareName $ShareName -DomainName $DomainName -IdentityServiceProvider $IdentityServiceProvider -AzureCloudEnvironment $AzureCloudEnvironment -CustomOuPath $CustomOuPath -OUName $OUName -AdminUserName $AdminUserName -AdminUserPassword $AdminUserPassword -ClientId $ClientId -SecurityPrincipalName $SecurityPrincipalName -StoragePurpose $StoragePurpose -StorageFqdn $StorageFqdn -Verbose; \ No newline at end of file +DomainJoinFileShare -ConfigurationData $config -StorageService $StorageService -StorageAccountName $StorageAccountName -StorageAccountRG $StorageAccountRG -SubscriptionId $SubscriptionId -ShareName $ShareName -DomainName $DomainName -IdentityServiceProvider $IdentityServiceProvider -AzureCloudEnvironment $AzureCloudEnvironment -CustomOuPath $CustomOuPath -OUName $OUName -AdminUserName $AdminUserName -AdminUserPassword $AdminUserPassword -ClientId $ClientId -SecurityPrincipalName $SecurityPrincipalName -StoragePurpose $StoragePurpose -StorageFqdn $StorageFqdn -Verbose; \ No newline at end of file diff --git a/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 b/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 index 1b386ffba..ef18405c4 100644 --- a/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 +++ b/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 @@ -145,26 +145,49 @@ $connectTestResult = Test-NetConnection -ComputerName $StorageFqdn -Port 445 Write-Log "Test connection access to port 445 for $StorageFqdn was $connectTestResult" -Try { - Write-Log "Mounting Profile storage $StorageAccountName as a drive $DriveLetter" - if (-not (Get-PSDrive -Name $DriveLetter -ErrorAction SilentlyContinue)) { - $UserStorage = "/user:Azure\$StorageAccountName" - Write-Log "User storage: $UserStorage" - $StorageKey = (Get-AzStorageAccountKey -ResourceGroupName $StorageAccountRG -AccountName $StorageAccountName) | Where-Object { $_.KeyName -eq "key1" } - Write-Log "File Share location: $FileShareLocation" - net use ${DriveLetter}: $FileShareLocation $UserStorage $StorageKey.Value - #$StorageKey1 = ConvertTo-SecureString $StorageKey.value -AsPlainText -Force - #$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ("Azure\stfsly206dorg", $StorageKey1) - #New-PSDrive -Name $DriveLetter -PSProvider FileSystem -Root $FileShareLocation -Credential $credential +if ($StorageService -eq 'AzureFiles') { + Try { + Write-Log "Mounting Profile storage $StorageAccountName as a drive $DriveLetter" + if (-not (Get-PSDrive -Name $DriveLetter -ErrorAction SilentlyContinue)) { + $UserStorage = "/user:Azure\$StorageAccountName" + Write-Log "User storage: $UserStorage" + $StorageKey = (Get-AzStorageAccountKey -ResourceGroupName $StorageAccountRG -AccountName $StorageAccountName) | Where-Object { $_.KeyName -eq "key1" } + Write-Log "File Share location: $FileShareLocation" + net use ${DriveLetter}: $FileShareLocation $UserStorage $StorageKey.Value + #$StorageKey1 = ConvertTo-SecureString $StorageKey.value -AsPlainText -Force + #$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ("Azure\stfsly206dorg", $StorageKey1) + #New-PSDrive -Name $DriveLetter -PSProvider FileSystem -Root $FileShareLocation -Credential $credential + } + else { + Write-Log "Drive $DriveLetter already mounted." + } } - else { - Write-Log "Drive $DriveLetter already mounted." + Catch { + Write-Log -Err "Error while mounting profile storage as drive $DriveLetter" + Write-Log -Err $_.Exception.Message + Throw $_ } } -Catch { - Write-Log -Err "Error while mounting profile storage as drive $DriveLetter" - Write-Log -Err $_.Exception.Message - Throw $_ + +if ($StorageService -eq 'ANF') { + Try { + Write-Log "Mounting Profile storage $StorageAccountName as a drive $DriveLetter" + if (-not (Get-PSDrive -Name $DriveLetter -ErrorAction SilentlyContinue)) { + #$UserStorage = "/user:Azure\$StorageAccountName" + #Write-Log "User storage: $UserStorage" + #$StorageKey = (Get-AzStorageAccountKey -ResourceGroupName $StorageAccountRG -AccountName $StorageAccountName) | Where-Object { $_.KeyName -eq "key1" } + #Write-Log "File Share location: $FileShareLocation" + net use ${DriveLetter}: $FileShareLocation $UserStorage $StorageKey.Value + } + else { + Write-Log "Drive $DriveLetter already mounted." + } + } + Catch { + Write-Log -Err "Error while mounting profile storage as drive $DriveLetter" + Write-Log -Err $_.Exception.Message + Throw $_ + } } Try { diff --git a/workload/scripts/Set-NtfsPermissions.ps1 b/workload/scripts/Set-NtfsPermissions.ps1 new file mode 100644 index 000000000..393eefb6d --- /dev/null +++ b/workload/scripts/Set-NtfsPermissions.ps1 @@ -0,0 +1,529 @@ +param +( + [Parameter(Mandatory = $false)] + [string]$AdminGroupNames, + + [Parameter(Mandatory = $true)] + [String]$Shares, + + [Parameter(Mandatory = $false)] + [string]$ShardAzureFilesStorage, + + [Parameter(Mandatory = $false)] + [String]$DomainAccountType = "ComputerAccount", + + [Parameter(Mandatory = $true)] + [String]$DomainJoinUserPwd, + + [Parameter(Mandatory = $true)] + [String]$DomainJoinUserPrincipalName, + + [Parameter(Mandatory = $false)] + [ValidateSet("AES256", "RC4")] + [String]$KerberosEncryptionType, + + [Parameter(Mandatory = $false)] + [String]$NetAppServers, + + [Parameter(Mandatory = $false)] + [String]$OuPath, + + [Parameter(Mandatory = $false)] + [string]$ResourceManagerUri, + + [Parameter(Mandatory = $false)] + [String]$StorageAccountPrefix, + + [Parameter(Mandatory = $false)] + [String]$StorageAccountResourceGroupName, + + [Parameter(Mandatory = $false)] + [String]$StorageCount, + + [Parameter(Mandatory = $false)] + [String]$StorageIndex, + + [Parameter(Mandatory = $true)] + [String]$StorageSolution, + + [Parameter(Mandatory = $false)] + [String]$StorageSuffix, + + [Parameter(Mandatory = $false)] + [string]$SubscriptionId, + + [Parameter(Mandatory = $false)] + [String]$UserGroupNames, + + [Parameter(Mandatory = $false)] + [string]$UserAssignedIdentityClientId +) + +$ErrorActionPreference = 'Stop' +$WarningPreference = 'SilentlyContinue' + +[string]$Script:LogDir = "C:\WindowsAzure\Logs\RunCommands" +[string]$Script:Name = 'Set-NTFSPermissions' + +Function ConvertFrom-JsonString { + [CmdletBinding()] + param ( + [string]$JsonString, + [string]$Name, + [switch]$SensitiveValues + ) + If ($JsonString -ne '[]' -and $JsonString -ne $null) { + [array]$Array = $JsonString.replace('\"', '"') | ConvertFrom-Json + If ($Array.Length -gt 0) { + If ($SensitiveValues) { Write-Log -message "Array '$Name' has $($Array.Length) members" } Else { Write-Log -message "$($Name): '$($Array -join "', '")'" } + Return $Array + } + Else { + Return $null + } + } + Else { + Return $null + } +} + +Function Get-FullyQualifiedGroupName { + [CmdletBinding()] + param ( + [Parameter()] + [string]$GroupDisplayName, + [pscredential]$Credential + ) + $Group = $null + $Group = Get-ADGroup -Filter "Name -eq '$groupDisplayName'" -Credential $Credential + If ($null -ne $Group) { + # Extract the domain components from the distinguished name + $domainComponents = ($group.DistinguishedName -split ',') | Where-Object { $_ -like 'DC=*' } + # Construct the domain name + $domainName = ($domainComponents -replace 'DC=', '') -join '.' + # Get the domain information + $domain = Get-ADDomain -Identity $domainName + # Get the NetBIOS name + $netbiosName = $domain.NetBIOSName + # Combine NetBIOS name and group name + $GroupName = "$netbiosName\$($group.SamAccountName)" + Return $GroupName + } + Return $null +} + +function Update-ACL { + Param ( + [Parameter(Mandatory = $false)] + [Array]$AdminGroups, + [Parameter(Mandatory = $true)] + [pscredential]$Credential, + [Parameter(Mandatory = $true)] + [String]$FileShare, + [Parameter(Mandatory = $true)] + [Array]$UserGroups + ) + # Map Drive + Write-Log -message "[Update-ACL]: Mapping Drive to $FileShare" + New-PSDrive -Name 'Z' -PSProvider 'FileSystem' -Root $FileShare -Credential $Credential | Out-Null + # Set recommended NTFS permissions on the file share + Write-Log -message "[Update-ACL]: Getting Existing ACL for $FileShare" + $ACL = Get-Acl -Path 'Z:' + $CreatorOwner = [System.Security.Principal.Ntaccount]("Creator Owner") + Write-Log -message "[Update-ACL]: Purging Existing Access Control Entries for 'Creater Owner' from ACL" + $ACL.PurgeAccessRules($CreatorOwner) + $AuthenticatedUsers = [System.Security.Principal.Ntaccount]("Authenticated Users") + Write-Log -message "[Update-ACL]: Purging Existing Access Control Entries for 'Authenticated Users' from ACL" + $ACL.PurgeAccessRules($AuthenticatedUsers) + $Users = [System.Security.Principal.Ntaccount]("Users") + Write-Log -message "[Update-ACL]: Purging Existing Access Control Entries for 'Users' from ACL" + $ACL.PurgeAccessRules($Users) + If ($AdminGroups.Count -gt 0) { + ForEach ($Group in $AdminGroups) { + Write-Log -message "[Update-ACL]: Adding ACE '$($Group):Full Control' to ACL." + $Ntaccount = [System.Security.Principal.Ntaccount]("$Group") + $ACE = ([System.Security.AccessControl.FileSystemAccessRule]::new("$Ntaccount", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow")) + $ACL.SetAccessRule($ACE) + } + } + + ForEach ($Group in $UserGroups) { + Write-Log -message "[Update-ACL]: Adding ACE '$($Group):Modify (This Folder Only)' to ACL." + $Ntaccount = [System.Security.Principal.Ntaccount]("$Group") + $ACE = ([System.Security.AccessControl.FileSystemAccessRule]::new("$Ntaccount", "Modify", "None", "None", "Allow")) + $ACL.SetAccessRule($ACE) + } + + Write-Log -message "[Update-ACL]: Adding ACE 'Creator Owner:Modify (Subfolder and Files Only)' to ACL." + $ACE = ([System.Security.AccessControl.FileSystemAccessRule]::new("$CreatorOwner", "Modify", "ContainerInherit,ObjectInherit", "InheritOnly", "Allow")) + $ACL.SetAccessRule($ACE) + Write-Log -message "[Update-ACL]: Applying the following ACL to $($FileShare):" + Write-Log -message "$($ACL.access | Format-Table | Out-String)" + $ACL | Set-Acl -Path 'Z:' | Out-Null + Start-Sleep -Seconds 5 | Out-Null + $ACL = Get-Acl -Path 'Z:' + Write-Log -message "[Update-ACL]: Current ACL of $($FileShare):" + Write-Log -message "$($ACL.access | Format-Table | Out-String)" + # Unmount file share + Write-Log -message "[Update-ACL]: Unmapping Drive from $FileShare" + Remove-PSDrive -Name 'Z' -PSProvider 'FileSystem' -Force | Out-Null + Start-Sleep -Seconds 5 | Out-Null +} + +function New-Log { + <# + .SYNOPSIS + Sets default log file and stores in a script accessible variable $script:Log + Log File name "packageExecution_$date.log" + + .PARAMETER Path + Path to the log file + + .EXAMPLE + New-Log c:\Windows\Logs + Create a new log file in c:\Windows\Logs + #> + + Param ( + [Parameter(Mandatory = $true, Position = 0)] + [string] $Path + ) + + # Create central log file with given date + + $date = Get-Date -UFormat "%Y-%m-%d %H-%M-%S" + Set-Variable logFile -Scope Script + $script:logFile = "$Script:Name-$date.log" + + if ((Test-Path $path ) -eq $false) { + $null = New-Item -Path $path -type directory + } + + $script:Log = Join-Path $path $logfile + + Add-Content $script:Log "Date`t`t`tCategory`t`tDetails" +} + +function Write-Log { + + <# + .SYNOPSIS + Creates a log file and stores logs based on categories with tab seperation + + .PARAMETER category + Category to put into the trace + + .PARAMETER message + Message to be loged + + .EXAMPLE + Log 'Info' 'Message' + + #> + + Param ( + [Parameter(Mandatory = $false, Position = 0)] + [ValidateSet("Info", "Warning", "Error")] + $category = 'Info', + [Parameter(Mandatory = $true, Position = 1)] + $message + ) + + $date = get-date + $content = "[$date]`t$category`t`t$message" + Add-Content $Script:Log $content -ErrorAction Stop +} + +try { + + New-Log -Path $Script:LogDir + write-log -message "*** Parameter Values ***" + + # Convert Parameters passed as a JSON String to an array and remove any backslashes + [array]$AdminGroupNames = ConvertFrom-JsonString -JsonString $AdminGroupNames -Name 'AdminGroupNames' + [array]$Shares = ConvertFrom-JsonString -JsonString $Shares -Name 'Shares' + [array]$UserGroupNames = ConvertFrom-JsonString -JsonString $UserGroupNames -Name 'UserGroupNames' + + # Check if the Active Directory module is installed + $RsatInstalled = (Get-WindowsFeature -Name 'RSAT-AD-PowerShell').Installed + if (!$RsatInstalled) { + Install-WindowsFeature -Name 'RSAT-AD-PowerShell' | Out-Null + } + # Create Domain credential + $DomainJoinUserName = $DomainJoinUserPrincipalName.Split('@')[0] + $DomainPassword = ConvertTo-SecureString -String $DomainJoinUserPwd -AsPlainText -Force + [pscredential]$DomainCredential = New-Object System.Management.Automation.PSCredential ($DomainJoinUserName, $DomainPassword) + + # Get Domain information + $Domain = Get-ADDomain -Credential $DomainCredential -Current 'LocalComputer' + Write-Log -message "Domain Information:" + Write-Log -message "DistiguishedName: $($Domain.DistinguishedName)" + Write-Log -message "DNSRoot: $($Domain.DNSRoot)" + Write-Log -message "NetBIOSName: $($Domain.NetBIOSName)" + + # Get the SamAccountName for all the DisplayNames provided. + if ($AdminGroupNames.Count -gt 0) { + [array]$AdminGroups = @() + Write-Log -message "Processing AdminGroupNames by searching AD for Groups with the provided display name and returning the SamAccountName" + ForEach ($DisplayName in $AdminGroupNames) { + Write-Log -message "Processing AdminGroupName: $DisplayName" + $FullyQualifiedGroupName = $null + $FullyQualifiedGroupName = Get-FullyQualifiedGroupName -GroupDisplayName $DisplayName -Credential $DomainCredential + If ($null -ne $FullyQualifiedGroupName) { + Write-Log -message "Found Group: $FullyQualifiedGroupName" + $AdminGroups += $FullyQualifiedGroupName + } + Else { + Write-Log -message "Admin Group not found in Active Directory" + } + } + } + + Write-Log -message "Processing UserGroupNames by searching AD for Groups with the provided display name and returning the SamAccountName" + [array]$UserGroups = @() + ForEach ($DisplayName in $UserGroupNames) { + Write-Log -message "Processing UserGroupName: $DisplayName" + $FullyQualifiedGroupName = $null + $FullyQualifiedGroupName = Get-FullyQualifiedGroupName -GroupDisplayName $DisplayName -Credential $DomainCredential + If ($null -ne $FullyQualifiedGroupName) { + Write-Log -message "Found Group: $FullyQualifiedGroupName" + $UserGroups += $FullyQualifiedGroupName + } + Else { + Write-Log -message "User not found" + } + } + + Switch ($StorageSolution) { + 'AzureFiles' { + Write-Log -message "Processing Azure Files" + # Convert strings to integers + [int]$StCount = $StorageCount.replace('\"', '"') + [int]$StIndex = $StorageIndex.replace('\"', '"') + Write-Log -message "Storage Account Count: $StCount" + Write-Log -message "Storage Account Index: $StIndex" + # Remove any escape characters from strings + $OuPath = $OuPath.Replace('\"', '"') + Write-Log -message "OU Path: $OuPath" + $ResourceManagerUri = $ResourceManagerUri.Replace('\"', '"') + Write-Log -message "ResourceManagerUri: $ResourceManagerUri" + $StorageAccountPrefix = $StorageAccountPrefix.ToLower().replace('\"', '"') + Write-Log -message "Storage Account Prefix: $StorageAccountPrefix" + $StorageAccountResourceGroupName = $StorageAccountResourceGroupName.Replace('\"', '"') + Write-Log -message "Storage Account Resource Group Name: $StorageAccountResourceGroupName" + $SubscriptionId = $SubscriptionId.replace('\"', '"') + Write-Log -message "Subscription Id: $SubscriptionId" + $UserAssignedIdentityClientId = $UserAssignedIdentityClientId.replace('\"', '"') + Write-Log -message "User Assigned Identity Client Id: $UserAssignedIdentityClientId" + # Set the suffix for the Azure Files + $FilesSuffix = ".file.$($StorageSuffix.Replace('\"', '"'))" + Write-Log -message "Files Suffix: $FilesSuffix" + # Fix the resource manager URI since only AzureCloud contains a trailing slash + $ResourceManagerUriFixed = if ($ResourceManagerUri[-1] -eq '/') { $ResourceManagerUri.Substring(0, $ResourceManagerUri.Length - 1) } else { $ResourceManagerUri } + # Get an access token for Azure resources + Write-Log -message "Getting an access token for Azure resources" + $AzureManagementAccessToken = (Invoke-RestMethod ` + -Headers @{Metadata = "true" } ` + -Uri $('http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=' + $ResourceManagerUriFixed + '&client_id=' + $UserAssignedIdentityClientId)).access_token + # Set header for Azure Management API + $AzureManagementHeader = @{ + 'Content-Type' = 'application/json' + 'Authorization' = 'Bearer ' + $AzureManagementAccessToken + } + for ($i = 0; $i -lt $StCount; $i++) { + # Build the Storage Account Name and FQDN + $StorageAccountName = $StorageAccountPrefix + ($i + $StIndex).ToString().PadLeft(2, '0') + Write-Log -message "Processing Storage Account Name: $StorageAccountName" + $FileServer = '\\' + $StorageAccountName + $FilesSuffix + # Get the storage account key + $StorageKey = (Invoke-RestMethod ` + -Headers $AzureManagementHeader ` + -Method 'POST' ` + -Uri $($ResourceManagerUriFixed + '/subscriptions/' + $SubscriptionId + '/resourceGroups/' + $StorageAccountResourceGroupName + '/providers/Microsoft.Storage/storageAccounts/' + $StorageAccountName + '/listKeys?api-version=2023-05-01')).keys[0].value + + # Create credential for accessing the storage account + Write-Log -message "Building Storage Key Credential" + $StorageUsername = 'Azure\' + $StorageAccountName + $StoragePassword = ConvertTo-SecureString -String "$($StorageKey)" -AsPlainText -Force + [pscredential]$StorageKeyCredential = New-Object System.Management.Automation.PSCredential ($StorageUsername, $StoragePassword) + Write-Log -message "Successfully Built Storage Key Credential" + # Get / create kerberos key for Azure Storage Account + Write-Log -message "Getting Kerberos Key for Azure Storage Account" + $KerberosKey = ((Invoke-RestMethod ` + -Headers $AzureManagementHeader ` + -Method 'POST' ` + -Uri $($ResourceManagerUriFixed + '/subscriptions/' + $SubscriptionId + '/resourceGroups/' + $StorageAccountResourceGroupName + '/providers/Microsoft.Storage/storageAccounts/' + $StorageAccountName + '/listKeys?api-version=2023-05-01&$expand=kerb')).keys | Where-Object { $_.Keyname -contains 'kerb1' }).Value + + if (!$KerberosKey) { + Write-Log -message "Kerberos Key not found, Generating a new key" + $null = Invoke-RestMethod ` + -Body (@{keyName = 'kerb1' } | ConvertTo-Json) ` + -Headers $AzureManagementHeader ` + -Method 'POST' ` + -Uri $($ResourceManagerUriFixed + '/subscriptions/' + $SubscriptionId + '/resourceGroups/' + $StorageAccountResourceGroupName + '/providers/Microsoft.Storage/storageAccounts/' + $StorageAccountName + '/regenerateKey?api-version=2023-05-01') + $Key = ((Invoke-RestMethod ` + -Headers $AzureManagementHeader ` + -Method 'POST' ` + -Uri $($ResourceManagerUriFixed + '/subscriptions/' + $SubscriptionId + '/resourceGroups/' + $StorageAccountResourceGroupName + '/providers/Microsoft.Storage/storageAccounts/' + $StorageAccountName + '/listKeys?api-version=2023-05-01&$expand=kerb')).keys | Where-Object { $_.Keyname -contains 'kerb1' }).Value + } + else { + Write-Log -message "Kerberos Key found" + $Key = $KerberosKey + } + # Creates a password for the Azure Storage Account in AD using the Kerberos key + Write-Log -message "Creating a password for the Azure Storage Account in AD using the Kerberos key" + $ComputerPassword = ConvertTo-SecureString -String $Key.Replace("'", "") -AsPlainText -Force + # Create the SPN value for the Azure Storage Account; attribute for computer object in AD + Write-Log -message "Creating the SPN value for the Azure Storage Account" + $SPN = 'cifs/' + $StorageAccountName + $FilesSuffix + # Create the Description value for the Azure Storage Account; attribute for computer object in AD + $Description = "Computer account object for Azure storage account $($StorageAccountName)." + + # Create the AD computer object for the Azure Storage Account + Write-Log -message "Searching for existing computer account object for Azure Storage Account" + $Computer = Get-ADComputer -Credential $DomainCredential -Filter { Name -eq $StorageAccountName } + if ($Computer) { + Write-Log -message "Computer account object for Azure Storage Account found, removing the existing object" + Remove-ADComputer -Credential $DomainCredential -Identity $StorageAccountName -Confirm:$false + } + Else { + Write-Log -message "Computer account object for Azure Storage Account not found" + } + Write-Log -message "Creating the AD computer object for the Azure Storage Account" + $ComputerObject = New-ADComputer -Credential $DomainCredential -Name $StorageAccountName -Path $OuPath -ServicePrincipalNames $SPN -AccountPassword $ComputerPassword -Description $Description -PassThru + # Update the Azure Storage Account with the domain join 'INFO' + Write-Log -message "Updating the Azure Storage Account with the domain join 'INFO'" + $SamAccountName = switch ($KerberosEncryptionType) { + 'AES256' { $StorageAccountName } + 'RC4' { $ComputerObject.SamAccountName } + } + $Body = (@{ + properties = @{ + azureFilesIdentityBasedAuthentication = @{ + activeDirectoryProperties = @{ + accountType = 'Computer' + azureStorageSid = $ComputerObject.SID.Value + domainGuid = $Domain.ObjectGUID.Guid + domainName = $Domain.DNSRoot + domainSid = $Domain.DomainSID.Value + forestName = $Domain.Forest + netBiosDomainName = $Domain.NetBIOSName + samAccountName = $samAccountName + } + directoryServiceOptions = 'AD' + } + } + } | ConvertTo-Json -Depth 6 -Compress) + + $null = Invoke-RestMethod ` + -Body $Body ` + -Headers $AzureManagementHeader ` + -Method 'PATCH' ` + -Uri $($ResourceManagerUriFixed + '/subscriptions/' + $SubscriptionId + '/resourceGroups/' + $StorageAccountResourceGroupName + '/providers/Microsoft.Storage/storageAccounts/' + $StorageAccountName + '?api-version=2023-05-01') + + # Enable AES256 encryption if selected + if ($KerberosEncryptionType -eq 'AES256') { + Write-Log -message "Setting the Kerberos encryption to $KerberosEncryptionType the computer object" + # Set the Kerberos encryption on the computer object + $DistinguishedName = 'CN=' + $StorageAccountName + ',' + $OuPath + Set-ADComputer -Credential $DomainCredential -Identity $DistinguishedName -KerberosEncryptionType 'AES256' | Out-Null + + # Reset the Kerberos key on the Storage Account + Write-Log -message "Resetting the kerb1 key on the Storage Account" + $null = Invoke-RestMethod ` + -Body (@{keyName = 'kerb1' } | ConvertTo-Json) ` + -Headers $AzureManagementHeader ` + -Method 'POST' ` + -Uri $($ResourceManagerUriFixed + '/subscriptions/' + $SubscriptionId + '/resourceGroups/' + $StorageAccountResourceGroupName + '/providers/Microsoft.Storage/storageAccounts/' + $StorageAccountName + '/regenerateKey?api-version=2023-05-01') + + Write-Log -message "Resetting the kerb2 key on the Storage Account" + $null = Invoke-RestMethod ` + -Body (@{keyName = 'kerb2' } | ConvertTo-Json) ` + -Headers $AzureManagementHeader ` + -Method 'POST' ` + -Uri $($ResourceManagerUriFixed + '/subscriptions/' + $SubscriptionId + '/resourceGroups/' + $StorageAccountResourceGroupName + '/providers/Microsoft.Storage/storageAccounts/' + $StorageAccountName + '/regenerateKey?api-version=2023-05-01') + + $Key = ((Invoke-RestMethod ` + -Headers $AzureManagementHeader ` + -Method 'POST' ` + -Uri $($ResourceManagerUriFixed + '/subscriptions/' + $SubscriptionId + '/resourceGroups/' + $StorageAccountResourceGroupName + '/providers/Microsoft.Storage/storageAccounts/' + $StorageAccountName + '/listKeys?api-version=2023-05-01&$expand=kerb')).keys | Where-Object { $_.Keyname -contains 'kerb1' }).Value + + # Update the password on the computer object with the new Kerberos key on the Storage Account + Write-Log -message "Updating the password on the computer object with the new Kerberos key (kerb1) on the Storage Account" + $NewPassword = ConvertTo-SecureString -String $Key -AsPlainText -Force + Set-ADAccountPassword -Credential $DomainCredential -Identity $DistinguishedName -Reset -NewPassword $NewPassword | Out-Null + } + if ($ShardAzureFilesStorage -eq 'true') { + foreach ($Share in $Shares) { + $FileShare = $FileServer + '\' + $Share + $UserGroup = $null + [array]$UserGroup += $UserGroups[$i] + Write-Log -message "Processing File Share: $FileShare with UserGroup = $($UserGroups[$i])" + if ($AdminGroups.Count -gt 0) { + Write-Log -message "Admin Groups provided, executing Update-ACL with Admin Groups" + Update-ACL -AdminGroups $AdminGroups -Credential $StorageKeyCredential -FileShare $FileShare -UserGroups $UserGroup + } + Else { + Write-Log -message "Admin Groups not provided, executing Update-ACL without Admin Groups" + Update-ACL -Credential $StorageKeyCredential -FileShare $FileShare -UserGroups $UserGroup + } + } + } + Else { + foreach ($Share in $Shares) { + $FileShare = $FileServer + '\' + $Share + Write-Log -message "Processing File Share: $FileShare" + if ($AdminGroups.Count -gt 0) { + Write-Log -message "Admin Groups provided, executing Update-ACL with Admin Groups" + Update-ACL -AdminGroups $AdminGroups -Credential $StorageKeyCredential -FileShare $FileShare -UserGroups $UserGroups + } + Else { + Write-Log -message "Admin Groups not provided, executing Update-ACL without Admin Groups" + Update-ACL -Credential $StorageKeyCredential -FileShare $FileShare -UserGroups $UserGroups + } + } + } + } + } + 'AzureNetAppFiles' { + Write-Log -message "Processing Azure NetApp Files" + + [array]$NetAppServers = ConvertFrom-JsonString -JsonString $NetAppServers -Name 'NetAppServers' + + $ProfileShare = "\\$($NetAppServers[0])\$($Shares[0])" + Write-Log -message "Processing Profile Share: $ProfileShare" + if ($AdminGroups.Count -gt 0) { + Write-Log -message "Admin Groups and UserGroups provided, executing Update-ACL with Admin Groups and UserGroups" + Update-ACL -AdminGroups $AdminGroups -Credential $DomainCredential -FileShare $ProfileShare -UserGroups $UserGroups + } + Else { + Write-Log -message "UserGroups provided, executing Update-ACL with UserGroups only" + Update-ACL -Credential $DomainCredential -FileShare $ProfileShare -UserGroups $UserGroups + } + + If ($NetAppServers.Count -gt 1 -and $Shares.Count -gt 1) { + $OfficeShare = "\\" + $NetAppServers[1] + "\" + $Shares[1] + Write-Log -message "Processing Office Share: $OfficeShare" + If ($AdminGroups.Count -gt 0 -and $UserGroups.Count -gt 0) { + Write-Log -message "Admin Groups and UserGroups provided, executing Update-ACL with Admin Groups and UserGroups" + Update-ACL -AdminGroups $AdminGroups -Credential $DomainCredential -FileShare $OfficeShare -UserGroups $UserGroups + } + ElseIf ($AdminGroups.Count -gt 0 -and $UserGroups.Count -eq 0) { + Write-Log -message "Admin Groups provided, executing Update-ACL with Admin Groups only" + Update-ACL -AdminGroups $AdminGroups -Credential $DomainCredential -FileShare $OfficeShare + } + ElseIf ($AdminGroups.Count -eq 0 -and $UserGroups.Count -gt 0) { + Write-Log -message "UserGroups provided, executing Update-ACL with UserGroups only" + Update-ACL -Credential $DomainCredential -FileShare $OfficeShare -UserGroups $UserGroups + } + Else { + Write-Log -message "No Admin Groups or UserGroups provided, executing Update-ACL without Admin Groups or UserGroups" + Update-ACL -Credential $DomainCredential -FileShare $OfficeShare + } + } + } + } +} +catch { + throw +} \ No newline at end of file diff --git a/workload/scripts/Set-SessionHostConfiguration copy.ps1 b/workload/scripts/Set-SessionHostConfiguration copy.ps1 new file mode 100644 index 000000000..916525822 --- /dev/null +++ b/workload/scripts/Set-SessionHostConfiguration copy.ps1 @@ -0,0 +1,502 @@ +Param( + [parameter(Mandatory = $false)] + [string] + $IdentityDomainName, + + [parameter(Mandatory)] + [string] + $AmdVmSize, + + [parameter(Mandatory)] + [string] + $IdentityServiceProvider, + + [parameter(Mandatory)] + [string] + $FSLogix, + + [parameter(Mandatory = $false)] + [string] + $FSLogixStorageAccountKey, + + [parameter(Mandatory = $false)] + [string] + $FSLogixFileShare, + + [parameter(Mandatory)] + [string] + $HostPoolRegistrationToken, + + [parameter(Mandatory)] + [string] + $NvidiaVmSize + + # [parameter(Mandatory)] + # [string] + # $ScreenCaptureProtection +) + +function New-Log { + Param ( + [Parameter(Mandatory = $true, Position = 0)] + [string] $Path + ) + + $date = Get-Date -UFormat "%Y-%m-%d %H-%M-%S" + Set-Variable logFile -Scope Script + $script:logFile = "$Script:Name-$date.log" + + if ((Test-Path $path ) -eq $false) { + $null = New-Item -Path $path -ItemType directory + } + + $script:Log = Join-Path $path $logfile + + Add-Content $script:Log "Date`t`t`tCategory`t`tDetails" +} + +function Write-Log { + Param ( + [Parameter(Mandatory = $false, Position = 0)] + [ValidateSet("Info", "Warning", "Error")] + $Category = 'Info', + [Parameter(Mandatory = $true, Position = 1)] + $Message + ) + + $Date = get-date + $Content = "[$Date]`t$Category`t`t$Message`n" + Add-Content $Script:Log $content -ErrorAction Stop + If ($Verbose) { + Write-Verbose $Content + } + Else { + Switch ($Category) { + 'Info' { Write-Host $content } + 'Error' { Write-Error $Content } + 'Warning' { Write-Warning $Content } + } + } +} + +function Get-WebFile { + param( + [parameter(Mandatory)] + [string]$FileName, + + [parameter(Mandatory)] + [string]$URL + ) + $Counter = 0 + do { + Invoke-WebRequest -Uri $URL -OutFile $FileName -ErrorAction 'SilentlyContinue' + if ($Counter -gt 0) { + Start-Sleep -Seconds 30 + } + $Counter++ + } + until((Test-Path $FileName) -or $Counter -eq 9) +} + +Function Set-RegistryValue { + [CmdletBinding()] + param ( + [Parameter()] + [string] + $Name, + [Parameter()] + [string] + $Path, + [Parameter()] + [string]$PropertyType, + [Parameter()] + $Value + ) + Begin { + Write-Log -message "[Set-RegistryValue]: Setting Registry Value: $Name" + } + Process { + # Create the registry Key(s) if necessary. + If (!(Test-Path -Path $Path)) { + Write-Log -message "[Set-RegistryValue]: Creating Registry Key: $Path" + New-Item -Path $Path -Force | Out-Null + } + # Check for existing registry setting + $RemoteValue = Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue + If ($RemoteValue) { + # Get current Value + $CurrentValue = Get-ItemPropertyValue -Path $Path -Name $Name + Write-Log -message "[Set-RegistryValue]: Current Value of $($Path)\$($Name) : $CurrentValue" + If ($Value -ne $CurrentValue) { + Write-Log -message "[Set-RegistryValue]: Setting Value of $($Path)\$($Name) : $Value" + Set-ItemProperty -Path $Path -Name $Name -Value $Value -Force | Out-Null + } + Else { + Write-Log -message "[Set-RegistryValue]: Value of $($Path)\$($Name) is already set to $Value" + } + } + Else { + Write-Log -message "[Set-RegistryValue]: Setting Value of $($Path)\$($Name) : $Value" + New-ItemProperty -Path $Path -Name $Name -PropertyType $PropertyType -Value $Value -Force | Out-Null + } + Start-Sleep -Milliseconds 500 + } + End { + } +} + +$ErrorActionPreference = 'Stop' +$Script:Name = 'Set-SessionHostConfiguration' +New-Log -Path (Join-Path -Path $env:SystemRoot -ChildPath 'Logs') +try { + + ############################################################## + # Add Recommended AVD Settings + ############################################################## + $Settings = @( + + # Disable Automatic Updates: https://docs.microsoft.com/en-us/azure/virtual-desktop/set-up-customize-master-image#disable-automatic-updates + [PSCustomObject]@{ + Name = 'NoAutoUpdate' + Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' + PropertyType = 'DWord' + Value = 1 + }, + + # Enable Time Zone Redirection: https://docs.microsoft.com/en-us/azure/virtual-desktop/set-up-customize-master-image#set-up-time-zone-redirection + [PSCustomObject]@{ + Name = 'fEnableTimeZoneRedirection' + Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' + PropertyType = 'DWord' + Value = 1 + } + ) + + ############################################################## + # Add GPU Settings + ############################################################## + # This setting applies to the VM Size's recommended for AVD with a GPU + if ($AmdVmSize -eq 'true' -or $NvidiaVmSize -eq 'true') { + $Settings += @( + + # Configure GPU-accelerated app rendering: https://docs.microsoft.com/en-us/azure/virtual-desktop/configure-vm-gpu#configure-gpu-accelerated-app-rendering + [PSCustomObject]@{ + Name = 'bEnumerateHWBeforeSW' + Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' + PropertyType = 'DWord' + Value = 1 + }, + # Configure fullscreen video encoding: https://docs.microsoft.com/en-us/azure/virtual-desktop/configure-vm-gpu#configure-fullscreen-video-encoding + [PSCustomObject]@{ + Name = 'AVC444ModePreferred' + Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' + PropertyType = 'DWord' + Value = 1 + }, + [PSCustomObject]@{ + Name = 'KeepAliveEnable' + Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' + PropertyType = 'DWord' + Value = 1 + }, + [PSCustomObject]@{ + Name = 'KeepAliveInterval' + Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' + PropertyType = 'DWord' + Value = 1 + }, + [PSCustomObject]@{ + Name = 'MinEncryptionLevel' + Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' + PropertyType = 'DWord' + Value = 3 + }, + [PSCustomObject]@{ + Name = 'AVCHardwareEncodePreferred' + Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' + PropertyType = 'DWord' + Value = 1 + } + ) + } + # This setting applies only to VM Size's recommended for AVD with a Nvidia GPU + if ($NvidiaVmSize -eq 'true') { + $Settings += @( + + # Configure GPU-accelerated frame encoding: https://docs.microsoft.com/en-us/azure/virtual-desktop/configure-vm-gpu#configure-gpu-accelerated-frame-encoding + [PSCustomObject]@{ + Name = 'AVChardwareEncodePreferred' + Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' + PropertyType = 'DWord' + Value = 1 + } + ) + } + + # ############################################################## + # # Add Screen Capture Protection Setting + # ############################################################## + # if ($ScreenCaptureProtection -eq 'true') { + # $Settings += @( + + # # Enable Screen Capture Protection: https://docs.microsoft.com/en-us/azure/virtual-desktop/screen-capture-protection + # [PSCustomObject]@{ + # Name = 'fEnableScreenCaptureProtect' + # Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' + # PropertyType = 'DWord' + # Value = 1 + # } + # ) + # } + + ############################################################## + # Add Fslogix Settings + ############################################################## + if ($Fslogix -eq 'true') { + $FSLogixStorageFQDN = $FSLogixFileShare.Split('\')[2] + $Settings += @( + # Enables Fslogix profile containers: https://docs.microsoft.com/en-us/fslogix/profile-container-configuration-reference#enabled + [PSCustomObject]@{ + Name = 'Enabled' + Path = 'HKLM:\SOFTWARE\Fslogix\Profiles' + PropertyType = 'DWord' + Value = 1 + }, + # Deletes a local profile if it exists and matches the profile being loaded from VHD: https://docs.microsoft.com/en-us/fslogix/profile-container-configuration-reference#deletelocalprofilewhenvhdshouldapply + [PSCustomObject]@{ + Name = 'DeleteLocalProfileWhenVHDShouldApply' + Path = 'HKLM:\SOFTWARE\FSLogix\Profiles' + PropertyType = 'DWord' + Value = 1 + }, + # The folder created in the Fslogix fileshare will begin with the username instead of the SID: https://docs.microsoft.com/en-us/fslogix/profile-container-configuration-reference#flipflopprofiledirectoryname + [PSCustomObject]@{ + Name = 'FlipFlopProfileDirectoryName' + Path = 'HKLM:\SOFTWARE\FSLogix\Profiles' + PropertyType = 'DWord' + Value = 1 + }, + # # Loads FRXShell if there's a failure attaching to, or using an existing profile VHD(X): https://docs.microsoft.com/en-us/fslogix/profile-container-configuration-reference#preventloginwithfailure + # [PSCustomObject]@{ + # Name = 'PreventLoginWithFailure' + # Path = 'HKLM:\SOFTWARE\FSLogix\Profiles' + # PropertyType = 'DWord' + # Value = 1 + # }, + # # Loads FRXShell if it's determined a temp profile has been created: https://docs.microsoft.com/en-us/fslogix/profile-container-configuration-reference#preventloginwithtempprofile + # [PSCustomObject]@{ + # Name = 'PreventLoginWithTempProfile' + # Path = 'HKLM:\SOFTWARE\FSLogix\Profiles' + # PropertyType = 'DWord' + # Value = 1 + # }, + # List of file system locations to search for the user's profile VHD(X) file: https://docs.microsoft.com/en-us/fslogix/profile-container-configuration-reference#vhdlocations + [PSCustomObject]@{ + Name = 'VHDLocations' + Path = 'HKLM:\SOFTWARE\FSLogix\Profiles' + PropertyType = 'MultiString' + Value = $FSLogixFileShare + }, + [PSCustomObject]@{ + Name = 'VolumeType' + Path = 'HKLM:\SOFTWARE\FSLogix\Profiles' + PropertyType = 'String' + Value = 'vhdx' + }, + [PSCustomObject]@{ + Name = 'LockedRetryCount' + Path = 'HKLM:\SOFTWARE\FSLogix\Profiles' + PropertyType = 'DWord' + Value = 3 + }, + [PSCustomObject]@{ + Name = 'LockedRetryInterval' + Path = 'HKLM:\SOFTWARE\FSLogix\Profiles' + PropertyType = 'DWord' + Value = 15 + }, + [PSCustomObject]@{ + Name = 'ReAttachIntervalSeconds' + Path = 'HKLM:\SOFTWARE\FSLogix\Profiles' + PropertyType = 'DWord' + Value = 15 + }, + [PSCustomObject]@{ + Name = 'ReAttachRetryCount' + Path = 'HKLM:\SOFTWARE\FSLogix\Profiles' + PropertyType = 'DWord' + Value = 3 + } + ) + if ($IdentityServiceProvider -eq "EntraIDKerberos" -and $Fslogix -eq 'true') { + $Settings += @( + [PSCustomObject]@{ + Name = 'CloudKerberosTicketRetrievalEnabled' + Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters' + PropertyType = 'DWord' + Value = 1 + }, + [PSCustomObject]@{ + Name = 'LoadCredKeyFromProfile' + Path = 'HKLM:\Software\Policies\Microsoft\AzureADAccount' + PropertyType = 'DWord' + Value = 1 + }, + [PSCustomObject]@{ + Name = $IdentityDomainName + Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\domain_realm' + PropertyType = 'String' + Value = $FSLogixStorageFQDN + } + + ) + } + If ($FsLogixStorageAccountKey -ne '') { + $SAName = $FSLogixStorageFQDN.Split('.')[0] + Write-Log -Message "Adding Local Storage Account Key for '$FSLogixStorageFQDN' to Credential Manager" -Category 'Info' + $CMDKey = Start-Process -FilePath 'cmdkey.exe' -ArgumentList "/add:$FSLogixStorageFQDN /user:localhost\$SAName /pass:$FSLogixStorageAccountKey" -Wait -PassThru + If ($CMDKey.ExitCode -ne 0) { + Write-Log -Message "CMDKey Failed with '$($CMDKey.ExitCode)'. Failed to add Local Storage Account Key for '$FSLogixStorageFQDN' to Credential Manager" -Category 'Error' + } + Else { + Write-Log -Message "Successfully added Local Storage Account Key for '$FSLogixStorageFQDN' to Credential Manager" -Category 'Info' + } + $Settings += @( + # Attach the users VHD(x) as the computer: https://learn.microsoft.com/en-us/fslogix/reference-configuration-settings?tabs=profiles#accessnetworkascomputerobject + [PSCustomObject]@{ + Name = 'AccessNetworkAsComputerObject' + Path = 'HKLM:\SOFTWARE\FSLogix\Profiles' + PropertyType = 'DWord' + Value = 1 + } + ) + $Settings += @( + # Disable Roaming the Recycle Bin because it corrupts. https://learn.microsoft.com/en-us/fslogix/reference-configuration-settings?tabs=profiles#roamrecyclebin + [PSCustomObject]@{ + Name = 'RoamRecycleBin' + Path = 'HKLM:\SOFTWARE\FSLogix\Apps' + PropertyType = 'DWord' + Value = 0 + } + ) + # Disable the Recycle Bin + Reg LOAD "HKLM\TempHive" "$env:SystemDrive\Users\Default User\NtUser.dat" + Set-RegistryValue -Path 'HKLM:\TempHive\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer' -Name NoRecycleFiles -PropertyType DWord -Value 1 + Write-Log -Message "Unloading default user hive." + $null = cmd /c REG UNLOAD "HKLM\TempHive" '2>&1' + If ($LastExitCode -ne 0) { + # sometimes the registry doesn't unload properly so we have to perform powershell garbage collection first. + [GC]::Collect() + [GC]::WaitForPendingFinalizers() + Start-Sleep -Seconds 5 + $null = cmd /c REG UNLOAD "HKLM\TempHive" '2>&1' + If ($LastExitCode -eq 0) { + Write-Log -Message "Hive unloaded successfully." + } + Else { + Write-Log -category Error -Message "Default User hive unloaded with exit code [$LastExitCode]." + } + } + Else { + Write-Log -Message "Hive unloaded successfully." + } + } + $LocalAdministrator = (Get-LocalUser | Where-Object { $_.SID -like '*-500' }).Name + $LocalGroups = 'FSLogix Profile Exclude List', 'FSLogix ODFC Exclude List' + ForEach ($Group in $LocalGroups) { + If (-not (Get-LocalGroupMember -Group $Group | Where-Object { $_.Name -like "*$LocalAdministrator" })) { + Add-LocalGroupMember -Group $Group -Member $LocalAdministrator + } + } + } + + ############################################################## + # Add Microsoft Entra ID Join Setting + ############################################################## + if ($IdentityServiceProvider -match "EntraID") { + $Settings += @( + + # Enable PKU2U: https://docs.microsoft.com/en-us/azure/virtual-desktop/troubleshoot-azure-ad-connections#windows-desktop-client + [PSCustomObject]@{ + Name = 'AllowOnlineID' + Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\pku2u' + PropertyType = 'DWord' + Value = 1 + } + ) + } + + # Set registry settings + foreach ($Setting in $Settings) { + Set-RegistryValue -Name $Setting.Name -Path $Setting.Path -PropertyType $Setting.PropertyType -Value $Setting.Value -Verbose + } + + # Resize OS Disk + Write-Log -message "Resizing OS Disk" + $driveLetter = $env:SystemDrive.Substring(0, 1) + $size = Get-PartitionSupportedSize -DriveLetter $driveLetter + Resize-Partition -DriveLetter $driveLetter -Size $size.SizeMax + Write-Log -message "OS Disk Resized" + + ############################################################## + # Add Defender Exclusions for FSLogix + ############################################################## + # https://docs.microsoft.com/en-us/azure/architecture/example-scenario/wvd/windows-virtual-desktop-fslogix#antivirus-exclusions + if ($Fslogix -eq 'true') { + + $Files = @( + "%ProgramFiles%\FSLogix\Apps\frxdrv.sys", + "%ProgramFiles%\FSLogix\Apps\frxdrvvt.sys", + "%ProgramFiles%\FSLogix\Apps\frxccd.sys", + "%TEMP%\*.VHD", + "%TEMP%\*.VHDX", + "%Windir%\TEMP\*.VHD", + "%Windir%\TEMP\*.VHDX" + "$FslogixFileShareName\*.VHD" + "$FslogixFileShareName\*.VHDX" + ) + + foreach ($File in $Files) { + Add-MpPreference -ExclusionPath $File + } + Write-Log -Message 'Enabled Defender exlusions for FSLogix paths' -Category 'Info' + + $Processes = @( + "%ProgramFiles%\FSLogix\Apps\frxccd.exe", + "%ProgramFiles%\FSLogix\Apps\frxccds.exe", + "%ProgramFiles%\FSLogix\Apps\frxsvc.exe" + ) + + foreach ($Process in $Processes) { + Add-MpPreference -ExclusionProcess $Process + } + Write-Log -Message 'Enabled Defender exlusions for FSLogix processes' -Category 'Info' + } + + + ############################################################## + # Install the AVD Agent + ############################################################## + $BootInstaller = 'AVD-Bootloader.msi' + Get-WebFile -FileName $BootInstaller -URL 'https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RWrxrH' + Start-Process -FilePath 'msiexec.exe' -ArgumentList "/i $BootInstaller /quiet /qn /norestart /passive" -Wait -Passthru + Write-Log -Message 'Installed AVD Bootloader' -Category 'Info' + Start-Sleep -Seconds 5 + + $AgentInstaller = 'AVD-Agent.msi' + Get-WebFile -FileName $AgentInstaller -URL 'https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RWrmXv' + Start-Process -FilePath 'msiexec.exe' -ArgumentList "/i $AgentInstaller /quiet /qn /norestart /passive REGISTRATIONTOKEN=$HostPoolRegistrationToken" -Wait -PassThru + Write-Log -Message 'Installed AVD Agent' -Category 'Info' + Start-Sleep -Seconds 5 + + ############################################################## + # Restart VM + ############################################################## + if ($IdentityServiceProvider -eq "EntraIDKerberos" -and $AmdVmSize -eq 'false' -and $NvidiaVmSize -eq 'false') { + Start-Process -FilePath 'shutdown' -ArgumentList '/r /t 30' + } +} +catch { + Write-Log -Message $_ -Category 'Error' + throw +} \ No newline at end of file From e41e2abd48cffaa1f95fb006e6035fea833484d6 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Mon, 31 Mar 2025 17:24:07 -0500 Subject: [PATCH 20/55] pushing new AVM version --- workload/bicep/deploy-baseline.bicep | 7 +++++-- .../bicep/modules/sharedModules/storage.bicep | 15 ++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index 4b4fa539d..6bc5ce384 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -240,13 +240,16 @@ param avdDeploySessionHostsCount int = 1 @sys.description('The session host number to begin with for the deployment. This is important when adding virtual machines to ensure the names do not conflict. (Default: 1)') param avdSessionHostCountIndex int = 1 -@sys.description('When set to AvailabilityZones, VMs and storage are distributed across availability zones, when set to None, VMs and storage will be deployed at regional level.') +@sys.description('When set to AvailabilityZones, VMs are distributed across availability zones, when set to None, VMs are deployed at regional level.') @allowed([ 'None' 'AvailabilityZones' ]) param availability string = 'None' +@sys.description('When true, Zone Redundant Storage (ZRS) is used, when set to false, Locally Redundant Storage (LRS) is used. (Default: false)') +param zoneRedundantStorage bool = false + @sys.description('The Availability Zones to use for the session hosts.') @allowed([ '1' @@ -1389,7 +1392,7 @@ module storage './modules/sharedModules/storage.bicep' = if (varCreateStorageDep deploymentEnvironment: varDeploymentEnvironmentLowercase storageService: storageService useCustomNaming: avdUseCustomNaming - availability: availability + storageAvailabilityZones: zoneRedundantStorage domainJoinUserName: avdDomainJoinUserName vmLocalUserName: avdVmLocalUserName identityServiceProvider: avdIdentityServiceProvider diff --git a/workload/bicep/modules/sharedModules/storage.bicep b/workload/bicep/modules/sharedModules/storage.bicep index 9563a72d1..e690ba296 100644 --- a/workload/bicep/modules/sharedModules/storage.bicep +++ b/workload/bicep/modules/sharedModules/storage.bicep @@ -103,8 +103,8 @@ param sessionHostTimeZone string @description('The resource ID of the application security group.') param applicationSecurityGroupResourceId string -@description('The availability setting (AvailabilityZones or other).') -param availability string +@description('USe or not zone redundant storage.') +param storageAvailabilityZones bool @description('The custom DNS IPs.') param dnsServers string @@ -194,7 +194,7 @@ var varFslogixAnfVolume = createFslogixDeployment name: varFslogixFileShareName coolAccess: false encryptionKeySource: 'Microsoft.NetApp' - zones: [] // availability == 'AvailabilityZones' + zones: [] // storageAvailabilityZones //? availabilityZones //: [] serviceLevel: fslogixStoragePerformance @@ -216,7 +216,7 @@ var varAppAttchAnfVolume = createAppAttachDeployment name: varAppAttachFileShareName coolAccess: false encryptionKeySource: 'Microsoft.NetApp' - zones: [] // availability == 'AvailabilityZones' + zones: [] // storageAvailabilityZones //? availabilityZones //: [] serviceLevel: appAttachStoragePerformance @@ -278,13 +278,10 @@ var varFslogixStoragePerformance = fslogixStoragePerformance == 'Ultra' var varAppAttachStoragePerformance = appAttachStoragePerformance == 'Ultra' ? 'Premium' : appAttachStoragePerformance -var varStorageAccountAvailability = availability == 'AvailabilityZones' - ? true - : false -var varFslogixStorageSku = (varStorageAccountAvailability && storageService == 'AzureFiles') +var varFslogixStorageSku = (storageAvailabilityZones && storageService == 'AzureFiles') ? '${varFslogixStoragePerformance}_ZRS' : '${varFslogixStoragePerformance}_LRS' -var varAppAttachStorageSku = varStorageAccountAvailability +var varAppAttachStorageSku = storageAvailabilityZones ? '${varAppAttachStoragePerformance}_ZRS' : '${varAppAttachStoragePerformance}_LRS' var varStorageAzureFilesDscAgentPackageLocation = 'https://github.com/Azure/avdaccelerator/raw/main/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip' From 0365b86db840a16b35f2011423133bd32337faa9 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 09:07:53 -0500 Subject: [PATCH 21/55] updates --- readme.md | 4 +- workload/arm/deploy-baseline.json | 22515 +++++--- workload/bicep/deploy-baseline.bicep | 2 +- workload/bicep/deploy-baseline.json | 44083 ++++++++++++++++ workload/portal-ui/portal-ui-baseline.json | 63 +- .../1.0.3/Script-DomainJoinStorage.ps1 | 4 - 6 files changed, 58253 insertions(+), 8418 deletions(-) create mode 100644 workload/bicep/deploy-baseline.json diff --git a/readme.md b/readme.md index f8ceec14b..dbf605a98 100644 --- a/readme.md +++ b/readme.md @@ -31,7 +31,7 @@ As of today, we have a first reference implementation scenario that is one of th | Deployment Type | Link | |:--|:--| -| Azure portal UI |[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fmain%2Fworkload%2Farm%2Fdeploy-baseline.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fmain%2Fworkload%2Fportal-ui%2Fportal-ui-baseline.json) [![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/?feature.deployapiver=2022-12-01#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fmain%2Fworkload%2Farm%2Fdeploy-baseline.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fmain%2Fworkload%2Fportal-ui%2Fportal-ui-baseline.json) [![Deploy to Azure China](https://aka.ms/deploytoazurechinabutton)](https://portal.azure.cn/?feature.deployapiver=2022-12-01#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fmain%2Fworkload%2Farm%2Fdeploy-baseline.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fmain%2Fworkload%2Fportal-ui%2Fportal-ui-baseline.json)| +| Azure portal UI |[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fanf-fslogix%2Fworkload%2Farm%2Fdeploy-baseline.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fanf-fslogix%2Fworkload%2Fportal-ui%2Fportal-ui-baseline.json) [![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/?feature.deployapiver=2022-12-01#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fanf-fslogix%2Fworkload%2Farm%2Fdeploy-baseline.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fanf-fslogix%2Fworkload%2Fportal-ui%2Fportal-ui-baseline.json) [![Deploy to Azure China](https://aka.ms/deploytoazurechinabutton)](https://portal.azure.cn/?feature.deployapiver=2022-12-01#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fanf-fslogix%2Fworkload%2Farm%2Fdeploy-baseline.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fanf-fslogix%2Fworkload%2Fportal-ui%2Fportal-ui-baseline.json)| | Command line (Bicep/ARM) | [![Powershell/Azure CLI](./workload/docs/icons/powershell.png)](./workload/bicep/readme.md#avd-accelerator-baseline) | | Terraform | [![Terraform](./workload/docs/icons/terraform.png)](./workload/terraform/greenfield/readme.md) | @@ -87,7 +87,7 @@ Custom image is optimized using [Virtual Desktop Optimization Tool (VDOT)](https | Deployment Type | Link | |:--|:--| -| Azure portal UI | [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fmain%2Fworkload%2Farm%2Fdeploy-custom-image.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fmain%2Fworkload%2Fportal-ui%2Fportal-ui-custom-image.json) [![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/?feature.deployapiver=2022-12-01#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fmain%2Fworkload%2Farm%2Fdeploy-custom-image.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fmain%2Fworkload%2Fportal-ui%2Fportal-ui-custom-image.json) | +| Azure portal UI | [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fanf-fslogix%2Fworkload%2Farm%2Fdeploy-custom-image.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fanf-fslogix%2Fworkload%2Fportal-ui%2Fportal-ui-custom-image.json) [![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/?feature.deployapiver=2022-12-01#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fanf-fslogix%2Fworkload%2Farm%2Fdeploy-custom-image.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Favdaccelerator%2Fanf-fslogix%2Fworkload%2Fportal-ui%2Fportal-ui-custom-image.json) | | Command line (Bicep/ARM) | [![Powershell/Azure CLI](./workload/docs/icons/powershell.png)](./workload/bicep/readme.md#optional-custom-image-build-deployment) | | Terraform | [![Terraform](./workload/docs/icons/terraform.png)](./workload/terraform/customimage) | diff --git a/workload/arm/deploy-baseline.json b/workload/arm/deploy-baseline.json index ebd6dc9e6..befe571e0 100644 --- a/workload/arm/deploy-baseline.json +++ b/workload/arm/deploy-baseline.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "8731675713086337665" + "version": "0.34.44.8038", + "templateHash": "18159930501355149539" }, "name": "AVD Accelerator - Baseline Deployment", "description": "AVD Accelerator - Deployment Baseline", @@ -266,11 +266,18 @@ "description": "Existing virtual network subnet for private endpoints. (Default: \"\")" } }, + "existingVnetAnfSubnetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Existing virtual network subnet for ANF. (Default: \"\")" + } + }, "existingHubVnetResourceId": { "type": "string", "defaultValue": "", "metadata": { - "description": "Existing hub virtual network for perring. (Default: \"\")" + "description": "Existing hub virtual network for peering. (Default: \"\")" } }, "avdVnetworkAddressPrefixes": { @@ -294,6 +301,13 @@ "description": "private endpoints virtual network subnet address prefix. (Default: 10.10.2.0/27)" } }, + "vNetworkAnfSubnetAddressPrefix": { + "type": "string", + "defaultValue": "10.10.3.0/26", + "metadata": { + "description": "ANF virtual network subnet address prefix. (Default: 10.10.3.0/26)" + } + }, "customDnsIps": { "type": "string", "defaultValue": "", @@ -364,13 +378,24 @@ "description": "Does the hub contains a virtual network gateway. (Default: false)" } }, - "createAvdFslogixDeployment": { + "createFslogixDeployment": { "type": "bool", "defaultValue": true, "metadata": { "description": "Deploy Fslogix setup. (Default: true)" } }, + "storageService": { + "type": "string", + "defaultValue": "AzureFiles", + "allowedValues": [ + "ANF", + "AzureFiles" + ], + "metadata": { + "description": "Type of storage service to deploy for FSLogix. (Default: AzureFiles)" + } + }, "createAppAttachDeployment": { "type": "bool", "defaultValue": false, @@ -380,16 +405,16 @@ }, "fslogixFileShareQuotaSize": { "type": "int", - "defaultValue": 1, + "defaultValue": 100, "metadata": { - "description": "Fslogix file share size. (Default: 1)" + "description": "Fslogix file share size in GB. (Default: 100)" } }, "appAttachFileShareQuotaSize": { "type": "int", - "defaultValue": 1, + "defaultValue": 100, "metadata": { - "description": "App Attach file share size. (Default: 1)" + "description": "App Attach file share size in GB. (Default: 100)" } }, "avdDeploySessionHosts": { @@ -465,7 +490,14 @@ "AvailabilityZones" ], "metadata": { - "description": "When true VMs are distributed across availability zones, when set to false, VMs will be deployed at regional level." + "description": "When set to AvailabilityZones, VMs are distributed across availability zones, when set to None, VMs are deployed at regional level." + } + }, + "zoneRedundantStorage": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "When true, Zone Redundant Storage (ZRS) is used, when set to false, Locally Redundant Storage (LRS) is used. (Default: false)" } }, "availabilityZones": { @@ -484,22 +516,16 @@ "description": "The Availability Zones to use for the session hosts." } }, - "zoneRedundantStorage": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "When true, Zone Redundant Storage (ZRS) is used, when set to false, Locally Redundant Storage (LRS) is used. (Default: false)" - } - }, "fslogixStoragePerformance": { "type": "string", "defaultValue": "Premium", "allowedValues": [ "Standard", - "Premium" + "Premium", + "Ultra" ], "metadata": { - "description": "Storage account SKU for FSLogix storage. Recommended tier is Premium (Default: Premium)" + "description": "SKU for FSLogix storage. Recommended tier is Premium for storage account and Standard for ANF. (Default: Premium)" } }, "appAttachStoragePerformance": { @@ -507,10 +533,11 @@ "defaultValue": "Premium", "allowedValues": [ "Standard", - "Premium" + "Premium", + "Ultra" ], "metadata": { - "description": "Storage account SKU for App Attach storage. Recommended tier is Premium. (Default: Premium)" + "description": "SKU for App Attach storage. RRecommended tier is Premium for storage account and Standard for ANF. (Default: Premium)" } }, "diskZeroTrust": { @@ -612,7 +639,7 @@ "type": "string", "defaultValue": "", "metadata": { - "description": "OU name for Azure Storage Account. It is recommended to create a new AD Organizational Unit (OU) in AD and disable password expiration policy on computer accounts or service logon accounts accordingly. (Default: \"\")" + "description": "OU name for Azure Storage Account or Azure Netapp Files. It is recommended to create a new AD Organizational Unit (OU) in AD and disable password expiration policy on computer accounts or service logon accounts accordingly. (Default: \"\")" } }, "avdUseCustomNaming": { @@ -694,6 +721,14 @@ "description": "private endpoints virtual network subnet custom name. (Default: snet-pe-app1-dev-use2-001)" } }, + "anfVnetworkSubnetCustomName": { + "type": "string", + "defaultValue": "snet-anf-app1-dev-use2-001", + "maxLength": 80, + "metadata": { + "description": "ANF virtual network subnet custom name. (Default: snet-anf-app1-dev-use2-001)" + } + }, "avdNetworksecurityGroupCustomName": { "type": "string", "defaultValue": "nsg-avd-app1-dev-use2-001", @@ -710,6 +745,14 @@ "description": "Private endpoint network security group custom name. (Default: nsg-pe-app1-dev-use2-001)" } }, + "anfNetworksecurityGroupCustomName": { + "type": "string", + "defaultValue": "nsg-anf-app1-dev-use2-001", + "maxLength": 80, + "metadata": { + "description": "ANF network security group custom name. (Default: nsg-anf-app1-dev-use2-001)" + } + }, "avdRouteTableCustomName": { "type": "string", "defaultValue": "route-avd-app1-dev-use2-001", @@ -806,6 +849,13 @@ "description": "AVD FSLogix and App Attach storage account prefix custom name. (Default: st)" } }, + "anfAccountCustomName": { + "type": "string", + "defaultValue": "anf-acc-app1-dev-use2-001", + "metadata": { + "description": "AVD FSLogix and App Attach storage account prefix custom name. (Default: anf-acc-app1-dev-use2-001)" + } + }, "fslogixFileShareCustomName": { "type": "string", "defaultValue": "fslogix-pc-app1-dev-use2-001", @@ -1305,85 +1355,10 @@ "timeZone": "Mountain Standard Time" } }, - "$fxv#1": { - "win10_22h2_g2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "windows-10", - "sku": "win10-22h2-avd-g2", - "version": "latest" - }, - "win10_22h2_office_g2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "office-365", - "sku": "win10-22h2-avd-m365-g2", - "version": "latest" - }, - "win11_22h2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "Windows-11", - "sku": "win11-22h2-avd", - "version": "latest" - }, - "win11_22h2_office": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "office-365", - "sku": "win11-22h2-avd-m365", - "version": "latest" - }, - "win11_23h2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "Windows-11", - "sku": "win11-23h2-avd", - "version": "latest" - }, - "win11_23h2_office": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "office-365", - "sku": "win11-23h2-avd-m365", - "version": "latest" - }, - "win11_24h2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "Windows-11", - "sku": "win11-24h2-avd", - "version": "latest" - }, - "win11_24h2_office": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "office-365", - "sku": "win11-24h2-avd-m365", - "version": "latest" - }, - "winServer_2022_Datacenter": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "2022-datacenter-g2", - "version": "latest" - }, - "winServer_2022_Datacenter_smalldisk_g2": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "2022-datacenter-smalldisk-g2", - "version": "latest" - }, - "winServer_2022_datacenter_core": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "2022-datacenter-core-g2", - "version": "latest" - }, - "winServer_2022_Datacenter_core_smalldisk_g2": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "2022-datacenter-core-smalldisk-g2", - "version": "latest" - } - }, "varDeploymentPrefixLowercase": "[toLower(parameters('deploymentPrefix'))]", "varAzureCloudName": "[environment().name]", "varDeploymentEnvironmentLowercase": "[toLower(parameters('deploymentEnvironment'))]", - "varDeploymentEnvironmentComputeStorage": "[if(equals(parameters('deploymentEnvironment'), 'Dev'), 'd', if(equals(parameters('deploymentEnvironment'), 'Test'), 't', if(equals(parameters('deploymentEnvironment'), 'Prod'), 'p', '')))]", - "varNamingUniqueStringThreeChar": "[take(format('{0}', uniqueString(parameters('avdWorkloadSubsId'), variables('varDeploymentPrefixLowercase'), parameters('time'))), 3)]", + "varDeploymentEnvironmentOneCharacter": "[if(equals(parameters('deploymentEnvironment'), 'Dev'), 'd', if(equals(parameters('deploymentEnvironment'), 'Test'), 't', if(equals(parameters('deploymentEnvironment'), 'Prod'), 'p', '')))]", "varNamingUniqueStringTwoChar": "[take(format('{0}', uniqueString(parameters('avdWorkloadSubsId'), variables('varDeploymentPrefixLowercase'), parameters('time'))), 2)]", "varSessionHostLocationAcronym": "[variables('varLocations')[variables('varSessionHostLocationLowercase')].acronym]", "varManagementPlaneLocationAcronym": "[variables('varLocations')[variables('varManagementPlaneLocationLowercase')].acronym]", @@ -1405,8 +1380,10 @@ "varRemoteVnetPeeringName": "[format('peer-{0}', variables('varVnetName'))]", "varVnetAvdSubnetName": "[if(parameters('avdUseCustomNaming'), parameters('avdVnetworkSubnetCustomName'), format('snet-avd-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", "varVnetPrivateEndpointSubnetName": "[if(parameters('avdUseCustomNaming'), parameters('privateEndpointVnetworkSubnetCustomName'), format('snet-pe-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", + "varVnetAnfSubnetName": "[if(parameters('avdUseCustomNaming'), parameters('anfVnetworkSubnetCustomName'), format('snet-anf-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", "varAvdNetworksecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('avdNetworksecurityGroupCustomName'), format('nsg-avd-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", "varPrivateEndpointNetworksecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('privateEndpointNetworksecurityGroupCustomName'), format('nsg-pe-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", + "varAnfNetworksecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('anfNetworksecurityGroupCustomName'), format('nsg-anf-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", "varAvdRouteTableName": "[if(parameters('avdUseCustomNaming'), parameters('avdRouteTableCustomName'), format('route-avd-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", "varPrivateEndpointRouteTableName": "[if(parameters('avdUseCustomNaming'), parameters('privateEndpointRouteTableCustomName'), format('route-pe-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", "varApplicationSecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('avdApplicationSecurityGroupCustomName'), format('asg-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", @@ -1430,26 +1407,15 @@ "varWrklKvName": "[if(parameters('avdUseCustomNaming'), format('{0}-{1}-{2}', parameters('avdWrklKvPrefixCustomName'), variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')), format('kv-sec-{0}-{1}', variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')))]", "varWrklKvPrivateEndpointName": "[format('pe-{0}-vault', variables('varWrklKvName'))]", "varWrklKeyVaultSku": "[if(or(equals(variables('varAzureCloudName'), 'AzureCloud'), equals(variables('varAzureCloudName'), 'AzureUSGovernment')), 'premium', if(equals(variables('varAzureCloudName'), 'AzureChinaCloud'), 'standard', null()))]", - "varSessionHostNamePrefix": "[if(parameters('avdUseCustomNaming'), parameters('avdSessionHostCustomNamePrefix'), format('vm{0}{1}{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentComputeStorage'), variables('varSessionHostLocationAcronym')))]", + "varSessionHostNamePrefix": "[if(parameters('avdUseCustomNaming'), parameters('avdSessionHostCustomNamePrefix'), format('vm{0}{1}{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentOneCharacter'), variables('varSessionHostLocationAcronym')))]", "varStorageManagedIdentityName": "[format('id-storage-{0}-001', variables('varComputeStorageResourcesNamingStandard'))]", - "varFslogixFileShareName": "[if(parameters('avdUseCustomNaming'), parameters('fslogixFileShareCustomName'), format('fslogix-pc-{0}-{1}-{2}-001', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentLowercase'), variables('varSessionHostLocationAcronym')))]", - "varAppAttachFileShareName": "[if(parameters('avdUseCustomNaming'), parameters('appAttachFileShareCustomName'), format('appa-{0}-{1}-{2}-001', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentLowercase'), variables('varSessionHostLocationAcronym')))]", - "varFslogixStorageName": "[if(parameters('avdUseCustomNaming'), format('{0}fsl{1}{2}{3}', parameters('storageAccountPrefixCustomName'), variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentComputeStorage'), variables('varNamingUniqueStringThreeChar')), format('stfsl{0}{1}{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentComputeStorage'), variables('varNamingUniqueStringThreeChar')))]", - "varFslogixStorageFqdn": "[if(parameters('createAvdFslogixDeployment'), format('{0}.file.{1}', variables('varFslogixStorageName'), environment().suffixes.storage), '')]", - "varAppAttachStorageFqdn": "[format('{0}.file.{1}', variables('varAppAttachStorageName'), environment().suffixes.storage)]", - "varAppAttachStorageName": "[if(parameters('avdUseCustomNaming'), format('{0}appa{1}{2}{3}', parameters('storageAccountPrefixCustomName'), variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentComputeStorage'), variables('varNamingUniqueStringThreeChar')), format('stappa{0}{1}{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentComputeStorage'), variables('varNamingUniqueStringThreeChar')))]", - "varManagementVmName": "[format('vmmgmt{0}{1}{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentComputeStorage'), variables('varSessionHostLocationAcronym'))]", "varAlaWorkspaceName": "[if(parameters('avdUseCustomNaming'), parameters('avdAlaWorkspaceCustomName'), format('log-avd-{0}-{1}', variables('varDeploymentEnvironmentLowercase'), variables('varManagementPlaneLocationAcronym')))]", "varDataCollectionRulesName": "[format('microsoft-avdi-{0}', variables('varSessionHostLocationLowercase'))]", "varZtKvName": "[if(parameters('avdUseCustomNaming'), format('{0}-{1}-{2}', parameters('ztKvPrefixCustomName'), variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')), format('kv-key-{0}-{1}', variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')))]", "varZtKvPrivateEndpointName": "[format('pe-{0}-vault', variables('varZtKvName'))]", - "varFslogixSharePath": "[if(parameters('createAvdFslogixDeployment'), format('\\\\{0}.file.{1}\\{2}', variables('varFslogixStorageName'), environment().suffixes.storage, variables('varFslogixFileShareName')), '')]", - "varBaseScriptUri": "https://raw.githubusercontent.com/azure/avdaccelerator/main/workload/", + "varBaseScriptUri": "https://raw.githubusercontent.com/azure/avdaccelerator/anf-fslogix/workload/", "varSessionHostConfigurationScriptUri": "[format('{0}scripts/Set-SessionHostConfiguration.ps1', variables('varBaseScriptUri'))]", "varSessionHostConfigurationScript": "Set-SessionHostConfiguration.ps1", - "varCreateStorageDeployment": "[if(or(parameters('createAvdFslogixDeployment'), equals(variables('varCreateAppAttachDeployment'), true())), true(), false())]", - "varFslogixStorageSku": "[if(parameters('zoneRedundantStorage'), format('{0}_ZRS', parameters('fslogixStoragePerformance')), format('{0}_LRS', parameters('fslogixStoragePerformance')))]", - "varAppAttachStorageSku": "[if(parameters('zoneRedundantStorage'), format('{0}_ZRS', parameters('appAttachStoragePerformance')), format('{0}_LRS', parameters('appAttachStoragePerformance')))]", "varMaxSessionHostsPerTemplate": 10, "varMaxSessionHostsDivisionValue": "[div(parameters('avdDeploySessionHostsCount'), variables('varMaxSessionHostsPerTemplate'))]", "varMaxSessionHostsDivisionRemainderValue": "[mod(parameters('avdDeploySessionHostsCount'), variables('varMaxSessionHostsPerTemplate'))]", @@ -1707,13 +1673,6 @@ } } ], - "varMarketPlaceGalleryWindows": "[variables('$fxv#1')]", - "varStorageAzureFilesDscAgentPackageLocation": "https://github.com/Azure/avdaccelerator/raw/main/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip", - "varStorageToDomainScriptUri": "[format('{0}scripts/Manual-DSC-Storage-Scripts.ps1', variables('varBaseScriptUri'))]", - "varStorageToDomainScript": "./Manual-DSC-Storage-Scripts.ps1", - "varOuStgPath": "[if(not(empty(parameters('storageOuPath'))), format('\"{0}\"', parameters('storageOuPath')), format('\"{0}\"', variables('varDefaultStorageOuPath')))]", - "varDefaultStorageOuPath": "[if(equals(parameters('avdIdentityServiceProvider'), 'EntraDS'), 'AADDC Computers', 'Computers')]", - "varStorageCustomOuPath": "[if(not(empty(parameters('storageOuPath'))), 'true', 'false')]", "varAllDnsServers": "[format('{0},168.63.129.16', parameters('customDnsIps'))]", "varDnsServers": "[if(empty(parameters('customDnsIps')), createArray(), split(variables('varAllDnsServers'), ','))]", "varCreateVnetPeering": "[if(not(empty(parameters('existingHubVnetResourceId'))), true(), false())]", @@ -1750,7 +1709,8 @@ } ], "varSecurityPrincipalId": "[if(not(empty(parameters('avdSecurityGroups'))), parameters('avdSecurityGroups')[0].objectId, '')]", - "varSecurityPrincipalName": "[if(not(empty(parameters('avdSecurityGroups'))), parameters('avdSecurityGroups')[0].displayName, '')]" + "varSecurityPrincipalName": "[if(not(empty(parameters('avdSecurityGroups'))), parameters('avdSecurityGroups')[0].displayName, '')]", + "varCreateStorageDeployment": "[if(or(parameters('createFslogixDeployment'), parameters('createAppAttachDeployment')), true(), false())]" }, "resources": [ { @@ -1799,8 +1759,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "17832108042529526083" + "version": "0.34.44.8038", + "templateHash": "5574722192240323807" }, "name": "Resource Groups", "description": "This module deploys a Resource Group.", @@ -1928,8 +1888,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "17832108042529526083" + "version": "0.34.44.8038", + "templateHash": "5574722192240323807" }, "name": "Resource Groups", "description": "This module deploys a Resource Group.", @@ -2052,8 +2012,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "17832108042529526083" + "version": "0.34.44.8038", + "templateHash": "5574722192240323807" }, "name": "Resource Groups", "description": "This module deploys a Resource Group.", @@ -2172,7 +2132,7 @@ "dataCollectionRulesName": { "value": "[variables('varDataCollectionRulesName')]" }, - "storageObjectsRgName": "[if(or(parameters('createAvdFslogixDeployment'), parameters('createAppAttachDeployment')), createObject('value', variables('varStorageObjectsRgName')), createObject('value', ''))]", + "storageObjectsRgName": "[if(variables('varCreateStorageDeployment'), createObject('value', variables('varStorageObjectsRgName')), createObject('value', ''))]", "networkObjectsRgName": "[if(parameters('createAvdVnet'), createObject('value', variables('varNetworkObjectsRgName')), createObject('value', ''))]", "monitoringRgName": { "value": "[variables('varMonitoringRgName')]" @@ -2196,8 +2156,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "9075036806052194789" + "version": "0.34.44.8038", + "templateHash": "8859176354402895974" }, "name": "AVD LZA insights monitoring", "description": "This module deploys Log analytics workspace, DCR and policies", @@ -2334,8 +2294,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "17832108042529526083" + "version": "0.34.44.8038", + "templateHash": "5574722192240323807" }, "name": "Resource Groups", "description": "This module deploys a Resource Group.", @@ -2468,8 +2428,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "4856541365330529232" + "version": "0.34.44.8038", + "templateHash": "8971404674064738552" }, "name": "Log Analytics Workspaces", "description": "This module deploys a Log Analytics Workspace.", @@ -2701,8 +2661,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "17358515953093451973" + "version": "0.34.44.8038", + "templateHash": "4384156253703622371" }, "name": "Log Analytics Workspace Storage Insight Configs", "description": "This module deploys a Log Analytics Workspace Storage Insight Config.", @@ -2897,8 +2857,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "15722550007411230806" + "version": "0.34.44.8038", + "templateHash": "16349959440930876908" } }, "parameters": { @@ -3226,8 +3186,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "14608202935063519743" + "version": "0.34.44.8038", + "templateHash": "15296566503434303805" } }, "parameters": { @@ -3377,8 +3337,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "8832321830420649266" + "version": "0.34.44.8038", + "templateHash": "10756132163516015710" } }, "parameters": { @@ -3527,8 +3487,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "11624908005940613332" + "version": "0.34.44.8038", + "templateHash": "10386382608825992636" }, "name": "Policy Assignments (Resource Group scope)", "description": "This module deploys a Policy Assignment at a Resource Group scope.", @@ -3778,8 +3738,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "15388209522748095710" + "version": "0.34.44.8038", + "templateHash": "8141314117626850328" }, "name": "Policy Insights Remediations (Resource Group scope)", "description": "This module deploys a Policy Insights Remediation on a Resource Group scope.", @@ -3947,8 +3907,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "5179740017078291369" + "version": "0.34.44.8038", + "templateHash": "13560993199783159016" } }, "parameters": { @@ -4111,7 +4071,7 @@ ] }, { - "condition": "[or(or(or(or(parameters('createAvdVnet'), parameters('createPrivateDnsZones')), parameters('avdDeploySessionHosts')), parameters('createAvdFslogixDeployment')), variables('varCreateAppAttachDeployment'))]", + "condition": "[or(or(or(or(parameters('createAvdVnet'), parameters('createPrivateDnsZones')), parameters('avdDeploySessionHosts')), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('Networking-{0}', parameters('time'))]", @@ -4125,7 +4085,7 @@ "createVnet": { "value": "[parameters('createAvdVnet')]" }, - "deployAsg": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createAvdFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', true()), createObject('value', false()))]", + "deployAsg": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', true()), createObject('value', false()))]", "existingAvdSubnetResourceId": { "value": "[parameters('existingVnetAvdSubnetResourceId')]" }, @@ -4142,6 +4102,9 @@ "avdNetworksecurityGroupName": { "value": "[variables('varAvdNetworksecurityGroupName')]" }, + "anfNetworksecurityGroupName": { + "value": "[variables('varAnfNetworksecurityGroupName')]" + }, "privateEndpointNetworksecurityGroupName": { "value": "[variables('varPrivateEndpointNetworksecurityGroupName')]" }, @@ -4169,6 +4132,9 @@ "vnetPrivateEndpointSubnetName": { "value": "[variables('varVnetPrivateEndpointSubnetName')]" }, + "vnetAnfSubnetName": { + "value": "[variables('varVnetAnfSubnetName')]" + }, "createVnetPeering": { "value": "[variables('varCreateVnetPeering')]" }, @@ -4179,6 +4145,7 @@ "value": "[variables('varDDosProtectionPlanName')]" }, "deployPrivateEndpointSubnet": "[if(or(parameters('deployPrivateEndpointKeyvaultStorage'), parameters('deployAvdPrivateLinkService')), createObject('value', true()), createObject('value', false()))]", + "deployAnfSubnet": "[if(equals(parameters('storageService'), 'ANF'), createObject('value', true()), createObject('value', false()))]", "deployAvdPrivateLinkService": { "value": "[parameters('deployAvdPrivateLinkService')]" }, @@ -4195,6 +4162,9 @@ "vnetPrivateEndpointSubnetAddressPrefix": { "value": "[parameters('vNetworkPrivateEndpointSubnetAddressPrefix')]" }, + "vnetAnfSubnetAddressPrefix": { + "value": "[parameters('vNetworkAnfSubnetAddressPrefix')]" + }, "workloadSubsId": { "value": "[parameters('avdWorkloadSubsId')]" }, @@ -4213,8 +4183,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "2534323673630065360" + "version": "0.34.44.8038", + "templateHash": "9241376745009248833" }, "name": "AVD LZA networking", "description": "This module deploys vNet, NSG, ASG, UDR, private DNs zones", @@ -4276,6 +4246,12 @@ "description": "Private endpoint Network Security Group Name" } }, + "anfNetworksecurityGroupName": { + "type": "string", + "metadata": { + "description": "ANF Network Security Group Name" + } + }, "applicationSecurityGroupName": { "type": "string", "metadata": { @@ -4342,6 +4318,12 @@ "description": "Optional. AVD Accelerator will deploy with private endpoints by default." } }, + "deployAnfSubnet": { + "type": "bool", + "metadata": { + "description": "Deploy with ANf subnet." + } + }, "deployAvdPrivateLinkService": { "type": "bool", "metadata": { @@ -4366,6 +4348,12 @@ "description": "Private endpoint subnet Name." } }, + "vnetAnfSubnetName": { + "type": "string", + "metadata": { + "description": "ANF subnet Name." + } + }, "vnetAvdSubnetAddressPrefix": { "type": "string", "metadata": { @@ -4378,6 +4366,12 @@ "description": "Private endpoint VNet subnet address prefix." } }, + "vnetAnfSubnetAddressPrefix": { + "type": "string", + "metadata": { + "description": "ANF VNet subnet address prefix." + } + }, "dnsServers": { "type": "array", "metadata": { @@ -4626,8 +4620,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "13272826448432874347" + "version": "0.34.44.8038", + "templateHash": "9898059387129093740" }, "name": "Network Security Groups", "description": "This module deploys a Network security Group (NSG).", @@ -4918,8 +4912,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "15539562466007631331" + "version": "0.34.44.8038", + "templateHash": "714966927696814087" }, "name": "Network Security Group (NSG) Security Rules", "description": "This module deploys a Network Security Group (NSG) Security Rule.", @@ -5181,8 +5175,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "13272826448432874347" + "version": "0.34.44.8038", + "templateHash": "9898059387129093740" }, "name": "Network Security Groups", "description": "This module deploys a Network security Group (NSG).", @@ -5473,8 +5467,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "15539562466007631331" + "version": "0.34.44.8038", + "templateHash": "714966927696814087" }, "name": "Network Security Group (NSG) Security Rules", "description": "This module deploys a Network Security Group (NSG) Security Rule.", @@ -5701,12 +5695,12 @@ } }, { - "condition": "[parameters('deployAsg')]", + "condition": "[and(parameters('createVnet'), parameters('deployAnfSubnet'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('ASG-{0}', parameters('time'))]", + "name": "[format('NSG-ANF-{0}', parameters('time'))]", "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -5714,144 +5708,20 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('applicationSecurityGroupName')]" + "value": "[parameters('anfNetworksecurityGroupName')]" }, "location": { "value": "[parameters('location')]" }, "tags": { "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "10611195212449783096" - }, - "name": "Application Security Groups (ASG)", - "description": "This module deploys an Application Security Group (ASG).", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Application Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-applicationsecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "applicationSecurityGroup": { - "type": "Microsoft.Network/applicationSecurityGroups", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": {} - } + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the application security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the application security group." - }, - "value": "[resourceId('Microsoft.Network/applicationSecurityGroups', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the application security group." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('applicationSecurityGroup', '2023-04-01', 'full').location]" - } + "securityRules": { + "value": [] } - } - } - }, - { - "condition": "[parameters('createVnet')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Route-Table-AVD-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('avdRouteTableName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "routes": "[if(variables('varCreateAvdStaticRoute'), createObject('value', variables('varStaticRoutes')), createObject('value', createArray()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -5860,65 +5730,103 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "5932224160998080111" + "version": "0.34.44.8038", + "templateHash": "9898059387129093740" }, - "name": "Route Tables", - "description": "This module deploys a User Defined Route Table (UDR).", + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG).", "owner": "Azure/module-maintainers" }, "definitions": { - "routeType": { + "diagnosticSettingType": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Name of the route." + "description": "Optional. The name of diagnostic setting." } }, - "properties": { - "type": "object", - "properties": { - "nextHopType": { - "type": "string", - "allowedValues": [ - "Internet", - "None", - "VirtualAppliance", - "VirtualNetworkGateway", - "VnetLocal" - ], - "metadata": { - "description": "Required. The type of Azure hop the packet should be sent to." - } - }, - "addressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination CIDR to which the route applies." - } - }, - "hasBgpOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." - } - }, - "nextHopIpAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, + "nullable": true, "metadata": { - "description": "Required. Properties of the route." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } } @@ -5930,7 +5838,7 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name given for the hub route table." + "description": "Required. Name of the Network Security Group." } }, "location": { @@ -5940,24 +5848,31 @@ "description": "Optional. Location for all resources." } }, - "routes": { - "$ref": "#/definitions/routeType", + "securityRules": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. An array of routes to be established within the hub route table." + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." } }, - "disableBgpRoutePropagation": { + "flushConnection": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Switch to disable BGP route propagation." + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." } }, "tags": { "type": "object", "nullable": true, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. Tags of the NSG resource." } }, "enableTelemetry": { @@ -5973,7 +5888,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -5989,175 +5904,400 @@ } } }, - "routeTable": { - "type": "Microsoft.Network/routeTables", - "apiVersion": "2023-04-01", + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2023-11-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "properties": { - "routes": "[parameters('routes')]", - "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" + "copy": [ + { + "name": "securityRules", + "count": "[length(parameters('securityRules'))]", + "input": { + "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", + "properties": { + "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", + "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", + "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", + "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", + "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" + } + } + } + ], + "flushConnection": "[parameters('flushConnection')]" } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the route table was deployed into." - }, - "value": "[resourceGroup().name]" }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the route table." + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the route table." + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, - "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" + "dependsOn": [ + "networkSecurityGroup" + ] }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "networkSecurityGroup_securityRules": { + "copy": { + "name": "networkSecurityGroup_securityRules", + "count": "[length(parameters('securityRules'))]" }, - "value": "[reference('routeTable', '2023-04-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Route-Table-PE-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('privateEndpointRouteTableName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "routes": { - "value": [] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "5932224160998080111" - }, - "name": "Route Tables", - "description": "This module deploys a User Defined Route Table (UDR).", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "routeType": { - "type": "array", - "items": { - "type": "object", - "properties": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the route." - } + "value": "[parameters('securityRules')[copyIndex()].name]" }, - "properties": { - "type": "object", - "properties": { - "nextHopType": { - "type": "string", - "allowedValues": [ - "Internet", - "None", - "VirtualAppliance", - "VirtualNetworkGateway", - "VnetLocal" - ], - "metadata": { - "description": "Required. The type of Azure hop the packet should be sent to." - } - }, - "addressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination CIDR to which the route applies." - } + "networkSecurityGroupName": { + "value": "[parameters('name')]" + }, + "protocol": { + "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" + }, + "access": { + "value": "[parameters('securityRules')[copyIndex()].properties.access]" + }, + "priority": { + "value": "[parameters('securityRules')[copyIndex()].properties.priority]" + }, + "direction": { + "value": "[parameters('securityRules')[copyIndex()].properties.direction]" + }, + "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "714966927696814087" + }, + "name": "Network Security Group (NSG) Security Rules", + "description": "This module deploys a Network Security Group (NSG) Security Rule.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security rule." + } + }, + "networkSecurityGroupName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." + } + }, + "access": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. Whether network traffic is allowed or denied." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 140, + "metadata": { + "description": "Optional. A description for this rule." + } + }, + "destinationAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + } + }, + "destinationApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as destination." + } + }, + "destinationPortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "metadata": { + "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The source port ranges." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", + "properties": { + "access": "[parameters('access')]", + "description": "[parameters('description')]", + "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", + "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", + "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", + "destinationPortRange": "[parameters('destinationPortRange')]", + "destinationPortRanges": "[parameters('destinationPortRanges')]", + "direction": "[parameters('direction')]", + "priority": "[parameters('priority')]", + "protocol": "[parameters('protocol')]", + "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", + "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", + "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", + "sourcePortRange": "[parameters('sourcePortRange')]", + "sourcePortRanges": "[parameters('sourcePortRanges')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the security rule was deployed into." }, - "hasBgpOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." - } + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the security rule." }, - "nextHopIpAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." - } - } + "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" }, - "metadata": { - "description": "Required. Properties of the route." + "name": { + "type": "string", + "metadata": { + "description": "The name of the security rule." + }, + "value": "[parameters('name')]" } } } }, - "nullable": true + "dependsOn": [ + "networkSecurityGroup" + ] } }, - "parameters": { + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network security group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the network security group." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, "name": { "type": "string", "metadata": { - "description": "Required. Name given for the hub route table." - } + "description": "The name of the network security group." + }, + "value": "[parameters('name')]" }, "location": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." - } + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[parameters('deployAsg')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('ASG-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('applicationSecurityGroupName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "6399800135303615704" }, - "routes": { - "$ref": "#/definitions/routeType", + "name": "Application Security Groups (ASG)", + "description": "This module deploys an Application Security Group (ASG).", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", "metadata": { - "description": "Optional. An array of routes to be established within the hub route table." + "description": "Required. Name of the Application Security Group." } }, - "disableBgpRoutePropagation": { - "type": "bool", - "defaultValue": false, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Switch to disable BGP route propagation." + "description": "Optional. Location for all resources." } }, "tags": { @@ -6180,7 +6320,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "name": "[format('46d3xbcp.res.network-applicationsecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -6196,56 +6336,53 @@ } } }, - "routeTable": { - "type": "Microsoft.Network/routeTables", + "applicationSecurityGroup": { + "type": "Microsoft.Network/applicationSecurityGroups", "apiVersion": "2023-04-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "properties": { - "routes": "[parameters('routes')]", - "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" - } + "properties": {} } }, "outputs": { "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the route table was deployed into." + "description": "The resource group the application security group was deployed into." }, "value": "[resourceGroup().name]" }, - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the route table." + "description": "The resource ID of the application security group." }, - "value": "[parameters('name')]" + "value": "[resourceId('Microsoft.Network/applicationSecurityGroups', parameters('name'))]" }, - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the route table." + "description": "The name of the application security group." }, - "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" + "value": "[parameters('name')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('routeTable', '2023-04-01', 'full').location]" + "value": "[reference('applicationSecurityGroup', '2023-04-01', 'full').location]" } } } } }, { - "condition": "[parameters('deployDDoSNetworkProtection')]", + "condition": "[parameters('createVnet')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('DDoS-Protection-Plan-{0}', parameters('time'))]", + "name": "[format('Route-Table-AVD-{0}', parameters('time'))]", "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", "properties": { @@ -6255,11 +6392,15 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('ddosProtectionPlanName')]" + "value": "[parameters('avdRouteTableName')]" }, "location": { "value": "[parameters('location')]" - } + }, + "tags": { + "value": "[parameters('tags')]" + }, + "routes": "[if(variables('varCreateAvdStaticRoute'), createObject('value', variables('varStaticRoutes')), createObject('value', createArray()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -6268,19 +6409,77 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "16370594914247543667" + "version": "0.34.44.8038", + "templateHash": "17894283484101609343" }, - "name": "DDoS Protection Plans", - "description": "This module deploys a DDoS Protection Plan.", + "name": "Route Tables", + "description": "This module deploys a User Defined Route Table (UDR).", "owner": "Azure/module-maintainers" }, + "definitions": { + "routeType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the route." + } + }, + "properties": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "None", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The type of Azure hop the packet should be sent to." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination CIDR to which the route applies." + } + }, + "hasBgpOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." + } + }, + "nextHopIpAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "description": "Required. Properties of the route." + } + } + } + }, + "nullable": true + } + }, "parameters": { "name": { "type": "string", - "minLength": 1, "metadata": { - "description": "Required. Name of the DDoS protection plan to assign the VNET to." + "description": "Required. Name given for the hub route table." } }, "location": { @@ -6290,6 +6489,19 @@ "description": "Optional. Location for all resources." } }, + "routes": { + "$ref": "#/definitions/routeType", + "metadata": { + "description": "Optional. An array of routes to be established within the hub route table." + } + }, + "disableBgpRoutePropagation": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Switch to disable BGP route propagation." + } + }, "tags": { "type": "object", "nullable": true, @@ -6310,7 +6522,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-ddosprotectionplan.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", "properties": { "mode": "Incremental", "template": { @@ -6326,53 +6538,56 @@ } } }, - "ddosProtectionPlan": { - "type": "Microsoft.Network/ddosProtectionPlans", - "apiVersion": "2023-11-01", + "routeTable": { + "type": "Microsoft.Network/routeTables", + "apiVersion": "2023-04-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "properties": {} + "properties": { + "routes": "[parameters('routes')]", + "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" + } } }, "outputs": { "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the DDOS protection plan was deployed into." + "description": "The resource group the route table was deployed into." }, "value": "[resourceGroup().name]" }, - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the DDOS protection plan." + "description": "The name of the route table." }, - "value": "[resourceId('Microsoft.Network/ddosProtectionPlans', parameters('name'))]" + "value": "[parameters('name')]" }, - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the DDOS protection plan." + "description": "The resource ID of the route table." }, - "value": "[parameters('name')]" + "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('ddosProtectionPlan', '2023-11-01', 'full').location]" + "value": "[reference('routeTable', '2023-04-01', 'full').location]" } } } } }, { - "condition": "[parameters('createVnet')]", + "condition": "[and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('vNet-{0}', parameters('time'))]", + "name": "[format('Route-Table-PE-{0}', parameters('time'))]", "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", "properties": { @@ -6382,25 +6597,16 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('vnetName')]" + "value": "[parameters('privateEndpointRouteTableName')]" }, "location": { "value": "[parameters('location')]" }, - "addressPrefixes": { - "value": "[array(parameters('vnetAddressPrefixes'))]" - }, - "dnsServers": { - "value": "[parameters('dnsServers')]" - }, - "peerings": "[if(parameters('createVnetPeering'), createObject('value', createArray(createObject('remoteVirtualNetworkId', parameters('existingHubVnetResourceId'), 'name', parameters('vnetPeeringName'), 'allowForwardedTraffic', true(), 'allowGatewayTransit', false(), 'allowVirtualNetworkAccess', true(), 'doNotVerifyRemoteGateways', true(), 'useRemoteGateways', if(parameters('vNetworkGatewayOnHub'), true(), false()), 'remotePeeringEnabled', true(), 'remotePeeringName', parameters('remoteVnetPeeringName'), 'remotePeeringAllowForwardedTraffic', true(), 'remotePeeringAllowGatewayTransit', if(parameters('vNetworkGatewayOnHub'), true(), false()), 'remotePeeringAllowVirtualNetworkAccess', true(), 'remotePeeringDoNotVerifyRemoteGateways', true(), 'remotePeeringUseRemoteGateways', false()))), createObject('value', createArray()))]", - "subnets": "[if(parameters('deployPrivateEndpointSubnet'), createObject('value', createArray(createObject('name', parameters('vnetAvdSubnetName'), 'addressPrefix', parameters('vnetAvdSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')), createObject('name', parameters('vnetPrivateEndpointSubnetName'), 'addressPrefix', parameters('vnetPrivateEndpointSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-Private-Endpoint-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-PE-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')))), createObject('value', createArray(createObject('name', parameters('vnetAvdSubnetName'), 'addressPrefix', parameters('vnetAvdSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage', 'locations', createArray(format('{0}', parameters('location')))), createObject('service', 'Microsoft.KeyVault', 'locations', createArray(format('{0}', parameters('location')))))))))]", - "ddosProtectionPlanResourceId": "[if(parameters('deployDDoSNetworkProtection'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('DDoS-Protection-Plan-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', ''))]", "tags": { "value": "[parameters('tags')]" }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" + "routes": { + "value": [] } }, "template": { @@ -6410,32 +6616,377 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "4245282512442607785" + "version": "0.34.44.8038", + "templateHash": "17894283484101609343" }, - "name": "Virtual Networks", - "description": "This module deploys a Virtual Network (vNet).", + "name": "Route Tables", + "description": "This module deploys a User Defined Route Table (UDR).", "owner": "Azure/module-maintainers" }, "definitions": { - "diagnosticSettingType": { + "routeType": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of diagnostic setting." + "description": "Required. Name of the route." } }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { + "properties": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "None", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The type of Azure hop the packet should be sent to." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination CIDR to which the route applies." + } + }, + "hasBgpOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." + } + }, + "nextHopIpAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "description": "Required. Properties of the route." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name given for the hub route table." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "routes": { + "$ref": "#/definitions/routeType", + "metadata": { + "description": "Optional. An array of routes to be established within the hub route table." + } + }, + "disableBgpRoutePropagation": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Switch to disable BGP route propagation." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "routeTable": { + "type": "Microsoft.Network/routeTables", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "routes": "[parameters('routes')]", + "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the route table was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the route table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the route table." + }, + "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('routeTable', '2023-04-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[parameters('deployDDoSNetworkProtection')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('DDoS-Protection-Plan-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('ddosProtectionPlanName')]" + }, + "location": { + "value": "[parameters('location')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "6678083091788427255" + }, + "name": "DDoS Protection Plans", + "description": "This module deploys a DDoS Protection Plan.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the DDoS protection plan to assign the VNET to." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-ddosprotectionplan.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "ddosProtectionPlan": { + "type": "Microsoft.Network/ddosProtectionPlans", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the DDOS protection plan was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the DDOS protection plan." + }, + "value": "[resourceId('Microsoft.Network/ddosProtectionPlans', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the DDOS protection plan." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('ddosProtectionPlan', '2023-11-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[parameters('createVnet')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('vNet-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('vnetName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "addressPrefixes": { + "value": "[array(parameters('vnetAddressPrefixes'))]" + }, + "dnsServers": { + "value": "[parameters('dnsServers')]" + }, + "peerings": "[if(parameters('createVnetPeering'), createObject('value', createArray(createObject('remoteVirtualNetworkId', parameters('existingHubVnetResourceId'), 'name', parameters('vnetPeeringName'), 'allowForwardedTraffic', true(), 'allowGatewayTransit', false(), 'allowVirtualNetworkAccess', true(), 'doNotVerifyRemoteGateways', true(), 'useRemoteGateways', if(parameters('vNetworkGatewayOnHub'), true(), false()), 'remotePeeringEnabled', true(), 'remotePeeringName', parameters('remoteVnetPeeringName'), 'remotePeeringAllowForwardedTraffic', true(), 'remotePeeringAllowGatewayTransit', if(parameters('vNetworkGatewayOnHub'), true(), false()), 'remotePeeringAllowVirtualNetworkAccess', true(), 'remotePeeringDoNotVerifyRemoteGateways', true(), 'remotePeeringUseRemoteGateways', false()))), createObject('value', createArray()))]", + "subnets": { + "value": "[union(if(parameters('deployPrivateEndpointSubnet'), createArray(createObject('name', parameters('vnetAvdSubnetName'), 'addressPrefix', parameters('vnetAvdSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''))), createArray(createObject('name', parameters('vnetAvdSubnetName'), 'addressPrefix', parameters('vnetAvdSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage', 'locations', createArray(format('{0}', parameters('location')))), createObject('service', 'Microsoft.KeyVault', 'locations', createArray(format('{0}', parameters('location')))))))), if(parameters('deployAnfSubnet'), createArray(createObject('name', parameters('vnetAnfSubnetName'), 'addressPrefix', parameters('vnetAnfSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(and(parameters('createVnet'), parameters('deployAnfSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-ANF-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'delegations', createArray(createObject('name', 'delegation', 'properties', createObject('serviceName', 'Microsoft.NetApp/volumes'))))), createArray()), if(parameters('deployPrivateEndpointSubnet'), createArray(createObject('name', parameters('vnetPrivateEndpointSubnetName'), 'addressPrefix', parameters('vnetPrivateEndpointSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-Private-Endpoint-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-PE-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''))), createArray()))]" + }, + "ddosProtectionPlanResourceId": "[if(parameters('deployDDoSNetworkProtection'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('DDoS-Protection-Plan-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', ''))]", + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "18267772730058349233" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { "type": "string", "nullable": true, "metadata": { @@ -6781,8 +7332,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "16191373076114856248" + "version": "0.34.44.8038", + "templateHash": "16351454463417912386" }, "name": "Virtual Network Subnets", "description": "This module deploys a Virtual Network Subnet.", @@ -7104,8 +7655,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "16105287874291442618" + "version": "0.34.44.8038", + "templateHash": "15212353974601574751" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -7249,8 +7800,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "16105287874291442618" + "version": "0.34.44.8038", + "templateHash": "15212353974601574751" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -7413,6 +7964,7 @@ }, "dependsOn": [ "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('DDoS-Protection-Plan-{0}', parameters('time')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-ANF-{0}', parameters('time')))]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time')))]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-Private-Endpoint-{0}', parameters('time')))]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time')))]", @@ -7447,8 +7999,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6927397674460939464" + "version": "0.34.44.8038", + "templateHash": "9826379828964980786" }, "name": "Private DNS Zones", "description": "This module deploys a Private DNS zone.", @@ -7558,8 +8110,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "7935296883010131007" + "version": "0.34.44.8038", + "templateHash": "4846633428140292997" }, "name": "Private DNS Zone Virtual Network Link", "description": "This module deploys a Private DNS Zone Virtual Network Link.", @@ -7729,8 +8281,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6927397674460939464" + "version": "0.34.44.8038", + "templateHash": "9826379828964980786" }, "name": "Private DNS Zones", "description": "This module deploys a Private DNS zone.", @@ -7840,8 +8392,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "7935296883010131007" + "version": "0.34.44.8038", + "templateHash": "4846633428140292997" }, "name": "Private DNS Zone Virtual Network Link", "description": "This module deploys a Private DNS Zone Virtual Network Link.", @@ -8011,8 +8563,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6927397674460939464" + "version": "0.34.44.8038", + "templateHash": "9826379828964980786" }, "name": "Private DNS Zones", "description": "This module deploys a Private DNS zone.", @@ -8122,8 +8674,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "7935296883010131007" + "version": "0.34.44.8038", + "templateHash": "4846633428140292997" }, "name": "Private DNS Zone Virtual Network Link", "description": "This module deploys a Private DNS Zone Virtual Network Link.", @@ -8293,8 +8845,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6927397674460939464" + "version": "0.34.44.8038", + "templateHash": "9826379828964980786" }, "name": "Private DNS Zones", "description": "This module deploys a Private DNS zone.", @@ -8404,8 +8956,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "7935296883010131007" + "version": "0.34.44.8038", + "templateHash": "4846633428140292997" }, "name": "Private DNS Zone Virtual Network Link", "description": "This module deploys a Private DNS Zone Virtual Network Link.", @@ -8693,8 +9245,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "7089616774495447601" + "version": "0.34.44.8038", + "templateHash": "4866343470162672721" }, "name": "AVD LZA management plane", "description": "This module deploys AVD workspace, host pool, application group scaling plan", @@ -9039,8 +9591,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "4797298004221587284" + "version": "0.34.44.8038", + "templateHash": "17896773356115754728" }, "name": "Azure Virtual Desktop Host Pool", "description": "This module deploys an Azure Virtual Desktop Host Pool", @@ -9650,8 +10202,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "17400304622639006546" + "version": "0.34.44.8038", + "templateHash": "12190317675030946449" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -10621,8 +11173,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "11120131172578458858" + "version": "0.34.44.8038", + "templateHash": "4794696781017607017" }, "name": "Azure Virtual Desktop Application Group", "description": "This module deploys an Azure Virtual Desktop Application Group.", @@ -11041,8 +11593,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "3961073075950222669" + "version": "0.34.44.8038", + "templateHash": "11724144502531514491" }, "name": "Azure Virtual Desktop Application Group Application", "description": "This module deploys an Azure Virtual Desktop Application Group Application.", @@ -11246,8 +11798,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "4385633039380296561" + "version": "0.34.44.8038", + "templateHash": "16965361488789112059" }, "name": "Workspace", "description": "This module deploys an Azure Virtual Desktop Workspace.", @@ -12380,8 +12932,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "3580382825984694060" + "version": "0.34.44.8038", + "templateHash": "13077254828568021707" }, "name": "Azure Virtual Desktop Scaling Plan", "description": "This module deploys an Azure Virtual Desktop Scaling Plan.", @@ -12784,8 +13336,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "7503246006456144251" + "version": "0.34.44.8038", + "templateHash": "16449043338553652850" } }, "parameters": { @@ -12968,8 +13520,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "4949725037835210878" + "version": "0.34.44.8038", + "templateHash": "11657260805865946801" }, "name": "User Assigned Identities", "description": "This module deploys a User Assigned Identity.", @@ -13223,8 +13775,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "2452193429452217414" + "version": "0.34.44.8038", + "templateHash": "298383569508499170" }, "name": "Role Assignments (Resource Group scope)", "description": "This module deploys a Role Assignment at a Resource Group scope.", @@ -13401,8 +13953,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "2452193429452217414" + "version": "0.34.44.8038", + "templateHash": "298383569508499170" }, "name": "Role Assignments (Resource Group scope)", "description": "This module deploys a Role Assignment at a Resource Group scope.", @@ -13577,8 +14129,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "2452193429452217414" + "version": "0.34.44.8038", + "templateHash": "298383569508499170" }, "name": "Role Assignments (Resource Group scope)", "description": "This module deploys a Role Assignment at a Resource Group scope.", @@ -13752,8 +14304,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "2452193429452217414" + "version": "0.34.44.8038", + "templateHash": "298383569508499170" }, "name": "Role Assignments (Resource Group scope)", "description": "This module deploys a Role Assignment at a Resource Group scope.", @@ -13930,8 +14482,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "2452193429452217414" + "version": "0.34.44.8038", + "templateHash": "298383569508499170" }, "name": "Role Assignments (Resource Group scope)", "description": "This module deploys a Role Assignment at a Resource Group scope.", @@ -14102,8 +14654,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "2452193429452217414" + "version": "0.34.44.8038", + "templateHash": "298383569508499170" }, "name": "Role Assignments (Resource Group scope)", "description": "This module deploys a Role Assignment at a Resource Group scope.", @@ -14274,8 +14826,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "2452193429452217414" + "version": "0.34.44.8038", + "templateHash": "298383569508499170" }, "name": "Role Assignments (Resource Group scope)", "description": "This module deploys a Role Assignment at a Resource Group scope.", @@ -14494,8 +15046,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "10869016739980645147" + "version": "0.34.44.8038", + "templateHash": "7927730494789166511" } }, "parameters": { @@ -14659,8 +15211,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "14608202935063519743" + "version": "0.34.44.8038", + "templateHash": "15296566503434303805" } }, "parameters": { @@ -14819,8 +15371,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "11624908005940613332" + "version": "0.34.44.8038", + "templateHash": "10386382608825992636" }, "name": "Policy Assignments (Resource Group scope)", "description": "This module deploys a Policy Assignment at a Resource Group scope.", @@ -15071,8 +15623,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "15388209522748095710" + "version": "0.34.44.8038", + "templateHash": "8141314117626850328" }, "name": "Policy Insights Remediations (Resource Group scope)", "description": "This module deploys a Policy Insights Remediation on a Resource Group scope.", @@ -15260,8 +15812,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "11624908005940613332" + "version": "0.34.44.8038", + "templateHash": "10386382608825992636" }, "name": "Policy Assignments (Resource Group scope)", "description": "This module deploys a Policy Assignment at a Resource Group scope.", @@ -15513,8 +16065,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "15388209522748095710" + "version": "0.34.44.8038", + "templateHash": "8141314117626850328" }, "name": "Policy Insights Remediations (Resource Group scope)", "description": "This module deploys a Policy Insights Remediation on a Resource Group scope.", @@ -15678,8 +16230,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "2452193429452217414" + "version": "0.34.44.8038", + "templateHash": "298383569508499170" }, "name": "Role Assignments (Resource Group scope)", "description": "This module deploys a Role Assignment at a Resource Group scope.", @@ -15852,8 +16404,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "2452193429452217414" + "version": "0.34.44.8038", + "templateHash": "298383569508499170" }, "name": "Role Assignments (Resource Group scope)", "description": "This module deploys a Role Assignment at a Resource Group scope.", @@ -16022,8 +16574,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "2452193429452217414" + "version": "0.34.44.8038", + "templateHash": "298383569508499170" }, "name": "Role Assignments (Resource Group scope)", "description": "This module deploys a Role Assignment at a Resource Group scope.", @@ -16223,8 +16775,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "5052089415637685759" + "version": "0.34.44.8038", + "templateHash": "7847524294349175140" } }, "parameters": { @@ -16369,8 +16921,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "16238346170268272034" + "version": "0.34.44.8038", + "templateHash": "14297043571004129093" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -17553,8 +18105,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "673206505709710643" + "version": "0.34.44.8038", + "templateHash": "17696169708082133914" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -17819,8 +18371,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "17400304622639006546" + "version": "0.34.44.8038", + "templateHash": "12190317675030946449" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -18100,8 +18652,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "15753887201917524746" + "version": "0.34.44.8038", + "templateHash": "1370782359529624908" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", @@ -19145,8 +19697,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "15753887201917524746" + "version": "0.34.44.8038", + "templateHash": "1370782359529624908" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", @@ -19467,8 +20019,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "18223652687669431134" + "version": "0.34.44.8038", + "templateHash": "15993472351338005036" }, "name": "Disk Encryption Sets", "description": "This module deploys a Disk Encryption Set. The module will attempt to set permissions on the provided Key Vault for any used user-assigned identity.", @@ -19694,8 +20246,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "10714750736508729314" + "version": "0.34.44.8038", + "templateHash": "12732011659166716786" } }, "parameters": { @@ -19782,8 +20334,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "13289997093207697331" + "version": "0.34.44.8038", + "templateHash": "8247309965052145251" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -20132,8 +20684,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "16238346170268272034" + "version": "0.34.44.8038", + "templateHash": "14297043571004129093" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -21316,8 +21868,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "673206505709710643" + "version": "0.34.44.8038", + "templateHash": "17696169708082133914" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -21582,8 +22134,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "17400304622639006546" + "version": "0.34.44.8038", + "templateHash": "12190317675030946449" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -21863,8 +22415,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "15753887201917524746" + "version": "0.34.44.8038", + "templateHash": "1370782359529624908" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", @@ -22850,10 +23402,11 @@ ] }, { - "condition": "[and(not(equals(parameters('avdIdentityServiceProvider'), 'EntraID')), or(parameters('createAvdFslogixDeployment'), variables('varCreateAppAttachDeployment')))]", + "condition": "[variables('varCreateStorageDeployment')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('Storage-MGMT-VM-{0}', parameters('time'))]", + "name": "[format('SMB-Storage-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('avdWorkloadSubsId'))]", "location": "[deployment().location]", "properties": { "expressionEvaluationOptions": { @@ -22861,44 +23414,64 @@ }, "mode": "Incremental", "parameters": { - "diskEncryptionSetResourceId": "[if(parameters('diskZeroTrust'), createObject('value', reference(subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time'))), '2022-09-01').outputs.ztDiskEncryptionSetResourceId.value), createObject('value', ''))]", - "identityServiceProvider": { - "value": "[parameters('avdIdentityServiceProvider')]" + "deploymentPrefix": { + "value": "[variables('varDeploymentPrefixLowercase')]" }, - "managementVmName": { - "value": "[variables('varManagementVmName')]" + "deploymentEnvironment": { + "value": "[variables('varDeploymentEnvironmentLowercase')]" }, - "computeTimeZone": { - "value": "[variables('varTimeZoneSessionHosts')]" + "storageService": { + "value": "[parameters('storageService')]" + }, + "useCustomNaming": { + "value": "[parameters('avdUseCustomNaming')]" + }, + "storageAvailabilityZones": { + "value": "[parameters('zoneRedundantStorage')]" }, - "applicationSecurityGroupResourceId": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createAvdFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', format('{0}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.applicationSecurityGroupResourceId.value)), createObject('value', ''))]", "domainJoinUserName": { "value": "[parameters('avdDomainJoinUserName')]" }, - "wrklKvName": { - "value": "[variables('varWrklKvName')]" + "vmLocalUserName": { + "value": "[parameters('avdVmLocalUserName')]" }, - "serviceObjectsRgName": { - "value": "[variables('varServiceObjectsRgName')]" + "identityServiceProvider": { + "value": "[parameters('avdIdentityServiceProvider')]" + }, + "avdSessionHostsOuPath": { + "value": "[parameters('avdOuPath')]" + }, + "storageOuPath": { + "value": "[parameters('storageOuPath')]" + }, + "managementVmSize": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostsSize')), createObject('value', 'Standard_D2ads_v5'))]", + "createResourceTags": { + "value": "[parameters('createResourceTags')]" + }, + "deployPrivateEndpointKeyvaultStorage": { + "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" + }, + "dnsServers": { + "value": "[parameters('customDnsIps')]" }, "identityDomainName": { "value": "[parameters('identityDomainName')]" }, - "ouPath": { - "value": "[createObject('osImage', variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')], 'osDiskType', 'Standard_LRS', 'mgmtVmSize', parameters('avdSessionHostsSize'), 'enableAcceleratedNetworking', false(), 'ouPath', parameters('avdOuPath'), 'subnetId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId'))).ouPath]" + "storageObjectsRgName": { + "value": "[variables('varStorageObjectsRgName')]" }, - "osDiskType": { - "value": "[createObject('osImage', variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')], 'osDiskType', 'Standard_LRS', 'mgmtVmSize', parameters('avdSessionHostsSize'), 'enableAcceleratedNetworking', false(), 'ouPath', parameters('avdOuPath'), 'subnetId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId'))).osDiskType]" + "baseScriptUri": { + "value": "[variables('varBaseScriptUri')]" }, - "location": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostLocation')), createObject('value', parameters('avdManagementPlaneLocation')))]", - "mgmtVmSize": { - "value": "[createObject('osImage', variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')], 'osDiskType', 'Standard_LRS', 'mgmtVmSize', parameters('avdSessionHostsSize'), 'enableAcceleratedNetworking', false(), 'ouPath', parameters('avdOuPath'), 'subnetId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId'))).mgmtVmSize]" + "securityPrincipalName": { + "value": "[variables('varSecurityPrincipalName')]" }, - "subnetId": { - "value": "[createObject('osImage', variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')], 'osDiskType', 'Standard_LRS', 'mgmtVmSize', parameters('avdSessionHostsSize'), 'enableAcceleratedNetworking', false(), 'ouPath', parameters('avdOuPath'), 'subnetId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId'))).subnetId]" + "diskEncryptionSetResourceId": "[if(parameters('diskZeroTrust'), createObject('value', reference(subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time'))), '2022-09-01').outputs.ztDiskEncryptionSetResourceId.value), createObject('value', ''))]", + "sessionHostTimeZone": { + "value": "[variables('varTimeZoneSessionHosts')]" }, - "enableAcceleratedNetworking": { - "value": "[createObject('osImage', variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')], 'osDiskType', 'Standard_LRS', 'mgmtVmSize', parameters('avdSessionHostsSize'), 'enableAcceleratedNetworking', false(), 'ouPath', parameters('avdOuPath'), 'subnetId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId'))).enableAcceleratedNetworking]" + "createFslogixDeployment": { + "value": "[parameters('createFslogixDeployment')]" }, "securityType": "[if(equals(parameters('securityType'), 'Standard'), createObject('value', ''), createObject('value', parameters('securityType')))]", "secureBootEnabled": { @@ -22907,20 +23480,70 @@ "vTpmEnabled": { "value": "[parameters('vTpmEnabled')]" }, - "vmLocalUserName": { - "value": "[parameters('avdVmLocalUserName')]" - }, - "workloadSubsId": { - "value": "[parameters('avdWorkloadSubsId')]" - }, "encryptionAtHost": { "value": "[parameters('diskZeroTrust')]" }, "storageManagedIdentityResourceId": "[if(and(variables('varCreateStorageDeployment'), not(equals(parameters('avdIdentityServiceProvider'), 'EntraID'))), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time'))), '2022-09-01').outputs.managedIdentityStorageResourceId.value), createObject('value', ''))]", - "osImage": { - "value": "[createObject('osImage', variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')], 'osDiskType', 'Standard_LRS', 'mgmtVmSize', parameters('avdSessionHostsSize'), 'enableAcceleratedNetworking', false(), 'ouPath', parameters('avdOuPath'), 'subnetId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId'))).osImage]" + "applicationSecurityGroupResourceId": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', format('{0}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.applicationSecurityGroupResourceId.value)), createObject('value', ''))]", + "createAppAttachDeployment": { + "value": "[parameters('createAppAttachDeployment')]" }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]" + "fslogixFileShareCustomName": { + "value": "[parameters('fslogixFileShareCustomName')]" + }, + "appAttachFileShareCustomName": { + "value": "[parameters('appAttachFileShareCustomName')]" + }, + "storageAccountPrefixCustomName": { + "value": "[parameters('storageAccountPrefixCustomName')]" + }, + "anfAccountCustomName": { + "value": "[parameters('anfAccountCustomName')]" + }, + "managedIdentityClientId": "[if(and(variables('varCreateStorageDeployment'), not(equals(parameters('avdIdentityServiceProvider'), 'EntraID'))), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time'))), '2022-09-01').outputs.managedIdentityStorageClientId.value), createObject('value', ''))]", + "privateDnsZoneFilesResourceId": "[if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.azureFilesDnsZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneFilesId')))]", + "serviceObjectsRgName": { + "value": "[variables('varServiceObjectsRgName')]" + }, + "alaWorkspaceResourceId": "[if(parameters('avdDeployMonitoring'), if(parameters('deployAlaWorkspace'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.avdAlaWorkspaceResourceId.value), createObject('value', parameters('alaExistingWorkspaceResourceId'))), createObject('value', ''))]", + "deploymentEnvironmentOneCharacter": { + "value": "[variables('varDeploymentEnvironmentOneCharacter')]" + }, + "computeStorageResourcesNamingStandard": { + "value": "[variables('varComputeStorageResourcesNamingStandard')]" + }, + "fslogixFileShareQuotaSize": { + "value": "[parameters('fslogixFileShareQuotaSize')]" + }, + "appAttachFileShareQuotaSize": { + "value": "[parameters('appAttachFileShareQuotaSize')]" + }, + "fslogixStoragePerformance": { + "value": "[parameters('fslogixStoragePerformance')]" + }, + "appAttachStoragePerformance": { + "value": "[parameters('appAttachStoragePerformance')]" + }, + "anfSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAnfSubnetName'))), createObject('value', parameters('existingVnetAnfSubnetResourceId')))]", + "vmsSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", + "privateEndpointSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", + "location": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostLocation')), createObject('value', parameters('avdManagementPlaneLocation')))]", + "locationAcronym": "[if(parameters('avdDeploySessionHosts'), createObject('value', variables('varSessionHostLocationAcronym')), createObject('value', parameters('avdManagementPlaneLocation')))]", + "managementVmOsImage": { + "value": "[parameters('managementVmOsImage')]" + }, + "keyVaultResourceId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" + }, + "customResourceTags": { + "value": "[variables('varCustomResourceTags')]" + }, + "defaultTags": { + "value": "[variables('varAvdDefaultTags')]" + }, + "identityDomainGuid": { + "value": "[parameters('identityDomainGuid')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", @@ -22928,207 +23551,506 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "13073563750586099024" + "version": "0.34.44.8038", + "templateHash": "17332805804383803852" } }, "parameters": { - "diskEncryptionSetResourceId": { + "subId": { "type": "string", + "defaultValue": "[subscription().subscriptionId]", "metadata": { - "description": "AVD disk encryption set resource ID to enable server side encyption." + "description": "The subscription ID for the AVD workload." } }, - "workloadSubsId": { + "deploymentPrefix": { "type": "string", "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." + "description": "The deployment prefix in lowercase." } }, - "computeTimeZone": { + "deploymentEnvironment": { "type": "string", "metadata": { - "description": "Virtual machine time zone." + "description": "The deployment environment in lowercase." } }, - "identityServiceProvider": { + "location": { "type": "string", "metadata": { - "description": "Required, The service providing domain services for Azure Virtual Desktop." + "description": "The session host location acronym derived from the resource group location." } }, - "serviceObjectsRgName": { + "locationAcronym": { "type": "string", "metadata": { - "description": "Resource Group Name for Azure Files." + "description": "The session host or AVD management plane location acronym For example, \"eus\" for East US." } }, - "subnetId": { + "storageService": { "type": "string", "metadata": { - "description": "AVD subnet ID." + "description": "The storage service to use (AzureFiles or ANF)." } }, - "enableAcceleratedNetworking": { + "useCustomNaming": { "type": "bool", "metadata": { - "description": "Enable accelerated networking on the session host VMs." + "description": "Indicates whether to use custom naming for AVD." + } + }, + "computeStorageResourcesNamingStandard": { + "type": "string", + "metadata": { + "description": "The naming standard for compute storage resources coming from the main template." + } + }, + "fslogixFileShareCustomName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The custom name for the FSLogix file share." + } + }, + "appAttachFileShareCustomName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The custom name for the App Attach file share." + } + }, + "managementVmOsImage": { + "type": "string", + "metadata": { + "description": "The OS image for the management VM." + } + }, + "storageAccountPrefixCustomName": { + "type": "string", + "defaultValue": "st", + "metadata": { + "description": "AVD FSLogix and App Attach storage account prefix custom name." + } + }, + "anfAccountCustomName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The custom name for the ANF account." + } + }, + "deploymentEnvironmentOneCharacter": { + "type": "string", + "metadata": { + "description": "Deployment prefix one character." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Key Vault." + } + }, + "alaWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "The Azure Log Analytics workspace resource ID." + } + }, + "privateDnsZoneFilesResourceId": { + "type": "string", + "metadata": { + "description": "The private DNS zone files resource ID." + } + }, + "managedIdentityClientId": { + "type": "string", + "metadata": { + "description": "The client ID of the managed identity." + } + }, + "fslogixFileShareQuotaSize": { + "type": "int", + "metadata": { + "description": "The FSLogix file share quota size in GiBs." + } + }, + "appAttachFileShareQuotaSize": { + "type": "int", + "metadata": { + "description": "The App Attach file share quota size in GiBs." + } + }, + "fslogixStoragePerformance": { + "type": "string", + "metadata": { + "description": "The storage performance level for FSLogix." + } + }, + "appAttachStoragePerformance": { + "type": "string", + "metadata": { + "description": "The storage performance level for App Attach." + } + }, + "anfSubnetResourceId": { + "type": "string", + "metadata": { + "description": "Subnet resource ID for ANF volumes." + } + }, + "vmsSubnetResourceId": { + "type": "string", + "metadata": { + "description": "Subnet resource ID for VMs." } }, "securityType": { "type": "string", "metadata": { - "description": "Specifies the securityType of the virtual machine. Must be TrustedLaunch or ConfidentialVM enable UefiSettings." + "description": "The security type for the VM (e.g., TrustedLaunch, Standard)." + } + }, + "privateEndpointSubnetResourceId": { + "type": "string", + "metadata": { + "description": "Subnet resource ID for private endpoints." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the disk encryption set." + } + }, + "encryptionAtHost": { + "type": "bool", + "metadata": { + "description": "Indicates whether encryption at host is enabled for the VM." + } + }, + "storageManagedIdentityResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the managed identity for storage." } }, "secureBootEnabled": { "type": "bool", "metadata": { - "description": "Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." + "description": "Indicates whether secure boot is enabled for the VM." } }, "vTpmEnabled": { "type": "bool", "metadata": { - "description": "Specifies whether virtual TPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." + "description": "Indicates whether vTPM is enabled for the VM." } }, - "location": { + "sessionHostTimeZone": { "type": "string", "metadata": { - "description": "Location where to deploy compute services." + "description": "The time zone for the session host." } }, - "encryptionAtHost": { - "type": "bool", + "applicationSecurityGroupResourceId": { + "type": "string", "metadata": { - "description": "This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + "description": "The resource ID of the application security group." } }, - "mgmtVmSize": { - "type": "string", + "storageAvailabilityZones": { + "type": "bool", "metadata": { - "description": "Session host VM size." + "description": "USe or not zone redundant storage." } }, - "osDiskType": { + "dnsServers": { "type": "string", "metadata": { - "description": "OS disk type for session host." + "description": "The custom DNS IPs." } }, - "osImage": { - "type": "object", + "identityServiceProvider": { + "type": "string", "metadata": { - "description": "Market Place OS image" + "description": "The identity service provider (e.g., EntraDS)." } }, - "storageManagedIdentityResourceId": { + "domainJoinUserName": { "type": "string", "metadata": { - "description": "Storage Managed Identity Resource ID." + "description": "The domain join username." } }, "vmLocalUserName": { "type": "string", "metadata": { - "description": "Local administrator username." + "description": "The VM local username." } }, - "identityDomainName": { + "serviceObjectsRgName": { "type": "string", "metadata": { - "description": "Identity domain name." + "description": "The service objects resource group name." } }, - "wrklKvName": { + "storageObjectsRgName": { "type": "string", "metadata": { - "description": "Keyvault name to get credentials from." + "description": "The storage objects resource group name." } }, - "domainJoinUserName": { + "managementVmSize": { "type": "string", "metadata": { - "description": "AVD session host domain join credentials." + "description": "The VM size for the management VM." } }, - "ouPath": { + "avdSessionHostsOuPath": { "type": "string", "metadata": { - "description": "OU path to join AVd VMs." + "description": "The OU path for AVD session hosts." } }, - "applicationSecurityGroupResourceId": { + "storageOuPath": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Application Security Group (ASG) for the session hosts." + "description": "The storage OU path." } }, - "tags": { + "customResourceTags": { "type": "object", + "defaultValue": {}, "metadata": { - "description": "Tags to be applied to resources" + "description": "The custom resource tags." + } + }, + "defaultTags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "The AVD default tags." + } + }, + "createResourceTags": { + "type": "bool", + "metadata": { + "description": "Indicates whether to create resource tags." + } + }, + "baseScriptUri": { + "type": "string", + "metadata": { + "description": "The base script URI." + } + }, + "securityPrincipalName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The security principal name." } }, - "managementVmName": { + "identityDomainName": { + "type": "string", + "metadata": { + "description": "The identity domain name." + } + }, + "identityDomainGuid": { "type": "string", + "defaultValue": "", + "metadata": { + "description": "The identity domain GUID." + } + }, + "deployPrivateEndpointKeyvaultStorage": { + "type": "bool", + "metadata": { + "description": "Indicates whether to deploy private endpoints for Key Vault and storage." + } + }, + "createFslogixDeployment": { + "type": "bool", "metadata": { - "description": "Name for management virtual machine. for tools and to join Azure Files to domain." + "description": "Indicates whether to create FSLogix deployment." + } + }, + "createAppAttachDeployment": { + "type": "bool", + "metadata": { + "description": "Indicates whether to create App Attach deployment." } }, "time": { "type": "string", "defaultValue": "[utcNow()]", "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." + "description": "The deployment timestamp." } } }, "variables": { - "varManagedDisk": "[if(empty(parameters('diskEncryptionSetResourceId')), createObject('storageAccountType', parameters('osDiskType')), createObject('diskEncryptionSet', createObject('id', parameters('diskEncryptionSetResourceId')), 'storageAccountType', parameters('osDiskType')))]" + "$fxv#0": { + "win10_22h2_g2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "windows-10", + "sku": "win10-22h2-avd-g2", + "version": "latest" + }, + "win10_22h2_office_g2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "office-365", + "sku": "win10-22h2-avd-m365-g2", + "version": "latest" + }, + "win11_22h2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "Windows-11", + "sku": "win11-22h2-avd", + "version": "latest" + }, + "win11_22h2_office": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "office-365", + "sku": "win11-22h2-avd-m365", + "version": "latest" + }, + "win11_23h2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "Windows-11", + "sku": "win11-23h2-avd", + "version": "latest" + }, + "win11_23h2_office": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "office-365", + "sku": "win11-23h2-avd-m365", + "version": "latest" + }, + "win11_24h2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "Windows-11", + "sku": "win11-24h2-avd", + "version": "latest" + }, + "win11_24h2_office": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "office-365", + "sku": "win11-24h2-avd-m365", + "version": "latest" + }, + "winServer_2022_Datacenter": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2022-datacenter-g2", + "version": "latest" + }, + "winServer_2022_Datacenter_smalldisk_g2": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2022-datacenter-smalldisk-g2", + "version": "latest" + }, + "winServer_2022_datacenter_core": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2022-datacenter-core-g2", + "version": "latest" + }, + "winServer_2022_Datacenter_core_smalldisk_g2": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2022-datacenter-core-smalldisk-g2", + "version": "latest" + } + }, + "varNamingUniqueStringThreeChar": "[take(format('{0}', uniqueString(parameters('subId'), parameters('deploymentPrefix'), parameters('time'))), 3)]", + "varAnfCapacityPoolSize": "[if(greater(add(if(parameters('createFslogixDeployment'), parameters('fslogixFileShareQuotaSize'), 0), if(parameters('createAppAttachDeployment'), parameters('appAttachFileShareQuotaSize'), 0)), 4096), add(if(parameters('createFslogixDeployment'), parameters('fslogixFileShareQuotaSize'), 0), if(parameters('createAppAttachDeployment'), parameters('appAttachFileShareQuotaSize'), 0)), 4096)]", + "varFslogixFileShareName": "[if(equals(parameters('storageService'), 'AzureFiles'), if(parameters('useCustomNaming'), parameters('fslogixFileShareCustomName'), format('fslogix-pc-{0}-{1}-{2}-001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('locationAcronym'))), if(equals(parameters('storageService'), 'ANF'), format('fsl{0}{1}{2}001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('locationAcronym')), ''))]", + "varAnfSmbServerNamePrefix": "[format('anf{0}{1}', parameters('deploymentPrefix'), parameters('deploymentEnvironment'))]", + "varAppAttachFileShareName": "[if(equals(parameters('storageService'), 'AzureFiles'), if(parameters('useCustomNaming'), parameters('appAttachFileShareCustomName'), format('appa-{0}-{1}-{2}-001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('locationAcronym'))), if(equals(parameters('storageService'), 'ANF'), format('appa{0}01', parameters('deploymentPrefix')), ''))]", + "varFslogixAnfVolume": "[if(parameters('createFslogixDeployment'), createArray(createObject('name', variables('varFslogixFileShareName'), 'coolAccess', false(), 'encryptionKeySource', 'Microsoft.NetApp', 'zones', createArray(), 'serviceLevel', parameters('fslogixStoragePerformance'), 'networkFeatures', 'Standard', 'usageThreshold', mul(parameters('fslogixFileShareQuotaSize'), 1073741824), 'protocolTypes', createArray('CIFS'), 'subnetResourceId', parameters('anfSubnetResourceId'), 'creationToken', variables('varFslogixFileShareName'), 'smbContinuouslyAvailable', true(), 'securityStyle', 'ntfs')), createArray())]", + "varAppAttchAnfVolume": "[if(parameters('createAppAttachDeployment'), createArray(createObject('name', variables('varAppAttachFileShareName'), 'coolAccess', false(), 'encryptionKeySource', 'Microsoft.NetApp', 'zones', createArray(), 'serviceLevel', parameters('appAttachStoragePerformance'), 'networkFeatures', 'Standard', 'usageThreshold', mul(parameters('appAttachFileShareQuotaSize'), 1073741824), 'protocolTypes', createArray('CIFS'), 'subnetResourceId', parameters('anfSubnetResourceId'), 'creationToken', variables('varAppAttachFileShareName'), 'smbContinuouslyAvailable', true(), 'securityStyle', 'ntfs')), createArray())]", + "varAnfVolumes": "[union(variables('varFslogixAnfVolume'), variables('varAppAttchAnfVolume'))]", + "varFslogixStorageName": "[if(parameters('useCustomNaming'), format('{0}fsl{1}{2}{3}', parameters('storageAccountPrefixCustomName'), parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')), format('stfsl{0}{1}{2}', parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')))]", + "varAnfAccountName": "[if(parameters('useCustomNaming'), parameters('anfAccountCustomName'), format('anf-acc-{0}-001', parameters('computeStorageResourcesNamingStandard')))]", + "varAnfCapacityPoolName": "[format('anf-cpool-{0}-001', parameters('computeStorageResourcesNamingStandard'))]", + "varFslogixStorageFqdn": "[if(parameters('createFslogixDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('{0}.file.{1}', variables('varFslogixStorageName'), environment().suffixes.storage), if(equals(parameters('storageService'), 'ANF'), format('{0}...{1}.netapp.azure.com', variables('varFslogixFileShareName'), parameters('location')), '')), '')]", + "varAppAttachStorageFqdn": "[if(parameters('createAppAttachDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('{0}.file.{1}', variables('varAppAttachStorageName'), environment().suffixes.storage), if(equals(parameters('storageService'), 'ANF'), format('{0}...{1}.netapp.azure.com', variables('varAppAttachFileShareName'), parameters('location')), '')), '')]", + "varAppAttachStorageName": "[if(parameters('useCustomNaming'), format('{0}appa{1}{2}{3}', parameters('storageAccountPrefixCustomName'), parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')), format('stappa{0}{1}{2}', parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')))]", + "varManagementVmName": "[format('vmmgmt{0}{1}{2}', parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), parameters('locationAcronym'))]", + "varFslogixStoragePerformance": "[if(equals(parameters('fslogixStoragePerformance'), 'Ultra'), 'Premium', parameters('fslogixStoragePerformance'))]", + "varAppAttachStoragePerformance": "[if(equals(parameters('appAttachStoragePerformance'), 'Ultra'), 'Premium', parameters('appAttachStoragePerformance'))]", + "varFslogixStorageSku": "[if(and(parameters('storageAvailabilityZones'), equals(parameters('storageService'), 'AzureFiles')), format('{0}_ZRS', variables('varFslogixStoragePerformance')), format('{0}_LRS', variables('varFslogixStoragePerformance')))]", + "varAppAttachStorageSku": "[if(parameters('storageAvailabilityZones'), format('{0}_ZRS', variables('varAppAttachStoragePerformance')), format('{0}_LRS', variables('varAppAttachStoragePerformance')))]", + "varStorageAzureFilesDscAgentPackageLocation": "https://github.com/Azure/avdaccelerator/raw/main/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip", + "varStorageToDomainScriptUri": "[format('{0}scripts/Manual-DSC-Storage-Scripts.ps1', parameters('baseScriptUri'))]", + "varStorageToDomainScript": "./Manual-DSC-Storage-Scripts.ps1", + "varOuStgPath": "[if(not(empty(parameters('storageOuPath'))), format('\"{0}\"', parameters('storageOuPath')), format('\"{0}\"', variables('varDefaultStorageOuPath')))]", + "varDefaultStorageOuPath": "[if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDC Computers', 'Computers')]", + "varStorageCustomOuPath": "[if(not(empty(parameters('storageOuPath'))), 'true', 'false')]", + "varMarketPlaceGalleryWindows": "[variables('$fxv#0')]" }, "resources": [ { + "condition": "[and(not(equals(parameters('identityServiceProvider'), 'EntraID')), or(parameters('createFslogixDeployment'), parameters('createAppAttachDeployment')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('MGMT-VM-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "name": "[format('Storage-MGMT-VM-{0}', parameters('time'))]", + "location": "[deployment().location]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[parameters('managementVmName')]" + "diskEncryptionSetResourceId": { + "value": "[parameters('diskEncryptionSetResourceId')]" }, - "location": { - "value": "[parameters('location')]" + "identityServiceProvider": { + "value": "[parameters('identityServiceProvider')]" }, - "timeZone": { - "value": "[parameters('computeTimeZone')]" + "vmName": { + "value": "[variables('varManagementVmName')]" }, - "managedIdentities": { - "value": { - "systemAssigned": false, - "userAssignedResourceIds": [ - "[parameters('storageManagedIdentityResourceId')]" - ] - } + "computeTimeZone": { + "value": "[parameters('sessionHostTimeZone')]" }, - "encryptionAtHost": { - "value": "[parameters('encryptionAtHost')]" + "applicationSecurityGroupResourceId": { + "value": "[parameters('applicationSecurityGroupResourceId')]" }, - "zone": { - "value": 0 + "domainJoinUserName": { + "value": "[parameters('domainJoinUserName')]" }, - "osType": { - "value": "Windows" + "keyVaultResourceId": { + "value": "[parameters('keyVaultResourceId')]" + }, + "serviceObjectsRgName": { + "value": "[parameters('serviceObjectsRgName')]" + }, + "identityDomainName": { + "value": "[parameters('identityDomainName')]" + }, + "ouPath": { + "value": "[parameters('avdSessionHostsOuPath')]" + }, + "osDiskType": { + "value": "Standard_LRS" + }, + "location": { + "value": "[parameters('location')]" }, "vmSize": { - "value": "[parameters('mgmtVmSize')]" + "value": "[parameters('managementVmSize')]" + }, + "subnetResourceId": { + "value": "[parameters('vmsSubnetResourceId')]" + }, + "enableAcceleratedNetworking": { + "value": true }, "securityType": { "value": "[parameters('securityType')]" @@ -23139,898 +24061,308 @@ "vTpmEnabled": { "value": "[parameters('vTpmEnabled')]" }, - "imageReference": { - "value": "[parameters('osImage')]" - }, - "osDisk": { - "value": { - "createOption": "FromImage", - "deleteOption": "Delete", - "caching": "ReadWrite", - "managedDisk": "[variables('varManagedDisk')]" - } - }, - "adminUsername": { + "vmLocalUserName": { "value": "[parameters('vmLocalUserName')]" }, - "adminPassword": { - "reference": { - "keyVault": { - "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.KeyVault/vaults', parameters('wrklKvName'))]" - }, - "secretName": "vmLocalUserPassword" - } - }, - "nicConfigurations": { - "value": [ - { - "name": "[format('nic-01-{0}', parameters('managementVmName'))]", - "deleteOption": "Delete", - "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", - "ipConfigurations": "[if(not(empty(parameters('applicationSecurityGroupResourceId'))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetId'), 'applicationSecurityGroups', createArray(createObject('id', parameters('applicationSecurityGroupResourceId'))))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetId'))))]" - } - ] - }, - "allowExtensionOperations": { - "value": true + "subId": { + "value": "[parameters('subId')]" }, - "extensionDomainJoinPassword": { - "reference": { - "keyVault": { - "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.KeyVault/vaults', parameters('wrklKvName'))]" - }, - "secretName": "domainJoinUserPassword" - } + "encryptionAtHost": { + "value": "[parameters('encryptionAtHost')]" }, - "extensionDomainJoinConfig": { - "value": { - "enabled": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), false(), true())]", - "settings": { - "name": "[parameters('identityDomainName')]", - "ouPath": "[if(not(empty(parameters('ouPath'))), parameters('ouPath'), null())]", - "user": "[parameters('domainJoinUserName')]", - "restart": "true", - "options": "3" - } - } + "storageManagedIdentityResourceId": { + "value": "[parameters('storageManagedIdentityResourceId')]" }, - "extensionAadJoinConfig": { - "value": { - "enabled": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), true(), false())]" - } + "osImage": { + "value": "[variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')]]" }, - "tags": { - "value": "[parameters('tags')]" - } + "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]" }, "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "11050393703898934384" + "version": "0.34.44.8038", + "templateHash": "8670712661433034722" }, - "name": "Virtual Machines", - "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", - "owner": "Azure/module-maintainers" + "name": "AVD LZA storage management VM", + "description": "This module deploys a management VM to join Azure Files to domain and for tools.", + "owner": "Azure/avdaccelerator" }, - "definitions": { - "managedIdentitiesType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } - } - }, - "nullable": true + "parameters": { + "diskEncryptionSetResourceId": { + "type": "string", + "metadata": { + "description": "AVD disk encryption set resource ID to enable server side encyption." + } + }, + "subId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "computeTimeZone": { + "type": "string", + "metadata": { + "description": "Virtual machine time zone." + } + }, + "identityServiceProvider": { + "type": "string", + "metadata": { + "description": "Required, The service providing domain services for Azure Virtual Desktop." + } + }, + "serviceObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name for Azure Files." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Subnet resource ID." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "metadata": { + "description": "Enable accelerated networking on the session host VMs." + } + }, + "securityType": { + "type": "string", + "metadata": { + "description": "Specifies the securityType of the virtual machine. Must be TrustedLaunch or ConfidentialVM enable UefiSettings." + } + }, + "secureBootEnabled": { + "type": "bool", + "metadata": { + "description": "Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "vTpmEnabled": { + "type": "bool", + "metadata": { + "description": "Specifies whether virtual TPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy compute services." + } + }, + "encryptionAtHost": { + "type": "bool", + "metadata": { + "description": "This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "Session host VM size." + } }, "osDiskType": { + "type": "string", + "metadata": { + "description": "OS disk type for session host." + } + }, + "osImage": { "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "metadata": { - "description": "Required. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } + "metadata": { + "description": "Market Place OS image" } }, - "dataDisksType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "lun": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the logical unit number of the data disk." - } - }, - "diskSizeGB": { - "type": "int", - "maxValue": 1023, - "metadata": { - "description": "Required. Specifies the size of an empty data disk in gigabytes." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "metadata": { - "description": "Required. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." - } - }, - "computerName": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "Required. Specifies the size for the VMs." - } - }, - "encryptionAtHost": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "securityType": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the SecurityType of the virtual machine. It is set as TrustedLaunch to enable UefiSettings." - } - }, - "secureBootEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "vTpmEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "imageReference": { - "type": "object", - "metadata": { - "description": "Required. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image." - } - }, - "plan": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." - } - }, - "osDisk": { - "$ref": "#/definitions/osDiskType", - "metadata": { - "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "dataDisks": { - "$ref": "#/definitions/dataDisksType", - "metadata": { - "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "ultraSSDEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." - } - }, - "adminUsername": { - "type": "securestring", - "metadata": { - "description": "Required. Administrator username." - } - }, - "adminPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. When specifying a Windows Virtual Machine, this value should be passed." - } - }, - "customData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." - } - }, - "certificatesToBeInstalled": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." - } - }, - "priority": { - "type": "string", - "defaultValue": "Regular", - "allowedValues": [ - "Regular", - "Low", - "Spot" - ], - "metadata": { - "description": "Optional. Specifies the priority for the virtual machine." - } - }, - "enableEvictionPolicy": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy." - } - }, - "maxPriceForLowPriorityVm": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." - } - }, - "dedicatedHostId": { + "storageManagedIdentityResourceId": { "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." - } - }, - "licenseType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "RHEL_BYOS", - "SLES_BYOS", - "Windows_Client", - "Windows_Server", - "" - ], - "metadata": { - "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", - "metadata": { - "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." - } - }, - "bootDiagnostics": { - "type": "bool", - "defaultValue": false, "metadata": { - "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." + "description": "Storage Managed Identity Resource ID." } }, - "bootDiagnosticStorageAccountName": { + "vmLocalUserName": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." + "description": "Local administrator username." } }, - "bootDiagnosticStorageAccountUri": { + "identityDomainName": { "type": "string", - "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", "metadata": { - "description": "Optional. Storage account boot diagnostic base URI." + "description": "Identity domain name." } }, - "proximityPlacementGroupResourceId": { + "keyVaultResourceId": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. Resource ID of a proximity placement group." + "description": "Keyvault resource ID to get credentials from." } }, - "virtualMachineScaleSetResourceId": { + "domainJoinUserName": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." + "description": "AVD session host domain join credentials." } }, - "availabilitySetResourceId": { + "ouPath": { "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." - } - }, - "zone": { - "type": "int", - "allowedValues": [ - 0, - 1, - 2, - 3 - ], - "metadata": { - "description": "Required. If set to 1, 2 or 3, the availability zone for all VMs is hardcoded to that value. If zero, then availability zones is not used. Cannot be used in combination with availability set nor scale set." - } - }, - "nicConfigurations": { - "type": "array", - "metadata": { - "description": "Required. Configures NICs and PIPs." - } - }, - "allowExtensionOperations": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." - } - }, - "extensionDomainJoinPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if name is specified. Password of the user specified in user parameter." - } - }, - "extensionDomainJoinConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAadJoinConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." - } - }, - "extensionAzureDiskEncryptionConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." - } - }, - "extensionDSCConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionCustomScriptConfig": { - "type": "object", - "defaultValue": { - "enabled": false, - "fileData": [] - }, - "metadata": { - "description": "Optional. The configuration for the [Custom Script] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionNvidiaGpuDriverWindows": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionCustomScriptProtectedSetting": { - "type": "secureObject", - "defaultValue": {}, "metadata": { - "description": "Optional. An object that contains the extension specific protected settings." + "description": "OU path to join AVd VMs." } }, - "location": { + "applicationSecurityGroupResourceId": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." + "description": "Application Security Group (ASG) for the session hosts." } }, "tags": { "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "baseTime": { - "type": "string", - "defaultValue": "[utcNow('u')]", - "metadata": { - "description": "Generated. Do not provide a value! This date value is used to generate a registration token." - } - }, - "sasTokenValidityLength": { - "type": "string", - "defaultValue": "PT8H", - "metadata": { - "description": "Optional. SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." - } - }, - "osType": { - "type": "string", - "allowedValues": [ - "Windows", - "Linux" - ], - "metadata": { - "description": "Required. The chosen OS type." - } - }, - "provisionVMAgent": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." - } - }, - "enableAutomaticUpdates": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." - } - }, - "patchMode": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "AutomaticByPlatform", - "AutomaticByOS", - "Manual", - "ImageDefault", - "" - ], - "metadata": { - "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." - } - }, - "bypassPlatformSafetyChecksOnUserSchedule": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enables customer to schedule patching without accidental upgrades." - } - }, - "rebootSetting": { - "type": "string", - "defaultValue": "IfRequired", - "allowedValues": [ - "Always", - "IfRequired", - "Never", - "Unknown" - ], - "metadata": { - "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." - } - }, - "patchAssessmentMode": { - "type": "string", - "defaultValue": "ImageDefault", - "allowedValues": [ - "AutomaticByPlatform", - "ImageDefault" - ], "metadata": { - "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." + "description": "Tags to be applied to resources" } }, - "timeZone": { + "vmName": { "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." - } - }, - "additionalUnattendContent": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." - } - }, - "winRM": { - "type": "array", - "defaultValue": [], "metadata": { - "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object." + "description": "Name for management virtual machine. for tools and to join Azure Files to domain." } }, - "configurationProfile": { + "time": { "type": "string", - "defaultValue": "", + "defaultValue": "[utcNow()]", "metadata": { - "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." + "description": "Do not modify, used to set unique value for resource deployment." } } }, "variables": { - "windowsConfiguration": { - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting'))), null())]", - "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", - "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), parameters('additionalUnattendContent'))]", - "winRM": "[if(not(empty(parameters('winRM'))), createObject('listeners', parameters('winRM')), null())]" - }, - "accountSasProperties": { - "signedServices": "b", - "signedPermission": "r", - "signedExpiry": "[dateTimeAdd(parameters('baseTime'), parameters('sasTokenValidityLength'))]", - "signedResourceTypes": "o", - "signedProtocol": "https" - }, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]", + "varManagedDisk": "[if(empty(parameters('diskEncryptionSetResourceId')), createObject('storageAccountType', parameters('osDiskType')), createObject('diskEncryptionSet', createObject('id', parameters('diskEncryptionSetResourceId')), 'storageAccountType', parameters('osDiskType')))]" }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "resources": [ + { "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2022-09-01", + "name": "[format('MGMT-VM-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "vm": { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2023-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "zones": "[if(not(equals(parameters('zone'), 0)), array(string(parameters('zone'))), null())]", - "plan": "[if(not(empty(parameters('plan'))), parameters('plan'), null())]", - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "securityProfile": { - "encryptionAtHost": "[if(parameters('encryptionAtHost'), parameters('encryptionAtHost'), null())]", - "securityType": "[parameters('securityType')]", - "uefiSettings": "[if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null())]" - }, - "storageProfile": { - "copy": [ - { - "name": "dataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", - "input": { - "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", - "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))]", - "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createoption'), 'Empty')]", - "deleteOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete')]", - "caching": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly')]", - "managedDisk": { - "storageAccountType": "[coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.storageAccountType]", - "diskEncryptionSet": "[coalesce(tryGet(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'managedDisk'), 'diskEncryptionSet'), null())]" - } - } + "parameters": { + "name": { + "value": "[parameters('vmName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "timeZone": { + "value": "[parameters('computeTimeZone')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": false, + "userAssignedResourceIds": [ + "[parameters('storageManagedIdentityResourceId')]" + ] } - ], - "imageReference": "[parameters('imageReference')]", + }, + "encryptionAtHost": { + "value": "[parameters('encryptionAtHost')]" + }, + "zone": { + "value": 0 + }, + "osType": { + "value": "Windows" + }, + "vmSize": { + "value": "[parameters('vmSize')]" + }, + "securityType": { + "value": "[parameters('securityType')]" + }, + "secureBootEnabled": { + "value": "[parameters('secureBootEnabled')]" + }, + "vTpmEnabled": { + "value": "[parameters('vTpmEnabled')]" + }, + "imageReference": { + "value": "[parameters('osImage')]" + }, "osDisk": { - "name": "[coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name')))]", - "createOption": "[coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage')]", - "deleteOption": "[coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete')]", - "caching": "[coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly')]", - "managedDisk": { - "storageAccountType": "[parameters('osDisk').managedDisk.storageAccountType]", - "diskEncryptionSet": { - "id": "[tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')]" - } + "value": { + "createOption": "FromImage", + "deleteOption": "Delete", + "caching": "ReadWrite", + "managedDisk": "[variables('varManagedDisk')]" } - } - }, - "additionalCapabilities": { - "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]" - }, - "osProfile": { - "computerName": "[parameters('computerName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]", - "customData": "[if(not(empty(parameters('customData'))), base64(parameters('customData')), null())]", - "windowsConfiguration": "[if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null())]", - "secrets": "[parameters('certificatesToBeInstalled')]", - "allowExtensionOperations": "[parameters('allowExtensionOperations')]" - }, - "networkProfile": { - "copy": [ - { - "name": "networkInterfaces", - "count": "[length(parameters('nicConfigurations'))]", - "input": { - "properties": { - "deleteOption": "[if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].deleteOption, 'Delete')]", - "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" - }, - "id": "[resourceId('Microsoft.Network/networkInterfaces', if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].name, format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].nicSuffix)))]" - } + }, + "adminUsername": { + "value": "[parameters('vmLocalUserName')]" + }, + "adminPassword": { + "reference": { + "keyVault": { + "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))]" + }, + "secretName": "vmLocalUserPassword" } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", - "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" - } - }, - "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", - "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", - "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", - "priority": "[parameters('priority')]", - "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", - "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", - "host": "[if(not(empty(parameters('dedicatedHostId'))), createObject('id', parameters('dedicatedHostId')), null())]", - "licenseType": "[if(not(empty(parameters('licenseType'))), parameters('licenseType'), null())]" - }, - "dependsOn": [ - "vm_nic" - ] - }, - "vm_configurationProfileAssignment": { - "condition": "[not(empty(parameters('configurationProfile')))]", - "type": "Microsoft.Automanage/configurationProfileAssignments", - "apiVersion": "2022-05-04", - "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", - "name": "default", - "properties": { - "configurationProfile": "[parameters('configurationProfile')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_nic": { - "copy": { - "name": "vm_nic", - "count": "[length(parameters('nicConfigurations'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "networkInterfaceName": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'name'), createObject('value', parameters('nicConfigurations')[copyIndex()].name), createObject('value', format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex()].nicSuffix)))]", - "virtualMachineName": { - "value": "[parameters('name')]" }, - "location": { - "value": "[parameters('location')]" + "nicConfigurations": { + "value": [ + { + "name": "[format('nic-01-{0}', parameters('vmName'))]", + "deleteOption": "Delete", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "ipConfigurations": "[if(not(empty(parameters('applicationSecurityGroupResourceId'))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetResourceId'), 'applicationSecurityGroups', createArray(createObject('id', parameters('applicationSecurityGroupResourceId'))))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetResourceId'))))]" + } + ] }, - "enableIPForwarding": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableIPForwarding), createObject('value', false()))]", - "enableAcceleratedNetworking": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableAcceleratedNetworking), createObject('value', true()))]", - "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(parameters('nicConfigurations')[copyIndex()].dnsServers)), createObject('value', parameters('nicConfigurations')[copyIndex()].dnsServers), createObject('value', createArray())), createObject('value', createArray()))]", - "networkSecurityGroupResourceId": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('nicConfigurations')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", - "ipConfigurations": { - "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" + "allowExtensionOperations": { + "value": true }, - "tags": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + "extensionDomainJoinPassword": { + "reference": { + "keyVault": { + "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))]" + }, + "secretName": "domainJoinUserPassword" + } }, - "diagnosticSettings": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" + "extensionDomainJoinConfig": { + "value": { + "enabled": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), false(), true())]", + "settings": { + "name": "[parameters('identityDomainName')]", + "ouPath": "[if(not(empty(parameters('ouPath'))), parameters('ouPath'), null())]", + "user": "[parameters('domainJoinUserName')]", + "restart": "true", + "options": "3" + } + } }, - "roleAssignments": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" + "extensionAadJoinConfig": { + "value": { + "enabled": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), true(), false())]" + } }, - "enableTelemetry": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + "tags": { + "value": "[parameters('tags')]" } }, "template": { @@ -24040,37 +24372,115 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "11733090358061195696" - } + "version": "0.34.44.8038", + "templateHash": "13031055217657209142" + }, + "name": "Virtual Machines", + "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", + "owner": "Azure/module-maintainers" }, "definitions": { - "lockType": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "osDiskType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Optional. The disk name." } }, - "kind": { + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "caching": { "type": "string", "allowedValues": [ - "CanNotDelete", "None", - "ReadOnly" + "ReadOnly", + "ReadWrite" ], "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "Optional. Specifies the caching requirements." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "metadata": { + "description": "Required. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." } } - }, - "nullable": true + } }, - "diagnosticSettingType": { + "dataDisksType": { "type": "array", "items": { "type": "object", @@ -24079,177 +24489,86 @@ "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of diagnostic setting." + "description": "Optional. The disk name." } }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, + "lun": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Optional. Specifies the logical unit number of the data disk." } }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, + "diskSizeGB": { + "type": "int", + "maxValue": 1023, "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + "description": "Required. Specifies the size of an empty data disk in gigabytes." } }, - "logAnalyticsDestinationType": { + "createOption": { "type": "string", "allowedValues": [ - "AzureDiagnostics", - "Dedicated" + "Attach", + "Empty", + "FromImage" ], "nullable": true, "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. Specifies how the virtual machine should be created." } }, - "principalType": { + "deleteOption": { "type": "string", "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" + "Delete", + "Detach" ], "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." } }, - "conditionVersion": { + "caching": { "type": "string", "allowedValues": [ - "2.0" + "None", + "ReadOnly", + "ReadWrite" ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Specifies the caching requirements." } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "metadata": { + "description": "Required. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + } + }, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Required. The managed disk parameters." } } } @@ -24258,121 +24577,622 @@ } }, "parameters": { - "networkInterfaceName": { - "type": "string" + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." + } }, - "virtualMachineName": { - "type": "string" + "computerName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." + } }, - "ipConfigurations": { - "type": "array" + "vmSize": { + "type": "string", + "metadata": { + "description": "Required. Specifies the size for the VMs." + } }, - "location": { + "encryptionAtHost": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "securityType": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. Specifies the SecurityType of the virtual machine. It is set as TrustedLaunch to enable UefiSettings." } }, - "tags": { - "type": "object", - "nullable": true, + "secureBootEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." } }, - "enableIPForwarding": { + "vTpmEnabled": { "type": "bool", - "defaultValue": false + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } }, - "enableAcceleratedNetworking": { + "imageReference": { + "type": "object", + "metadata": { + "description": "Required. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image." + } + }, + "plan": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." + } + }, + "osDisk": { + "$ref": "#/definitions/osDiskType", + "metadata": { + "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "dataDisks": { + "$ref": "#/definitions/dataDisksType", + "metadata": { + "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "ultraSSDEnabled": { "type": "bool", - "defaultValue": false + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." + } }, - "dnsServers": { + "adminUsername": { + "type": "securestring", + "metadata": { + "description": "Required. Administrator username." + } + }, + "adminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. When specifying a Windows Virtual Machine, this value should be passed." + } + }, + "customData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." + } + }, + "certificatesToBeInstalled": { "type": "array", - "defaultValue": [] + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." + } }, - "enableTelemetry": { + "priority": { + "type": "string", + "defaultValue": "Regular", + "allowedValues": [ + "Regular", + "Low", + "Spot" + ], + "metadata": { + "description": "Optional. Specifies the priority for the virtual machine." + } + }, + "enableEvictionPolicy": { "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." + "description": "Optional. Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy." } }, - "networkSecurityGroupResourceId": { + "maxPriceForLowPriorityVm": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." + "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." } }, - "lock": { - "$ref": "#/definitions/lockType", + "dedicatedHostId": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." } }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", + "licenseType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "RHEL_BYOS", + "SLES_BYOS", + "Windows_Client", + "Windows_Server", + "" + ], "metadata": { - "description": "Optional. The diagnostic settings of the Network Interface." + "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." } }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." } - } - }, + }, + "bootDiagnostics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." + } + }, + "bootDiagnosticStorageAccountName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." + } + }, + "bootDiagnosticStorageAccountUri": { + "type": "string", + "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", + "metadata": { + "description": "Optional. Storage account boot diagnostic base URI." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a proximity placement group." + } + }, + "virtualMachineScaleSetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." + } + }, + "availabilitySetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." + } + }, + "zone": { + "type": "int", + "allowedValues": [ + 0, + 1, + 2, + 3 + ], + "metadata": { + "description": "Required. If set to 1, 2 or 3, the availability zone for all VMs is hardcoded to that value. If zero, then availability zones is not used. Cannot be used in combination with availability set nor scale set." + } + }, + "nicConfigurations": { + "type": "array", + "metadata": { + "description": "Required. Configures NICs and PIPs." + } + }, + "allowExtensionOperations": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." + } + }, + "extensionDomainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if name is specified. Password of the user specified in user parameter." + } + }, + "extensionDomainJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAadJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." + } + }, + "extensionAzureDiskEncryptionConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." + } + }, + "extensionDSCConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "fileData": [] + }, + "metadata": { + "description": "Optional. The configuration for the [Custom Script] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionNvidiaGpuDriverWindows": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptProtectedSetting": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. An object that contains the extension specific protected settings." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to generate a registration token." + } + }, + "sasTokenValidityLength": { + "type": "string", + "defaultValue": "PT8H", + "metadata": { + "description": "Optional. SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. The chosen OS type." + } + }, + "provisionVMAgent": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." + } + }, + "enableAutomaticUpdates": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." + } + }, + "patchMode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "AutomaticByPlatform", + "AutomaticByOS", + "Manual", + "ImageDefault", + "" + ], + "metadata": { + "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." + } + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables customer to schedule patching without accidental upgrades." + } + }, + "rebootSetting": { + "type": "string", + "defaultValue": "IfRequired", + "allowedValues": [ + "Always", + "IfRequired", + "Never", + "Unknown" + ], + "metadata": { + "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." + } + }, + "patchAssessmentMode": { + "type": "string", + "defaultValue": "ImageDefault", + "allowedValues": [ + "AutomaticByPlatform", + "ImageDefault" + ], + "metadata": { + "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." + } + }, + "additionalUnattendContent": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." + } + }, + "winRM": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object." + } + }, + "configurationProfile": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." + } + } + }, + "variables": { + "windowsConfiguration": { + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting'))), null())]", + "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", + "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), parameters('additionalUnattendContent'))]", + "winRM": "[if(not(empty(parameters('winRM'))), createObject('listeners', parameters('winRM')), null())]" + }, + "accountSasProperties": { + "signedServices": "b", + "signedPermission": "r", + "signedExpiry": "[dateTimeAdd(parameters('baseTime'), parameters('sasTokenValidityLength'))]", + "signedResourceTypes": "o", + "signedProtocol": "https" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, "resources": { - "networkInterface_publicIPAddresses": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "vm": { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "zones": "[if(not(equals(parameters('zone'), 0)), array(string(parameters('zone'))), null())]", + "plan": "[if(not(empty(parameters('plan'))), parameters('plan'), null())]", + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "securityProfile": { + "encryptionAtHost": "[if(parameters('encryptionAtHost'), parameters('encryptionAtHost'), null())]", + "securityType": "[parameters('securityType')]", + "uefiSettings": "[if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null())]" + }, + "storageProfile": { + "copy": [ + { + "name": "dataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", + "input": { + "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", + "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))]", + "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createoption'), 'Empty')]", + "deleteOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete')]", + "caching": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly')]", + "managedDisk": { + "storageAccountType": "[coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.storageAccountType]", + "diskEncryptionSet": "[coalesce(tryGet(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'managedDisk'), 'diskEncryptionSet'), null())]" + } + } + } + ], + "imageReference": "[parameters('imageReference')]", + "osDisk": { + "name": "[coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name')))]", + "createOption": "[coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage')]", + "deleteOption": "[coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete')]", + "caching": "[coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly')]", + "managedDisk": { + "storageAccountType": "[parameters('osDisk').managedDisk.storageAccountType]", + "diskEncryptionSet": { + "id": "[tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')]" + } + } + } + }, + "additionalCapabilities": { + "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]" + }, + "osProfile": { + "computerName": "[parameters('computerName')]", + "adminUsername": "[parameters('adminUsername')]", + "adminPassword": "[parameters('adminPassword')]", + "customData": "[if(not(empty(parameters('customData'))), base64(parameters('customData')), null())]", + "windowsConfiguration": "[if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null())]", + "secrets": "[parameters('certificatesToBeInstalled')]", + "allowExtensionOperations": "[parameters('allowExtensionOperations')]" + }, + "networkProfile": { + "copy": [ + { + "name": "networkInterfaces", + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "properties": { + "deleteOption": "[if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].deleteOption, 'Delete')]", + "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" + }, + "id": "[resourceId('Microsoft.Network/networkInterfaces', if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].name, format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].nicSuffix)))]" + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", + "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" + } + }, + "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", + "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", + "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", + "priority": "[parameters('priority')]", + "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", + "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", + "host": "[if(not(empty(parameters('dedicatedHostId'))), createObject('id', parameters('dedicatedHostId')), null())]", + "licenseType": "[if(not(empty(parameters('licenseType'))), parameters('licenseType'), null())]" + }, + "dependsOn": [ + "vm_nic" + ] + }, + "vm_configurationProfileAssignment": { + "condition": "[not(empty(parameters('configurationProfile')))]", + "type": "Microsoft.Automanage/configurationProfileAssignments", + "apiVersion": "2022-05-04", + "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", + "name": "default", + "properties": { + "configurationProfile": "[parameters('configurationProfile')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_nic": { "copy": { - "name": "networkInterface_publicIPAddresses", - "count": "[length(parameters('ipConfigurations'))]" + "name": "vm_nic", + "count": "[length(parameters('nicConfigurations'))]" }, - "condition": "[contains(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIpNameSuffix)]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings')]" + "networkInterfaceName": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'name'), createObject('value', parameters('nicConfigurations')[copyIndex()].name), createObject('value', format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex()].nicSuffix)))]", + "virtualMachineName": { + "value": "[parameters('name')]" }, "location": { "value": "[parameters('location')]" }, - "lock": { - "value": "[parameters('lock')]" - }, - "idleTimeoutInMinutes": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'idleTimeoutInMinutes')]" + "enableIPForwarding": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableIPForwarding), createObject('value', false()))]", + "enableAcceleratedNetworking": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableAcceleratedNetworking), createObject('value', true()))]", + "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(parameters('nicConfigurations')[copyIndex()].dnsServers)), createObject('value', parameters('nicConfigurations')[copyIndex()].dnsServers), createObject('value', createArray())), createObject('value', createArray()))]", + "networkSecurityGroupResourceId": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('nicConfigurations')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", + "ipConfigurations": { + "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" }, - "ddosSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'ddosSettings')]" + "tags": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" }, - "dnsSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'dnsSettings')]" + "diagnosticSettings": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" }, - "publicIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressVersion'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAddressVersion), createObject('value', 'IPv4'))]", - "publicIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAllocationMethod'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAllocationMethod), createObject('value', 'Static'))]", - "publicIpPrefixResourceId": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPPrefixResourceId'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPPrefixResourceId), createObject('value', ''))]", - "roleAssignments": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'roleAssignments'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.roleAssignments), createObject('value', createArray()))]", - "skuName": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuName'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuName), createObject('value', 'Standard'))]", - "skuTier": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuTier'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuTier), createObject('value', 'Regional'))]", - "tags": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + "roleAssignments": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" }, - "zones": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.zones), createObject('value', createArray(1, 2, 3)))]", "enableTelemetry": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" } }, "template": { @@ -24382,80 +25202,11 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "4718335757080871925" - }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address.", - "owner": "Azure/module-maintainers" + "version": "0.34.44.8038", + "templateHash": "4081873631846149092" + } }, "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, "lockType": { "type": "object", "properties": { @@ -24481,72 +25232,6 @@ }, "nullable": true }, - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "", - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "metadata": { - "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "metadata": { - "description": "Required. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - } - }, "diagnosticSettingType": { "type": "array", "items": { @@ -24666,68 +25351,120 @@ } }, "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true } }, "parameters": { - "name": { + "networkInterfaceName": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + }, + "ipConfigurations": { + "type": "array" + }, + "location": { "type": "string", "metadata": { - "description": "Required. The name of the Public IP Address." + "description": "Optional. Location for all resources." } }, - "publicIpPrefixResourceId": { - "type": "string", + "tags": { + "type": "object", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + "description": "Optional. Tags of the resource." } }, - "publicIPAllocationMethod": { - "type": "string", - "defaultValue": "Static", - "allowedValues": [ - "Dynamic", - "Static" - ], - "metadata": { - "description": "Optional. The public IP address allocation method." - } + "enableIPForwarding": { + "type": "bool", + "defaultValue": false }, - "zones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false }, - "publicIPAddressVersion": { - "type": "string", - "defaultValue": "IPv4", - "allowedValues": [ - "IPv4", - "IPv6" - ], + "dnsServers": { + "type": "array", + "defaultValue": [] + }, + "enableTelemetry": { + "type": "bool", "metadata": { - "description": "Optional. IP address version." + "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." } }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. The DNS settings of the public IP address." + "description": "Optional. The network security group (NSG) to attach to the network interface." } }, "lock": { @@ -24736,40 +25473,10 @@ "description": "Optional. The lock settings of the service." } }, - "skuName": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Basic", - "Standard" - ], - "metadata": { - "description": "Optional. Name of a public IP address SKU." - } - }, - "skuTier": { - "type": "string", - "defaultValue": "Regional", - "allowedValues": [ - "Global", - "Regional" - ], - "metadata": { - "description": "Optional. Tier of a public IP address SKU." - } - }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. The diagnostic settings of the Network Interface." } }, "roleAssignments": { @@ -24777,759 +25484,1415 @@ "metadata": { "description": "Optional. Array of role assignments to create." } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "defaultValue": 4, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "networkInterface_publicIPAddresses": { + "copy": { + "name": "networkInterface_publicIPAddresses", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[contains(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2022-09-01", + "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIpNameSuffix)]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'idleTimeoutInMinutes')]" + }, + "ddosSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'dnsSettings')]" + }, + "publicIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressVersion'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAddressVersion), createObject('value', 'IPv4'))]", + "publicIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAllocationMethod'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAllocationMethod), createObject('value', 'Static'))]", + "publicIpPrefixResourceId": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPPrefixResourceId'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPPrefixResourceId), createObject('value', ''))]", + "roleAssignments": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'roleAssignments'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.roleAssignments), createObject('value', createArray()))]", + "skuName": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuName'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuName), createObject('value', 'Standard'))]", + "skuTier": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuTier'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuTier), createObject('value', 'Regional'))]", + "tags": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "zones": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.zones), createObject('value', createArray(1, 2, 3)))]", + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2023-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" - }, - "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", - "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": null - } - }, - "publicIpAddress_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_roleAssignments": { - "copy": { - "name": "publicIpAddress_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_diagnosticSettings": { - "copy": { - "name": "publicIpAddress_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the public IP address was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the public IP address." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the public IP address." - }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "ipAddress": { - "type": "string", - "metadata": { - "description": "The public IP address of the public IP address resource." - }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-NetworkInterface', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('networkInterfaceName')]" - }, - "ipConfigurations": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('ipConfigurations'))]", - "input": "[createObject('name', if(not(empty(parameters('ipConfigurations')[copyIndex('value')].name)), parameters('ipConfigurations')[copyIndex('value')].name, null()), 'primary', equals(copyIndex('value'), 0), 'privateIPAllocationMethod', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod, null()), null()), 'privateIPAddress', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('value')].privateIPAddress, null()), null()), 'publicIPAddressResourceId', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), resourceId('Microsoft.Network/publicIPAddresses', format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.publicIpNameSuffix)), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerBackendAddressPools, null()), 'applicationSecurityGroups', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('value')].applicationSecurityGroups, null()), 'applicationGatewayBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].applicationGatewayBackendAddressPools, null()), 'gatewayLoadBalancer', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('value')].gatewayLoadBalancer, null()), 'loadBalancerInboundNatRules', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerInboundNatRules, null()), 'privateIPAddressVersion', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('value')].privateIPAddressVersion, null()), 'virtualNetworkTaps', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('value')].virtualNetworkTaps, null()))]" - } - ] - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "dnsServers": "[if(not(empty(parameters('dnsServers'))), createObject('value', parameters('dnsServers')), createObject('value', createArray()))]", - "enableAcceleratedNetworking": { - "value": "[parameters('enableAcceleratedNetworking')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enableIPForwarding": { - "value": "[parameters('enableIPForwarding')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", - "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "1612343535299711142" - }, - "name": "Network Interface", - "description": "This module deploys a Network Interface.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.54.24096", + "templateHash": "4718335757080871925" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address.", + "owner": "Azure/module-maintainers" }, - "logCategoriesAndGroups": { - "type": "array", - "items": { + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { "type": "object", "properties": { - "category": { + "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + "description": "Optional. Specify the name of lock." } }, - "categoryGroup": { + "kind": { "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], "nullable": true, "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." } }, - "enabled": { - "type": "bool", + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "", + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "metadata": { + "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." } } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { + "ddosSettingsType": { "type": "object", "properties": { - "category": { - "type": "string", + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + "description": "Required. The DDoS protection plan associated with the public IP address." } }, - "enabled": { - "type": "bool", - "nullable": true, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "description": "Required. The DDoS protection policy customizations." } } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true } }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } } }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": null + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" } } } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the network interface." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If the network interface is accelerated networking enabled." - } - }, - "dnsServers": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "auxiliaryMode": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "Floating", - "MaxConnections", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "auxiliarySku": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "A1", - "A2", - "A4", - "A8", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "disableTcpStateTracking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "description": "Required. A list of IPConfigurations of the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." } }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "networkInterface": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.2.4', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkInterface', deployment().name)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('networkInterfaceName')]" + }, + "ipConfigurations": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('ipConfigurations'))]", + "input": "[createObject('name', if(not(empty(parameters('ipConfigurations')[copyIndex('value')].name)), parameters('ipConfigurations')[copyIndex('value')].name, null()), 'primary', equals(copyIndex('value'), 0), 'privateIPAllocationMethod', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod, null()), null()), 'privateIPAddress', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('value')].privateIPAddress, null()), null()), 'publicIPAddressResourceId', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), resourceId('Microsoft.Network/publicIPAddresses', format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.publicIpNameSuffix)), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerBackendAddressPools, null()), 'applicationSecurityGroups', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('value')].applicationSecurityGroups, null()), 'applicationGatewayBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].applicationGatewayBackendAddressPools, null()), 'gatewayLoadBalancer', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('value')].gatewayLoadBalancer, null()), 'loadBalancerInboundNatRules', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerInboundNatRules, null()), 'privateIPAddressVersion', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('value')].privateIPAddressVersion, null()), 'virtualNetworkTaps', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('value')].virtualNetworkTaps, null()))]" + } + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "dnsServers": "[if(not(empty(parameters('dnsServers'))), createObject('value', parameters('dnsServers')), createObject('value', createArray()))]", + "enableAcceleratedNetworking": { + "value": "[parameters('enableAcceleratedNetworking')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enableIPForwarding": { + "value": "[parameters('enableIPForwarding')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", + "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "ipConfigurations", - "count": "[length(parameters('ipConfigurations'))]", - "input": { - "name": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].name, format('ipconfig0{0}', add(copyIndex('ipConfigurations'), 1)))]", - "properties": { - "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", - "privateIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod, null()), null())]", - "privateIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress, null()), null())]", - "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId, null())), createObject('id', parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId), null()), null())]", - "subnet": { - "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" - }, - "loadBalancerBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerBackendAddressPools, null())]", - "applicationSecurityGroups": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationSecurityGroups, null())]", - "applicationGatewayBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationGatewayBackendAddressPools, null())]", - "gatewayLoadBalancer": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].gatewayLoadBalancer, null())]", - "loadBalancerInboundNatRules": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerInboundNatRules, null())]", - "privateIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddressVersion, null())]", - "virtualNetworkTaps": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].virtualNetworkTaps, null())]" - } - } - } - ], - "auxiliaryMode": "[parameters('auxiliaryMode')]", - "auxiliarySku": "[parameters('auxiliarySku')]", - "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", - "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", - "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", - "enableIPForwarding": "[parameters('enableIPForwarding')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" - } - }, - "networkInterface_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_diagnosticSettings": { - "copy": { - "name": "networkInterface_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "1612343535299711142" + }, + "name": "Network Interface", + "description": "This module deploys a Network Interface.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the network interface." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "dnsServers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "auxiliaryMode": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Floating", + "MaxConnections", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "auxiliarySku": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "A1", + "A2", + "A4", + "A8", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "disableTcpStateTracking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "description": "Required. A list of IPConfigurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.2.4', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "ipConfigurations", + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].name, format('ipconfig0{0}', add(copyIndex('ipConfigurations'), 1)))]", + "properties": { + "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", + "privateIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod, null()), null())]", + "privateIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress, null()), null())]", + "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId, null())), createObject('id', parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId), null()), null())]", + "subnet": { + "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" + }, + "loadBalancerBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerBackendAddressPools, null())]", + "applicationSecurityGroups": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationSecurityGroups, null())]", + "applicationGatewayBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationGatewayBackendAddressPools, null())]", + "gatewayLoadBalancer": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].gatewayLoadBalancer, null())]", + "loadBalancerInboundNatRules": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerInboundNatRules, null())]", + "privateIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddressVersion, null())]", + "virtualNetworkTaps": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].virtualNetworkTaps, null())]" + } + } + } + ], + "auxiliaryMode": "[parameters('auxiliaryMode')]", + "auxiliarySku": "[parameters('auxiliarySku')]", + "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", + "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "enableIPForwarding": "[parameters('enableIPForwarding')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" + } + }, + "networkInterface_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_diagnosticSettings": { + "copy": { + "name": "networkInterface_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_roleAssignments": { + "copy": { + "name": "networkInterface_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkInterface" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed resource." + }, + "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed resource." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkInterface', '2023-04-01', 'full').location]" + } + } + } }, "dependsOn": [ - "networkInterface" + "networkInterface_publicIPAddresses" ] + } + } + } + } + }, + "vm_aadJoinExtension": { + "condition": "[parameters('extensionAadJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "AADLogin" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.ActiveDirectory" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", + "typeHandlerVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAadJoinConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.0'), createObject('value', '1.0')))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAadJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAadJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": "[if(contains(parameters('extensionAadJoinConfig'), 'settings'), createObject('value', parameters('extensionAadJoinConfig').settings), createObject('value', createObject()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" }, - "networkInterface_roleAssignments": { - "copy": { - "name": "networkInterface_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "networkInterface" - ] + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the deployed resource." + "description": "The name of the extension." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed resource." + "description": "The resource ID of the extension." }, - "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed resource." + "description": "The name of the Resource Group the extension was created in." }, "value": "[resourceGroup().name]" }, @@ -25538,667 +26901,1323 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('networkInterface', '2023-04-01', 'full').location]" + "value": "[reference('extension', '2022-11-01', 'full').location]" } } } }, "dependsOn": [ - "networkInterface_publicIPAddresses" + "vm" ] - } - } - } - } - }, - "vm_aadJoinExtension": { - "condition": "[parameters('extensionAadJoinConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "AADLogin" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.ActiveDirectory" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAadJoinConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.0'), createObject('value', '1.0')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAadJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAadJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": "[if(contains(parameters('extensionAadJoinConfig'), 'settings'), createObject('value', parameters('extensionAadJoinConfig').settings), createObject('value', createObject()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "vm_domainJoinExtension": { + "condition": "[parameters('extensionDomainJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DomainJoin" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "JsonADDomainExtension" + }, + "typeHandlerVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDomainJoinConfig').typeHandlerVersion), createObject('value', '1.3'))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDomainJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDomainJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": { + "value": "[parameters('extensionDomainJoinConfig').settings]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": { + "Password": "[parameters('extensionDomainJoinPassword')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + "dependsOn": [ + "vm", + "vm_aadJoinExtension" + ] }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." + "vm_desiredStateConfigurationExtension": { + "condition": "[parameters('extensionDSCConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DesiredStateConfiguration" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Powershell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": "[if(contains(parameters('extensionDSCConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDSCConfig').typeHandlerVersion), createObject('value', '2.77'))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDSCConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDSCConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": "[if(contains(parameters('extensionDSCConfig'), 'settings'), createObject('value', parameters('extensionDSCConfig').settings), createObject('value', createObject()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": "[if(contains(parameters('extensionDSCConfig'), 'protectedSettings'), createObject('value', parameters('extensionDSCConfig').protectedSettings), createObject('value', createObject()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } }, - "value": "[resourceGroup().name]" + "dependsOn": [ + "vm" + ] }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "vm_customScriptExtension": { + "condition": "[parameters('extensionCustomScriptConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "CustomScriptExtension" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", + "typeHandlerVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionCustomScriptConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '1.10'), createObject('value', '2.1')))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionCustomScriptConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionCustomScriptConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": { + "value": { + "copy": [ + { + "name": "fileUris", + "count": "[length(parameters('extensionCustomScriptConfig').fileData)]", + "input": "[if(contains(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')], 'storageAccountId'), format('{0}?{1}', parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri, listAccountSas(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].storageAccountId, '2019-04-01', variables('accountSasProperties')).accountSasToken), parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri)]" + } + ] + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": "[parameters('extensionCustomScriptProtectedSetting')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_domainJoinExtension": { - "condition": "[parameters('extensionDomainJoinConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "DomainJoin" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "JsonADDomainExtension" - }, - "typeHandlerVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDomainJoinConfig').typeHandlerVersion), createObject('value', '1.3'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDomainJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDomainJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": { - "value": "[parameters('extensionDomainJoinConfig').settings]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": { - "Password": "[parameters('extensionDomainJoinPassword')]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" + "dependsOn": [ + "vm", + "vm_desiredStateConfigurationExtension" + ] }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" + "vm_azureDiskEncryptionExtension": { + "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "AzureDiskEncryption" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", + "typeHandlerVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.2'), createObject('value', '1.1')))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "forceUpdateTag": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').forceUpdateTag), createObject('value', '1.0'))]", + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "vm_nvidiaGpuDriverWindowsExtension": { + "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "NvidiaGpuDriverWindows" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.HpcCompute" + }, + "type": { + "value": "NvidiaGpuDriverWindows" + }, + "typeHandlerVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').typeHandlerVersion), createObject('value', '1.4'))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').enableAutomaticUpgrade), createObject('value', false()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureDiskEncryptionExtension" + ] } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the extension." + "description": "The name of the VM." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the extension." + "description": "The resource ID of the VM." }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the Resource Group the extension was created in." + "description": "The name of the resource group the VM was created in." }, "value": "[resourceGroup().name]" }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('vm', '2023-09-01', 'full'), 'identity'), 'principalId'), '')]" + }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('extension', '2022-11-01', 'full').location]" + "value": "[reference('vm', '2023-09-01', 'full').location]" } } } - }, - "dependsOn": [ - "vm", - "vm_aadJoinExtension" - ] + } + } + ] + } + } + }, + { + "condition": "[and(equals(parameters('storageService'), 'ANF'), not(contains(parameters('identityServiceProvider'), 'EntraID')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-ANF-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "accountName": { + "value": "[variables('varAnfAccountName')]" + }, + "capacityPoolName": { + "value": "[variables('varAnfCapacityPoolName')]" + }, + "volumes": { + "value": "[variables('varAnfVolumes')]" + }, + "smbServerNamePrefix": { + "value": "[variables('varAnfSmbServerNamePrefix')]" + }, + "capacityPoolSize": { + "value": "[variables('varAnfCapacityPoolSize')]" + }, + "dnsServers": { + "value": "[parameters('dnsServers')]" + }, + "performance": { + "value": "[parameters('fslogixStoragePerformance')]" + }, + "createFslogixStorage": { + "value": "[parameters('createFslogixDeployment')]" + }, + "createAppAttachStorage": { + "value": "[parameters('createAppAttachDeployment')]" + }, + "storageOuPath": "[if(not(empty(parameters('storageOuPath'))), createObject('value', parameters('storageOuPath')), createObject('value', variables('varDefaultStorageOuPath')))]", + "domainJoinUserName": { + "value": "[parameters('domainJoinUserName')]" + }, + "keyVaultResourceId": { + "value": "[parameters('keyVaultResourceId')]" + }, + "identityDomainName": { + "value": "[parameters('identityDomainName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "storageObjectsRgName": { + "value": "[parameters('storageObjectsRgName')]" + }, + "subId": { + "value": "[parameters('subId')]" + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "6273873211710387488" }, - "vm_desiredStateConfigurationExtension": { - "condition": "[parameters('extensionDSCConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "DesiredStateConfiguration" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Powershell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": "[if(contains(parameters('extensionDSCConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDSCConfig').typeHandlerVersion), createObject('value', '2.77'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDSCConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDSCConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": "[if(contains(parameters('extensionDSCConfig'), 'settings'), createObject('value', parameters('extensionDSCConfig').settings), createObject('value', createObject()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": "[if(contains(parameters('extensionDSCConfig'), 'protectedSettings'), createObject('value', parameters('extensionDSCConfig').protectedSettings), createObject('value', createObject()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] + "name": "AVD LZA storage", + "description": "This module deploys ANF account, capacity pool and volumes", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "subId": { + "type": "string", + "metadata": { + "description": "Workload subscription ID" + } }, - "vm_customScriptExtension": { - "condition": "[parameters('extensionCustomScriptConfig').enabled]", + "storageObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name where to deploy Azure NetApp Files." + } + }, + "accountName": { + "type": "string", + "metadata": { + "description": "ANF account name." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Capacity pool volume name." + } + }, + "createFslogixStorage": { + "type": "bool", + "metadata": { + "description": "Capacity pool volume name." + } + }, + "createAppAttachStorage": { + "type": "bool", + "metadata": { + "description": "Capacity pool volume name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "description": "ANF volumes." + } + }, + "smbServerNamePrefix": { + "type": "string", + "metadata": { + "description": "ANF SMB prefix." + } + }, + "dnsServers": { + "type": "string", + "metadata": { + "description": "DNS servers IPs." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy resources." + } + }, + "identityDomainName": { + "type": "string", + "metadata": { + "description": "Identity domain name." + } + }, + "storageOuPath": { + "type": "string", + "metadata": { + "description": "Organizational Unit (OU) storage path for domain join." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Keyvault resource ID to get credentials from." + } + }, + "domainJoinUserName": { + "type": "string", + "metadata": { + "description": "AVD session host domain join credentials." + } + }, + "performance": { + "type": "string", + "metadata": { + "description": "ANF performance tier." + } + }, + "capacityPoolSize": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "ANF capacity pool size in TiBs." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + } + }, + "variables": { + "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]" + }, + "resources": [ + { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", + "name": "[format('Storage-ANF-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subId'))]", + "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, "name": { - "value": "CustomScriptExtension" + "value": "[parameters('accountName')]" }, - "location": { - "value": "[parameters('location')]" + "adName": { + "value": "[parameters('accountName')]" }, - "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionCustomScriptConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '1.10'), createObject('value', '2.1')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionCustomScriptConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionCustomScriptConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": { - "value": { - "copy": [ - { - "name": "fileUris", - "count": "[length(parameters('extensionCustomScriptConfig').fileData)]", - "input": "[if(contains(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')], 'storageAccountId'), format('{0}?{1}', parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri, listAccountSas(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].storageAccountId, '2019-04-01', variables('accountSasProperties')).accountSasToken), parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri)]" - } - ] + "domainName": { + "value": "[parameters('identityDomainName')]" + }, + "domainJoinUser": { + "value": "[parameters('domainJoinUserName')]" + }, + "domainJoinPassword": { + "reference": { + "keyVault": { + "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))]" + }, + "secretName": "domainJoinUserPassword" } }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" + "domainJoinOU": { + "value": "[format('CN={0}', parameters('storageOuPath'))]" }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" + "dnsServers": { + "value": "[parameters('dnsServers')]" }, - "protectedSettings": { - "value": "[parameters('extensionCustomScriptProtectedSetting')]" + "smbServerNamePrefix": { + "value": "[parameters('smbServerNamePrefix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "capacityPools": { + "value": [ + { + "name": "[parameters('capacityPoolName')]", + "serviceLevel": "[parameters('performance')]", + "size": "[mul(parameters('capacityPoolSize'), 1073741824)]", + "volumes": "[parameters('volumes')]" + } + ] + }, + "tags": { + "value": "[parameters('tags')]" } }, "template": { @@ -26208,1813 +28227,4591 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" + "version": "0.34.44.8038", + "templateHash": "943345456492784680" }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" + "name": "Azure NetApp Files", + "description": "This module deploys an Azure NetApp File." }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", + "definitions": { + "backupVaultType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "backups": { + "type": "array", + "items": { + "$ref": "#/definitions/backupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of backups to create." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the backup vault." + } + } + }, "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + "__bicep_export!": true, + "description": "The type for a backup vault." } }, - "settings": { + "capacityPoolType": { "type": "object", - "defaultValue": {}, + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for the capcity pool." + } + }, + "serviceLevel": { + "type": "string", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "nullable": true, + "metadata": { + "description": "Optional. The pool service level." + } + }, + "size": { + "type": "int", + "metadata": { + "description": "Required. Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104)." + } + }, + "qosType": { + "type": "string", + "allowedValues": [ + "Auto", + "Manual" + ], + "nullable": true, + "metadata": { + "description": "Optional. The qos type of the pool." + } + }, + "volumes": { + "type": "array", + "items": { + "$ref": "#/definitions/volumeType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of volumes to create in the capacity pool." + } + }, + "coolAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "encryptionType": { + "type": "string", + "allowedValues": [ + "Double", + "Single" + ], + "nullable": true, + "metadata": { + "description": "Optional. Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool." + } + } + }, "metadata": { - "description": "Optional. Any object that contains the extension specific settings." + "__bicep_export!": true, + "description": "The type for a capacity pool." } }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, + "snapshotPolicyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the snapshot policy." + } + }, + "dailySchedule": { + "$ref": "#/definitions/dailyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Daily schedule for the snapshot policy." + } + }, + "hourlySchedule": { + "$ref": "#/definitions/hourlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Hourly schedule for the snapshot policy." + } + }, + "monthlySchedule": { + "$ref": "#/definitions/monthlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Monthly schedule for the snapshot policy." + } + }, + "weeklySchedule": { + "$ref": "#/definitions/weeklyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Weekly schedule for the snapshot policy." + } + } + }, "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." + "__bicep_export!": true, + "description": "The type for a snapshot policy." } }, - "supressFailures": { - "type": "bool", - "defaultValue": false, + "backupPolicyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup policy." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location of the backup policy." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "nullable": true, + "minValue": 2, + "maxValue": 1019, + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + "__bicep_export!": true, + "description": "The type for a backup policy." } }, - "enableAutomaticUpgrade": { - "type": "bool", + "_1.backupType": { + "type": "object", + "properties": { + "backupPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the backup policy to link." + } + }, + "policyEnforced": { + "type": "bool", + "metadata": { + "description": "Required. Enable to enforce the policy." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Backup Vault." + } + } + }, "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + "description": "The type for the backup properties.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } } }, - "tags": { + "_1.dataProtectionType": { "type": "object", - "nullable": true, + "properties": { + "replication": { + "$ref": "#/definitions/_1.replicationType", + "nullable": true, + "metadata": { + "description": "Optional. Replication properties." + } + }, + "backup": { + "$ref": "#/definitions/_1.backupType", + "nullable": true, + "metadata": { + "description": "Optional. Backup properties." + } + }, + "snapshot": { + "$ref": "#/definitions/_1.snapshotType", + "nullable": true, + "metadata": { + "description": "Optional. Snapshot properties." + } + } + }, "metadata": { - "description": "Optional. Tags of the resource." + "description": "The type for the data protection properties.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "_1.exportPolicyType": { + "type": "object", "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleIndex": { + "type": "int", + "metadata": { + "description": "Required. Order index." + } + }, + "allowedClients": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." + } + }, + "chownMode": { + "type": "string", + "allowedValues": [ + "Restricted", + "Unrestricted" + ], + "nullable": true, + "metadata": { + "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." + } + }, + "cifs": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allows CIFS protocol." + } + }, + "hasRootAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Has root access to volume." + } + }, + "kerberos5ReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read only access." + } + }, + "kerberos5ReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read and write access." + } + }, + "kerberos5iReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read only access." + } + }, + "kerberos5iReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read and write access." + } + }, + "kerberos5pReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read only access." + } + }, + "kerberos5pReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read and write access." + } + }, + "nfsv3": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." + } + }, + "nfsv41": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." + } + }, + "unixReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Read only access." + } + }, + "unixReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Read and write access." + } + } + } + }, + "metadata": { + "description": "Required. The Export policy rules." + } + } }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_desiredStateConfigurationExtension" - ] - }, - "vm_azureDiskEncryptionExtension": { - "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "AzureDiskEncryption" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.2'), createObject('value', '1.1')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "forceUpdateTag": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').forceUpdateTag), createObject('value', '1.0'))]", - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", "metadata": { - "description": "Required. The name of the extension handler publisher." + "description": "The type for export policy rules.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } } }, - "type": { - "type": "string", + "_1.replicationType": { + "type": "object", + "properties": { + "endpointType": { + "type": "string", + "allowedValues": [ + "dst", + "src" + ], + "metadata": { + "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." + } + }, + "remoteVolumeRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." + } + }, + "remoteVolumeResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." + } + }, + "replicationSchedule": { + "type": "string", + "allowedValues": [ + "_10minutely", + "daily", + "hourly" + ], + "metadata": { + "description": "Required. The replication schedule for the volume." + } + }, + "remotePath": { + "type": "object", + "properties": { + "externalHostName": { + "type": "string", + "metadata": { + "description": "Required. The Path to a ONTAP Host." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Required. The name of a server on the ONTAP Host." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of a volume on the server." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." + } + } + }, "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + "description": "The type for the replication properties.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } } }, - "typeHandlerVersion": { - "type": "string", + "_1.snapshotType": { + "type": "object", + "properties": { + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy to link." + } + } + }, "metadata": { - "description": "Required. Specifies the version of the script handler." + "description": "The type for the snapshot properties.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } } }, - "autoUpgradeMinorVersion": { - "type": "bool", + "backupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + "description": "The type for a backup.", + "__bicep_imported_from!": { + "sourceTemplate": "backup-vault/main.bicep" + } } }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } } }, - "settings": { + "dailyScheduleType": { "type": "object", - "defaultValue": {}, + "properties": { + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The daily snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The daily snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Daily snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, "metadata": { - "description": "Optional. Any object that contains the extension specific settings." + "description": "The type for a daily schedule for the snapshot policy.", + "__bicep_imported_from!": { + "sourceTemplate": "snapshot-policies/main.bicep" + } } }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, + "hourlyScheduleType": { + "type": "object", + "properties": { + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The hourly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Hourly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." + "description": "The type for an hourly schedule for the snapshot policy.", + "__bicep_imported_from!": { + "sourceTemplate": "snapshot-policies/main.bicep" + } } }, - "supressFailures": { - "type": "bool", - "defaultValue": false, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } } }, - "enableAutomaticUpgrade": { - "type": "bool", + "managedIdentityOnlyUserAssignedType": { + "type": "object", + "properties": { + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + "description": "An AVM-aligned type for a managed identity configuration. To be used if only user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } } }, - "tags": { + "monthlyScheduleType": { "type": "object", - "nullable": true, + "properties": { + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Required. Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The monthly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The monthly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Monthly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, "metadata": { - "description": "Optional. Tags of the resource." + "description": "The type for a monthly schedule for the snapshot policy.", + "__bicep_imported_from!": { + "sourceTemplate": "snapshot-policies/main.bicep" + } } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "roleAssignmentType": { + "type": "object", "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } }, - "location": { - "type": "string", + "volumeType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the pool volume." + } + }, + "coolAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "coolnessPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." + } + }, + "coolAccessRetrievalPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." + } + }, + "encryptionKeySource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source of the encryption key." + } + }, + "keyVaultPrivateEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the key vault private endpoint." + } + }, + "dataProtection": { + "$ref": "#/definitions/_1.dataProtectionType", + "nullable": true, + "metadata": { + "description": "Optional. DataProtection type volumes include an object containing details of the replication." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. Zone where the volume will be placed." + } + }, + "serviceLevel": { + "type": "string", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "nullable": true, + "metadata": { + "description": "Optional. The pool service level. Must match the one of the parent capacity pool." + } + }, + "networkFeatures": { + "type": "string", + "allowedValues": [ + "Basic", + "Basic_Standard", + "Standard", + "Standard_Basic" + ], + "nullable": true, + "metadata": { + "description": "Optional. Network feature for the volume." + } + }, + "creationToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." + } + }, + "usageThreshold": { + "type": "int", + "metadata": { + "description": "Required. Maximum storage quota allowed for a file system in bytes." + } + }, + "protocolTypes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Set of protocol types." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." + } + }, + "exportPolicy": { + "$ref": "#/definitions/_1.exportPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Export policy rules." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "smbEncryption": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." + } + }, + "smbContinuouslyAvailable": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." + } + }, + "smbNonBrowsable": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." + } + }, + "kerberosEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Define if a volume is KerberosEnabled." + } + }, + "volumeType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of the volume. DataProtection volumes are used for replication." + } + } + }, "metadata": { - "description": "The location the resource was deployed into." + "description": "The type for a volume in the capacity pool.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/main.bicep" + } + } + }, + "weeklyScheduleType": { + "type": "object", + "properties": { + "day": { + "type": "string", + "allowedValues": [ + "Friday", + "Monday", + "Saturday", + "Sunday", + "Thursday", + "Tuesday", + "Wednesday" + ], + "metadata": { + "description": "Required. The weekly snapshot day." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The weekly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The weekly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Weekly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } }, - "value": "[reference('extension', '2022-11-01', 'full').location]" + "metadata": { + "description": "The type for a weekly schedule for the snapshot policy.", + "__bicep_imported_from!": { + "sourceTemplate": "snapshot-policies/main.bicep" + } + } } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_nvidiaGpuDriverWindowsExtension": { - "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "NvidiaGpuDriverWindows" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.HpcCompute" - }, - "type": { - "value": "NvidiaGpuDriverWindows" - }, - "typeHandlerVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').typeHandlerVersion), createObject('value', '1.4'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').enableAutomaticUpgrade), createObject('value', false()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" }, "parameters": { - "virtualMachineName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + "description": "Required. The name of the NetApp account." } }, - "name": { + "adName": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. The name of the virtual machine extension." + "description": "Optional. Name of the active directory host as part of Kerberos Realm used for Kerberos authentication." } }, - "location": { + "aesEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable AES encryption on the SMB Server." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "domainName": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "", "metadata": { - "description": "Optional. The location the extension is deployed to." + "description": "Optional. Fully Qualified Active Directory DNS Domain Name (e.g. 'contoso.com')." } }, - "publisher": { + "domainJoinUser": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. The name of the extension handler publisher." + "description": "Optional. Required if domainName is specified. Username of Active Directory domain administrator, with permissions to create SMB server machine account in the AD domain." } }, - "type": { + "domainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if domainName is specified. Password of the user specified in domainJoinUser parameter." + } + }, + "domainJoinOU": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + "description": "Optional. Used only if domainName is specified. LDAP Path for the Organization Unit (OU) where SMB Server machine accounts will be created (i.e. 'OU=SecondLevel,OU=FirstLevel')." } }, - "typeHandlerVersion": { + "dnsServers": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. Specifies the version of the script handler." + "description": "Optional. Required if domainName is specified. Comma separated list of DNS server IP addresses (IPv4 only) required for the Active Directory (AD) domain join and SMB authentication operations to succeed." } }, - "autoUpgradeMinorVersion": { + "encryptDCConnections": { "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + "description": "Optional. Specifies whether encryption should be used for communication between SMB server and domain controller (DC). SMB3 only." } }, - "forceUpdateTag": { + "smbServerNamePrefix": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + "description": "Optional. Required if domainName is specified. NetBIOS name of the SMB server. A computer account with this prefix will be registered in the AD and used to mount volumes." } }, - "settings": { - "type": "object", - "defaultValue": {}, + "capacityPools": { + "type": "array", + "items": { + "$ref": "#/definitions/capacityPoolType" + }, + "nullable": true, "metadata": { - "description": "Optional. Any object that contains the extension specific settings." + "description": "Optional. Capacity pools to create." } }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlyUserAssignedType", + "nullable": true, "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." + "description": "Optional. The managed identity definition for this resource." } }, - "supressFailures": { + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "kdcIP": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Kerberos Key Distribution Center (KDC) as part of Kerberos Realm used for Kerberos authentication." + } + }, + "ldapOverTLS": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + "description": "Optional. Specifies whether to use TLS when NFS (with/without Kerberos) and SMB volumes communicate with an LDAP server. A server root CA certificate must be uploaded if enabled (serverRootCACertificate)." } }, - "enableAutomaticUpgrade": { + "ldapSigning": { "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + "description": "Optional. Specifies whether or not the LDAP traffic needs to be signed." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "serverRootCACertificate": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. A server Root certificate is required of ldapOverTLS is enabled." } }, "tags": { "type": "object", "nullable": true, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. Tags for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "backupVault": { + "$ref": "#/definitions/backupVaultType", + "nullable": true, + "metadata": { + "description": "Optional. The netapp backup vault to create & configure." + } + }, + "snapshotPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/snapshotPolicyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The snapshot policies to create." + } + }, + "backupPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/backupPolicyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The backup policies to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "activeDirectoryConnectionProperties": [ + { + "adName": "[if(not(empty(parameters('domainName'))), parameters('adName'), null())]", + "aesEncryption": "[if(not(empty(parameters('domainName'))), parameters('aesEncryption'), false())]", + "username": "[if(not(empty(parameters('domainName'))), parameters('domainJoinUser'), null())]", + "password": "[if(not(empty(parameters('domainName'))), parameters('domainJoinPassword'), null())]", + "domain": "[if(not(empty(parameters('domainName'))), parameters('domainName'), null())]", + "dns": "[if(not(empty(parameters('domainName'))), parameters('dnsServers'), null())]", + "encryptDCConnections": "[if(not(empty(parameters('domainName'))), parameters('encryptDCConnections'), false())]", + "kdcIP": "[if(not(empty(parameters('domainName'))), parameters('kdcIP'), null())]", + "ldapOverTLS": "[if(not(empty(parameters('domainName'))), parameters('ldapOverTLS'), false())]", + "ldapSigning": "[if(not(empty(parameters('domainName'))), parameters('ldapSigning'), false())]", + "serverRootCACertificate": "[if(not(empty(parameters('domainName'))), parameters('serverRootCACertificate'), null())]", + "smbServerName": "[if(not(empty(parameters('domainName'))), parameters('smbServerNamePrefix'), null())]", + "organizationalUnit": "[if(not(empty(parameters('domainJoinOU'))), parameters('domainJoinOU'), null())]" } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None'), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "virtualMachine": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.netapp-netappaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "netAppAccount": { + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "location": "[parameters('location')]", + "properties": { + "activeDirectories": "[if(not(empty(parameters('domainName'))), variables('activeDirectoryConnectionProperties'), null())]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('identity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), createObject('userAssignedIdentity', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/')))), null()), 'keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('keyName', parameters('customerManagedKey').keyName, 'keyVaultResourceId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]), 'Microsoft.KeyVault/vaults', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))), 'keyVaultUri', reference('cMKKeyVault').vaultUri)), null())]" }, - "value": "[parameters('name')]" + "dependsOn": [ + "cMKKeyVault" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." + "netAppAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + "dependsOn": [ + "netAppAccount" + ] }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." + "netAppAccount_roleAssignments": { + "copy": { + "name": "netAppAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, - "value": "[resourceGroup().name]" + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "netAppAccount" + ] }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." + "netAppAccount_backupPolicies": { + "copy": { + "name": "netAppAccount_backupPolicies", + "count": "[length(coalesce(parameters('backupPolicies'), createArray()))]" }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureDiskEncryptionExtension" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the VM." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the VM." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the VM was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[coalesce(tryGet(tryGet(reference('vm', '2023-09-01', 'full'), 'identity'), 'principalId'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('vm', '2023-09-01', 'full').location]" - } - } - } - } - } - ] - } - }, - "dependsOn": [ - "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]", - "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time')))]" - ] - }, - { - "condition": "[parameters('createAvdFslogixDeployment')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-FSLogix-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storagePurpose": { - "value": "fslogix" - }, - "vmLocalUserName": { - "value": "[parameters('avdVmLocalUserName')]" - }, - "fileShareName": { - "value": "[variables('varFslogixFileShareName')]" - }, - "fileShareMultichannel": "[if(equals(parameters('fslogixStoragePerformance'), 'Premium'), createObject('value', true()), createObject('value', false()))]", - "storageSku": { - "value": "[variables('varFslogixStorageSku')]" - }, - "fileShareQuotaSize": { - "value": "[parameters('fslogixFileShareQuotaSize')]" - }, - "storageAccountFqdn": { - "value": "[variables('varFslogixStorageFqdn')]" - }, - "storageAccountName": { - "value": "[variables('varFslogixStorageName')]" - }, - "storageToDomainScript": { - "value": "[variables('varStorageToDomainScript')]" - }, - "storageToDomainScriptUri": { - "value": "[variables('varStorageToDomainScriptUri')]" - }, - "identityServiceProvider": { - "value": "[parameters('avdIdentityServiceProvider')]" - }, - "dscAgentPackageLocation": { - "value": "[variables('varStorageAzureFilesDscAgentPackageLocation')]" - }, - "storageCustomOuPath": { - "value": "[variables('varStorageCustomOuPath')]" - }, - "managementVmName": { - "value": "[variables('varManagementVmName')]" - }, - "deployPrivateEndpoint": { - "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" - }, - "ouStgPath": { - "value": "[variables('varOuStgPath')]" - }, - "managedIdentityClientId": "[if(and(variables('varCreateStorageDeployment'), not(equals(parameters('avdIdentityServiceProvider'), 'EntraID'))), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time'))), '2022-09-01').outputs.managedIdentityStorageClientId.value), createObject('value', ''))]", - "securityPrincipalName": { - "value": "[variables('varSecurityPrincipalName')]" - }, - "domainJoinUserName": { - "value": "[parameters('avdDomainJoinUserName')]" - }, - "wrklKvName": { - "value": "[variables('varWrklKvName')]" - }, - "serviceObjectsRgName": { - "value": "[variables('varServiceObjectsRgName')]" - }, - "identityDomainName": { - "value": "[parameters('identityDomainName')]" - }, - "identityDomainGuid": { - "value": "[parameters('identityDomainGuid')]" - }, - "location": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostLocation')), createObject('value', parameters('avdManagementPlaneLocation')))]", - "storageObjectsRgName": { - "value": "[variables('varStorageObjectsRgName')]" - }, - "privateEndpointSubnetId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName'))), createObject('value', parameters('existingVnetPrivateEndpointSubnetResourceId')))]", - "vmsSubnetId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", - "vnetPrivateDnsZoneFilesId": "[if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.azureFilesDnsZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneFilesId')))]", - "workloadSubsId": { - "value": "[parameters('avdWorkloadSubsId')]" - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]", - "alaWorkspaceResourceId": "[if(parameters('avdDeployMonitoring'), if(parameters('deployAlaWorkspace'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.avdAlaWorkspaceResourceId.value), createObject('value', parameters('alaExistingWorkspaceResourceId'))), createObject('value', ''))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "8619049573819403821" - }, - "name": "AVD LZA storage", - "description": "This module deploys storage account, azure files. domain join logic", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "workloadSubsId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "storageObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group Name for Azure Files." - } - }, - "identityServiceProvider": { - "type": "string", - "metadata": { - "description": "Required, The service providing domain services for Azure Virtual Desktop." - } - }, - "serviceObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group Name for management VM." - } - }, - "storageAccountName": { - "type": "string", - "metadata": { - "description": "Storage account name." - } - }, - "fileShareName": { - "type": "string", - "metadata": { - "description": "Storage account file share name." - } - }, - "privateEndpointSubnetId": { - "type": "string", - "metadata": { - "description": "Private endpoint subnet ID." - } - }, - "vmsSubnetId": { - "type": "string", - "metadata": { - "description": "VMs subnet ID." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy resources." - } - }, - "fileShareMultichannel": { - "type": "bool", - "metadata": { - "description": "File share SMB multichannel." - } - }, - "identityDomainName": { - "type": "string", - "metadata": { - "description": "Identity domain name." - } - }, - "identityDomainGuid": { - "type": "string", - "metadata": { - "description": "AD domain GUID." - } - }, - "wrklKvName": { - "type": "string", - "metadata": { - "description": "Keyvault name to get credentials from." - } - }, - "domainJoinUserName": { - "type": "string", - "metadata": { - "description": "AVD session host domain join credentials." - } - }, - "vmLocalUserName": { - "type": "string", - "metadata": { - "description": "AVD session host local admin credentials." - } - }, - "storageSku": { - "type": "string", - "metadata": { - "description": "Azure Files storage account SKU." - } - }, - "fileShareQuotaSize": { - "type": "int", - "metadata": { - "description": "*Azure File share quota" - } - }, - "vnetPrivateDnsZoneFilesId": { - "type": "string", - "metadata": { - "description": "Use Azure private DNS zones for private endpoints." - } - }, - "storageToDomainScript": { - "type": "string", - "metadata": { - "description": "Script name for adding storage account to Active Directory." - } - }, - "storageToDomainScriptUri": { - "type": "string", - "metadata": { - "description": "URI for the script for adding the storage account to Active Directory." - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "managementVmName": { - "type": "string", - "metadata": { - "description": "Name for management virtual machine. for tools and to join Azure Files to domain." - } - }, - "deployPrivateEndpoint": { - "type": "bool", - "metadata": { - "description": "Optional. AVD Accelerator will deploy with private endpoints by default." - } - }, - "alaWorkspaceResourceId": { - "type": "string", - "metadata": { - "description": "Log analytics workspace for diagnostic logs." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - }, - "storagePurpose": { - "type": "string", - "metadata": { - "description": "Sets purpose of the storage account." - } - }, - "dscAgentPackageLocation": { - "type": "string", - "metadata": { - "description": "Sets location of DSC Agent." - } - }, - "storageCustomOuPath": { - "type": "string", - "metadata": { - "description": "Custom OU path for storage." - } - }, - "ouStgPath": { - "type": "string", - "metadata": { - "description": "OU Storage Path" - } - }, - "managedIdentityClientId": { - "type": "string", - "metadata": { - "description": "Managed Identity Client ID" - } - }, - "securityPrincipalName": { - "type": "string", - "metadata": { - "description": "Identity name array to grant RBAC role to access AVD application group and NTFS permissions." - } - }, - "storageAccountFqdn": { - "type": "string", - "metadata": { - "description": "storage account FDQN." - } - } - }, - "variables": { - "varAzureCloudName": "[environment().name]", - "varWrklStoragePrivateEndpointName": "[format('pe-{0}-file', parameters('storageAccountName'))]", - "varSecurityPrincipalName": "[if(not(empty(parameters('securityPrincipalName'))), parameters('securityPrincipalName'), 'none')]", - "varAdminUserName": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('vmLocalUserName'), parameters('domainJoinUserName'))]", - "varStorageToDomainScriptArgs": "[format('-DscPath {0} -StorageAccountName {1} -StorageAccountRG {2} -StoragePurpose {3} -DomainName {4} -IdentityServiceProvider {5} -AzureCloudEnvironment {6} -SubscriptionId {7} -AdminUserName {8} -CustomOuPath {9} -OUName {10} -ShareName {11} -ClientId {12} -SecurityPrincipalName \"{13}\" -StorageAccountFqdn {14} ', parameters('dscAgentPackageLocation'), parameters('storageAccountName'), parameters('storageObjectsRgName'), parameters('storagePurpose'), parameters('identityDomainName'), parameters('identityServiceProvider'), variables('varAzureCloudName'), parameters('workloadSubsId'), variables('varAdminUserName'), parameters('storageCustomOuPath'), parameters('ouStgPath'), parameters('fileShareName'), parameters('managedIdentityClientId'), variables('varSecurityPrincipalName'), parameters('storageAccountFqdn'))]", - "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]" - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('storageAccountName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "skuName": { - "value": "[parameters('storageSku')]" - }, - "allowBlobPublicAccess": { - "value": false - }, - "publicNetworkAccess": "[if(parameters('deployPrivateEndpoint'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "kind": "[if(or(equals(parameters('storageSku'), 'Premium_LRS'), equals(parameters('storageSku'), 'Premium_ZRS')), createObject('value', 'FileStorage'), createObject('value', 'StorageV2'))]", - "largeFileSharesState": "[if(or(equals(parameters('storageSku'), 'Standard_LRS'), equals(parameters('storageSku'), 'Standard_ZRS')), createObject('value', 'Enabled'), createObject('value', 'Disabled'))]", - "azureFilesIdentityBasedAuthentication": "[if(not(equals(parameters('identityServiceProvider'), 'EntraID')), createObject('value', createObject('directoryServiceOptions', if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDS', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), 'AADKERB', 'none')), 'activeDirectoryProperties', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), createObject('domainGuid', parameters('identityDomainGuid'), 'domainName', parameters('identityDomainName')), createObject()))), createObject('value', null()))]", - "accessTier": { - "value": "Hot" - }, - "networkAcls": "[if(parameters('deployPrivateEndpoint'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', parameters('vmsSubnetId'), 'action', 'Allow')), 'ipRules', createArray())))]", - "fileServices": { - "value": { - "shares": [ - { - "name": "[parameters('fileShareName')]", - "shareQuota": "[mul(parameters('fileShareQuotaSize'), 100)]" - } - ], - "protocolSettings": "[if(parameters('fileShareMultichannel'), createObject('smb', createObject('multichannel', createObject('enabled', parameters('fileShareMultichannel')))), createObject())]", - "diagnosticSettings": "[variables('varDiagnosticSettings')]" - } - }, - "privateEndpoints": "[if(parameters('deployPrivateEndpoint'), createObject('value', createArray(createObject('name', variables('varWrklStoragePrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointSubnetId'), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklStoragePrivateEndpointName')), 'service', 'file', 'privateDnsZoneGroupName', split(parameters('vnetPrivateDnsZoneFilesId'), '/')[8], 'privateDnsZoneResourceIds', createArray(parameters('vnetPrivateDnsZoneFilesId'))))), createObject('value', createArray()))]", - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "11421348829572406411" - }, - "name": "Storage Accounts", - "description": "This module deploys a Storage Account.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "managedIdentitiesType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } - } - }, - "nullable": true - }, - "networkAclsType": { - "type": "object", - "properties": { - "resourceAccessRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "metadata": { - "description": "Required. The ID of the tenant in which the resource resides in." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." - } - }, - "bypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "AzureServices, Logging", - "AzureServices, Logging, Metrics", - "AzureServices, Metrics", - "Logging", - "Logging, Metrics", - "Metrics", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." - } - }, - "virtualNetworkRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the virtual network rules." - } - }, - "ipRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the IP ACL rules." - } - }, - "defaultAction": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the default action of allow or deny when no other rules match." - } - } - } - }, - "privateEndpointType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-backupPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'name')]" + }, + "dailyBackupsToKeep": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'dailyBackupsToKeep')]" }, + "monthlyBackupsToKeep": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'monthlyBackupsToKeep')]" + }, + "weeklyBackupsToKeep": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'weeklyBackupsToKeep')]" + }, + "enabled": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'enabled')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'location'), parameters('location'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "16432727764202874682" + }, + "name": "Azure NetApp Files Backup Policy", + "description": "This module deploys a Backup Policy for Azure NetApp File." + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "backupPolicy", + "metadata": { + "description": "Optional. The name of the backup policy." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the backup policy." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "defaultValue": 2, + "minValue": 2, + "maxValue": 1019, + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "enabled": "[parameters('enabled')]", + "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", + "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]", + "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the backup Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Backup Policy was created in." + }, + "value": "[resourceGroup().name]" + } } } - } + }, + "dependsOn": [ + "netAppAccount" + ] }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "type": "object", + "netAppAccount_snapshotPolicies": { + "copy": { + "name": "netAppAccount_snapshotPolicies", + "count": "[length(coalesce(parameters('snapshotPolicies'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-snapshotPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "name": { - "type": "string", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "snapEnabled": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'snapEnabled')]" + }, + "dailySchedule": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'dailySchedule')]" + }, + "hourlySchedule": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'hourlySchedule')]" + }, + "monthlySchedule": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'monthlySchedule')]" + }, + "weeklySchedule": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'weeklySchedule')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "15408772009434991440" + }, + "name": "Azure NetApp Files Snapshot Policy", + "description": "This module deploys a Snapshot Policy for an Azure NetApp File." + }, + "definitions": { + "dailyScheduleType": { + "type": "object", + "properties": { + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The daily snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The daily snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Daily snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a daily schedule for the snapshot policy." + } + }, + "hourlyScheduleType": { + "type": "object", + "properties": { + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The hourly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Hourly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an hourly schedule for the snapshot policy." + } + }, + "weeklyScheduleType": { + "type": "object", + "properties": { + "day": { + "type": "string", + "allowedValues": [ + "Friday", + "Monday", + "Saturday", + "Sunday", + "Thursday", + "Tuesday", + "Wednesday" + ], + "metadata": { + "description": "Required. The weekly snapshot day." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The weekly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The weekly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Weekly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a weekly schedule for the snapshot policy." + } + }, + "monthlyScheduleType": { + "type": "object", + "properties": { + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Required. Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The monthly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The monthly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Monthly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a monthly schedule for the snapshot policy." + } + } + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "snapshotPolicy", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the snapshot policy." + } + }, + "hourlySchedule": { + "$ref": "#/definitions/hourlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for hourly snapshots." + } + }, + "dailySchedule": { + "$ref": "#/definitions/dailyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for daily snapshots." + } + }, + "monthlySchedule": { + "$ref": "#/definitions/monthlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for monthly snapshots." + } + }, + "weeklySchedule": { + "$ref": "#/definitions/weeklyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for weekly snapshots." + } + }, + "snapEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether the snapshot policy is enabled." + } + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "snapshotPolicies": { + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "enabled": "[parameters('snapEnabled')]", + "dailySchedule": "[parameters('dailySchedule')]", + "hourlySchedule": "[parameters('hourlySchedule')]", + "monthlySchedule": "[parameters('monthlySchedule')]", + "weeklySchedule": "[parameters('weeklySchedule')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the snapshot Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Snapshot was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "netAppAccount" + ] + }, + "netAppAccount_backupVault": { + "condition": "[not(empty(parameters('backupVault')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-BackupVault', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(parameters('backupVault'), 'name')]" + }, + "location": { + "value": "[coalesce(tryGet(parameters('backupVault'), 'location'), parameters('location'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12673365749567452459" + }, + "name": "Azure NetApp Files Volume Backup Vault", + "description": "This module deploys a NetApp Files Backup Vault." + }, + "definitions": { + "backupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backup." + } + } + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "vault", + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the backup vault." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backups": { + "type": "array", + "items": { + "$ref": "#/definitions/backupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of backups to create." + } + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backupVault": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": {} + }, + "backupVault_backups": { + "copy": { + "name": "backupVault_backups", + "count": "[length(coalesce(parameters('backups'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANF-Backup-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "backupVaultName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'name')]" + }, + "label": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'label')]" + }, + "snapshotName": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'snapshotName')]" + }, + "volumeName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].volumeName]" + }, + "capacityPoolName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].capacityPoolName]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "2218257802133394577" + }, + "name": "Azure NetApp Files Volume Backup", + "description": "This module deploys a backup of a NetApp Files Volume." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "backup", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent backup vault. Required if the template is used in a standalone deployment." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "resources": { + "netAppAccount::remoteCapacityPool::volume": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + }, + "netAppAccount::backupVault": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupVaultName'))]" + }, + "netAppAccount::remoteCapacityPool": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" + }, + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backup": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults/backups", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]", + "properties": { + "label": "[parameters('label')]", + "snapshotName": "[parameters('snapshotName')]", + "volumeResourceId": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults/backups', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "backupVault" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup vault." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup vault." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup vault was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('backupVault', '2024-07-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "netAppAccount" + ] + }, + "netAppAccount_capacityPools": { + "copy": { + "name": "netAppAccount_capacityPools", + "count": "[length(coalesce(parameters('capacityPools'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-CapPool-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('capacityPools'), createArray())[copyIndex()].name]" + }, + "size": { + "value": "[coalesce(parameters('capacityPools'), createArray())[copyIndex()].size]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "serviceLevel": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'serviceLevel'), 'Standard')]" + }, + "qosType": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'qosType'), 'Auto')]" + }, + "volumes": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'volumes'), createArray())]" + }, + "coolAccess": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'coolAccess'), false())]" + }, + "roleAssignments": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'roleAssignments'), createArray())]" + }, + "encryptionType": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'encryptionType'), 'Single')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "8976617662375535030" + }, + "name": "Azure NetApp Files Capacity Pools", + "description": "This module deploys an Azure NetApp Files Capacity Pool." + }, + "definitions": { + "volumeType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the pool volume." + } + }, + "coolAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "coolnessPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." + } + }, + "coolAccessRetrievalPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." + } + }, + "encryptionKeySource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source of the encryption key." + } + }, + "keyVaultPrivateEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the key vault private endpoint." + } + }, + "dataProtection": { + "$ref": "#/definitions/dataProtectionType", + "nullable": true, + "metadata": { + "description": "Optional. DataProtection type volumes include an object containing details of the replication." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. Zone where the volume will be placed." + } + }, + "serviceLevel": { + "type": "string", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "nullable": true, + "metadata": { + "description": "Optional. The pool service level. Must match the one of the parent capacity pool." + } + }, + "networkFeatures": { + "type": "string", + "allowedValues": [ + "Basic", + "Basic_Standard", + "Standard", + "Standard_Basic" + ], + "nullable": true, + "metadata": { + "description": "Optional. Network feature for the volume." + } + }, + "creationToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." + } + }, + "usageThreshold": { + "type": "int", + "metadata": { + "description": "Required. Maximum storage quota allowed for a file system in bytes." + } + }, + "protocolTypes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Set of protocol types." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." + } + }, + "exportPolicy": { + "$ref": "#/definitions/exportPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Export policy rules." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "smbEncryption": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." + } + }, + "smbContinuouslyAvailable": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." + } + }, + "smbNonBrowsable": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." + } + }, + "kerberosEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Define if a volume is KerberosEnabled." + } + }, + "volumeType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of the volume. DataProtection volumes are used for replication." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a volume in the capacity pool." + } + }, + "_1.backupType": { + "type": "object", + "properties": { + "backupPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the backup policy to link." + } + }, + "policyEnforced": { + "type": "bool", + "metadata": { + "description": "Required. Enable to enforce the policy." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Backup Vault." + } + } + }, + "metadata": { + "description": "The type for the backup properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "_1.replicationType": { + "type": "object", + "properties": { + "endpointType": { + "type": "string", + "allowedValues": [ + "dst", + "src" + ], + "metadata": { + "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." + } + }, + "remoteVolumeRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." + } + }, + "remoteVolumeResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." + } + }, + "replicationSchedule": { + "type": "string", + "allowedValues": [ + "_10minutely", + "daily", + "hourly" + ], + "metadata": { + "description": "Required. The replication schedule for the volume." + } + }, + "remotePath": { + "type": "object", + "properties": { + "externalHostName": { + "type": "string", + "metadata": { + "description": "Required. The Path to a ONTAP Host." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Required. The name of a server on the ONTAP Host." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of a volume on the server." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." + } + } + }, + "metadata": { + "description": "The type for the replication properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "_1.snapshotType": { + "type": "object", + "properties": { + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy to link." + } + } + }, + "metadata": { + "description": "The type for the snapshot properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "dataProtectionType": { + "type": "object", + "properties": { + "replication": { + "$ref": "#/definitions/_1.replicationType", + "nullable": true, + "metadata": { + "description": "Optional. Replication properties." + } + }, + "backup": { + "$ref": "#/definitions/_1.backupType", + "nullable": true, + "metadata": { + "description": "Optional. Backup properties." + } + }, + "snapshot": { + "$ref": "#/definitions/_1.snapshotType", + "nullable": true, + "metadata": { + "description": "Optional. Snapshot properties." + } + } + }, + "metadata": { + "description": "The type for the data protection properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "exportPolicyType": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleIndex": { + "type": "int", + "metadata": { + "description": "Required. Order index." + } + }, + "allowedClients": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." + } + }, + "chownMode": { + "type": "string", + "allowedValues": [ + "Restricted", + "Unrestricted" + ], + "nullable": true, + "metadata": { + "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." + } + }, + "cifs": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allows CIFS protocol." + } + }, + "hasRootAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Has root access to volume." + } + }, + "kerberos5ReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read only access." + } + }, + "kerberos5ReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read and write access." + } + }, + "kerberos5iReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read only access." + } + }, + "kerberos5iReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read and write access." + } + }, + "kerberos5pReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read only access." + } + }, + "kerberos5pReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read and write access." + } + }, + "nfsv3": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." + } + }, + "nfsv41": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." + } + }, + "unixReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Read only access." + } + }, + "unixReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Read and write access." + } + } + } + }, + "metadata": { + "description": "Required. The Export policy rules." + } + } + }, + "metadata": { + "description": "The type for export policy rules.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + } + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for all resources." + } + }, + "serviceLevel": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "metadata": { + "description": "Optional. The pool service level." + } + }, + "size": { + "type": "int", + "metadata": { + "description": "Required. Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104)." + } + }, + "qosType": { + "type": "string", + "defaultValue": "Auto", + "allowedValues": [ + "Auto", + "Manual" + ], + "metadata": { + "description": "Optional. The qos type of the pool." + } + }, + "volumes": { + "type": "array", + "items": { + "$ref": "#/definitions/volumeType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of volumes to create in the capacity pool." + } + }, + "coolAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "encryptionType": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Double", + "Single" + ], + "metadata": { + "description": "Optional. Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "capacityPool": { + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "serviceLevel": "[parameters('serviceLevel')]", + "size": "[parameters('size')]", + "qosType": "[parameters('qosType')]", + "coolAccess": "[parameters('coolAccess')]", + "encryptionType": "[parameters('encryptionType')]" + } + }, + "capacityPool_roleAssignments": { + "copy": { + "name": "capacityPool_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}/capacityPools/{1}', parameters('netAppAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts/capacityPools', parameters('netAppAccountName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "capacityPool" + ] + }, + "capacityPool_volumes": { + "copy": { + "name": "capacityPool_volumes", + "count": "[length(coalesce(parameters('volumes'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Vol-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "capacityPoolName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "serviceLevel": { + "value": "[parameters('serviceLevel')]" + }, + "creationToken": { + "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'creationToken'), coalesce(parameters('volumes'), createArray())[copyIndex()].name)]" + }, + "usageThreshold": { + "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].usageThreshold]" + }, + "protocolTypes": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'protocolTypes')]" + }, + "subnetResourceId": { + "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].subnetResourceId]" + }, + "exportPolicy": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'exportPolicy')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "networkFeatures": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'networkFeatures')]" + }, + "zones": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'zones')]" + }, + "coolAccess": { + "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolAccess'), false())]" + }, + "coolAccessRetrievalPolicy": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolAccessRetrievalPolicy')]" + }, + "coolnessPeriod": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolnessPeriod')]" + }, + "encryptionKeySource": { + "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'encryptionKeySource'), 'Microsoft.NetApp')]" + }, + "keyVaultPrivateEndpointResourceId": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'keyVaultPrivateEndpointResourceId')]" + }, + "dataProtection": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'dataProtection')]" + }, + "kerberosEnabled": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'kerberosEnabled')]" + }, + "smbContinuouslyAvailable": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbContinuouslyAvailable')]" + }, + "smbEncryption": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbEncryption')]" + }, + "smbNonBrowsable": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbNonBrowsable')]" + }, + "volumeType": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'volumeType')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "17068369293044189585" + }, + "name": "Azure NetApp Files Capacity Pool Volumes", + "description": "This module deploys an Azure NetApp Files Capacity Pool Volume." + }, + "definitions": { + "dataProtectionType": { + "type": "object", + "properties": { + "replication": { + "$ref": "#/definitions/replicationType", + "nullable": true, + "metadata": { + "description": "Optional. Replication properties." + } + }, + "backup": { + "$ref": "#/definitions/backupType", + "nullable": true, + "metadata": { + "description": "Optional. Backup properties." + } + }, + "snapshot": { + "$ref": "#/definitions/snapshotType", + "nullable": true, + "metadata": { + "description": "Optional. Snapshot properties." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data protection properties." + } + }, + "replicationType": { + "type": "object", + "properties": { + "endpointType": { + "type": "string", + "allowedValues": [ + "dst", + "src" + ], + "metadata": { + "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." + } + }, + "remoteVolumeRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." + } + }, + "remoteVolumeResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." + } + }, + "replicationSchedule": { + "type": "string", + "allowedValues": [ + "_10minutely", + "daily", + "hourly" + ], + "metadata": { + "description": "Required. The replication schedule for the volume." + } + }, + "remotePath": { + "type": "object", + "properties": { + "externalHostName": { + "type": "string", + "metadata": { + "description": "Required. The Path to a ONTAP Host." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Required. The name of a server on the ONTAP Host." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of a volume on the server." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." + } + } + }, + "metadata": { + "description": "The type for the replication properties." + } + }, + "backupType": { + "type": "object", + "properties": { + "backupPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the backup policy to link." + } + }, + "policyEnforced": { + "type": "bool", + "metadata": { + "description": "Required. Enable to enforce the policy." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Backup Vault." + } + } + }, + "metadata": { + "description": "The type for the backup properties." + } + }, + "snapshotType": { + "type": "object", + "properties": { + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy to link." + } + } + }, + "metadata": { + "description": "The type for the snapshot properties." + } + }, + "exportPolicyType": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleIndex": { + "type": "int", + "metadata": { + "description": "Required. Order index." + } + }, + "allowedClients": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." + } + }, + "chownMode": { + "type": "string", + "allowedValues": [ + "Restricted", + "Unrestricted" + ], + "nullable": true, + "metadata": { + "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." + } + }, + "cifs": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allows CIFS protocol." + } + }, + "hasRootAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Has root access to volume." + } + }, + "kerberos5ReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read only access." + } + }, + "kerberos5ReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read and write access." + } + }, + "kerberos5iReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read only access." + } + }, + "kerberos5iReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read and write access." + } + }, + "kerberos5pReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read only access." + } + }, + "kerberos5pReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read and write access." + } + }, + "nfsv3": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." + } + }, + "nfsv41": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." + } + }, + "unixReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Read only access." + } + }, + "unixReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Read and write access." + } + } + } + }, + "metadata": { + "description": "Required. The Export policy rules." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for export policy rules." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + } + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent capacity pool. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the pool volume." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "coolAccess": { + "type": "bool", + "metadata": { + "description": "Required. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "coolnessPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." + } + }, + "coolAccessRetrievalPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." + } + }, + "encryptionKeySource": { + "type": "string", + "metadata": { + "description": "Required. The source of the encryption key." + } + }, + "keyVaultPrivateEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the key vault private endpoint." + } + }, + "volumeType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of the volume. DataProtection volumes are used for replication." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. Zone where the volume will be placed." + } + }, + "serviceLevel": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "metadata": { + "description": "Optional. The pool service level. Must match the one of the parent capacity pool." + } + }, + "networkFeatures": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Basic_Standard", + "Standard", + "Standard_Basic" + ], + "metadata": { + "description": "Optional. Network feature for the volume." + } + }, + "creationToken": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." + } + }, + "usageThreshold": { + "type": "int", + "metadata": { + "description": "Required. Maximum storage quota allowed for a file system in bytes." + } + }, + "protocolTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Set of protocol types." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." + } + }, + "exportPolicy": { + "$ref": "#/definitions/exportPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. The export policy rules." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "dataProtection": { + "$ref": "#/definitions/dataProtectionType", + "nullable": true, + "metadata": { + "description": "Optional. DataProtection type volumes include an object containing details of the replication." + } + }, + "smbEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." + } + }, + "smbContinuouslyAvailable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." + } + }, + "smbNonBrowsable": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." + } + }, + "kerberosEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Define if a volume is KerberosEnabled." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "remoteCapacityPoolName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], '')]", + "remoteNetAppName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], '')]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "netAppAccount::capacityPool": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" + }, + "netAppAccount::backupVault": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))]" + }, + "netAppAccount::backupPolicy": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName'))]" + }, + "netAppAccount::snapshotPolicy": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'snapshot')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))]" + }, + "remoteNetAppAccount::remoteCapacityPool::remoteVolume": { + "condition": "[and(and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName'))))), not(empty(tryGet(parameters('dataProtection'), 'replication'))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}/{2}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/')))]" + }, + "remoteNetAppAccount::remoteCapacityPool": { + "condition": "[and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName')))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10])]" + }, + "vnet::subnet": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/')))]" + }, + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "keyVaultPrivateEndpoint": { + "condition": "[not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp'))]", + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/'))]" + }, + "remoteNetAppAccount": { + "condition": "[and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName'))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8]]" + }, + "vnet": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", + "name": "[split(parameters('subnetResourceId'), '/')[8]]" + }, + "volume": { + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": "[shallowMerge(createArray(createObject('coolAccess', parameters('coolAccess'), 'coolAccessRetrievalPolicy', parameters('coolAccessRetrievalPolicy'), 'coolnessPeriod', parameters('coolnessPeriod'), 'encryptionKeySource', parameters('encryptionKeySource')), if(not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp')), createObject('keyVaultPrivateEndpointResourceId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2], split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]), 'Microsoft.Network/privateEndpoints', last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/')))), createObject()), if(not(empty(parameters('volumeType'))), createObject('volumeType', parameters('volumeType')), createObject()), createObject('dataProtection', if(not(empty(parameters('dataProtection'))), createObject('replication', if(not(empty(tryGet(parameters('dataProtection'), 'replication'))), createObject('endpointType', tryGet(parameters('dataProtection'), 'replication', 'endpointType'), 'remoteVolumeRegion', if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]), 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/'))), null()), 'remoteVolumeResourceId', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'replicationSchedule', tryGet(parameters('dataProtection'), 'replication', 'replicationSchedule'), 'remotePath', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remotePath')), createObject()), 'backup', if(not(empty(tryGet(parameters('dataProtection'), 'backup'))), createObject('backupPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName')), 'policyEnforced', coalesce(tryGet(parameters('dataProtection'), 'backup', 'policyEnforced'), false()), 'backupVaultId', resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))), createObject()), 'snapshot', if(not(empty(tryGet(parameters('dataProtection'), 'snapshot'))), createObject('snapshotPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))), createObject())), null()), 'networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('subnetResourceId'), '/')[2], split(parameters('subnetResourceId'), '/')[4]), 'Microsoft.Network/virtualNetworks/subnets', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/'))), 'exportPolicy', parameters('exportPolicy'), 'smbContinuouslyAvailable', parameters('smbContinuouslyAvailable'), 'smbEncryption', parameters('smbEncryption'), 'smbNonBrowsable', parameters('smbNonBrowsable'), 'kerberosEnabled', parameters('kerberosEnabled'))))]", + "zones": "[map(parameters('zones'), lambda('zone', format('{0}', lambdaVariables('zone'))))]" + }, + "volume_roleAssignments": { + "copy": { + "name": "volume_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}/capacityPools/{1}/volumes/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "volume" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Volume." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the Volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Volume was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('volume', '2024-07-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "capacityPool" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Capacity Pool." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Capacity Pool." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools', parameters('netAppAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Capacity Pool was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('capacityPool', '2024-07-01', 'full').location]" + }, + "volumeResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the volume created in the capacity pool." + }, + "copy": { + "count": "[length(coalesce(parameters('volumes'), createArray()))]", + "input": "[reference(format('capacityPool_volumes[{0}]', copyIndex())).outputs.resourceId.value]" + } + } + } + } + }, + "dependsOn": [ + "netAppAccount", + "netAppAccount_backupPolicies", + "netAppAccount_backupVault", + "netAppAccount_snapshotPolicies" + ] + }, + "netAppAccount_backupVaultBackups": { + "condition": "[not(empty(tryGet(parameters('backupVault'), 'backups')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-BackupVault-Backups', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(parameters('backupVault'), 'name')]" + }, + "backups": { + "value": "[tryGet(parameters('backupVault'), 'backups')]" + }, + "location": { + "value": "[coalesce(tryGet(parameters('backupVault'), 'location'), parameters('location'))]" } }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12673365749567452459" + }, + "name": "Azure NetApp Files Volume Backup Vault", + "description": "This module deploys a NetApp Files Backup Vault." + }, + "definitions": { + "backupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backup." + } + } + }, + "parameters": { + "name": { "type": "string", + "defaultValue": "vault", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Optional. The name of the backup vault." } }, - "memberName": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Optional. Location of the backup vault." } }, - "privateIPAddress": { + "netAppAccountName": { "type": "string", "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backups": { + "type": "array", + "items": { + "$ref": "#/definitions/backupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of backups to create." } } }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backupVault": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": {} + }, + "backupVault_backups": { + "copy": { + "name": "backupVault_backups", + "count": "[length(coalesce(parameters('backups'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANF-Backup-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "backupVaultName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'name')]" + }, + "label": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'label')]" + }, + "snapshotName": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'snapshotName')]" + }, + "volumeName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].volumeName]" + }, + "capacityPoolName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].capacityPoolName]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "2218257802133394577" + }, + "name": "Azure NetApp Files Volume Backup", + "description": "This module deploys a backup of a NetApp Files Volume." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "backup", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent backup vault. Required if the template is used in a standalone deployment." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "resources": { + "netAppAccount::remoteCapacityPool::volume": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + }, + "netAppAccount::backupVault": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupVaultName'))]" + }, + "netAppAccount::remoteCapacityPool": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" + }, + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backup": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults/backups", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]", + "properties": { + "label": "[parameters('label')]", + "snapshotName": "[parameters('snapshotName')]", + "volumeResourceId": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults/backups', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "backupVault" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup vault." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup vault." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup vault was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('backupVault', '2024-07-01', 'full').location]" + } } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "dependsOn": [ + "netAppAccount", + "netAppAccount_capacityPools" + ] } }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the NetApp account." + }, + "value": "[parameters('name')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - } - }, - "nullable": true - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the NetApp account." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the NetApp account was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('netAppAccount', '2024-07-01', 'full').location]" + }, + "capacityPoolResourceIds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resourceId": { + "type": "string" + }, + "volumeResourceIds": { + "type": "array", + "items": { + "type": "string" + } } } + }, + "metadata": { + "description": "The resource IDs of the created capacity pools & their volumes." + }, + "copy": { + "count": "[length(coalesce(parameters('capacityPools'), createArray()))]", + "input": { + "resourceId": "[reference(format('netAppAccount_capacityPools[{0}]', copyIndex())).outputs.resourceId.value]", + "volumeResourceIds": "[reference(format('netAppAccount_capacityPools[{0}]', copyIndex())).outputs.volumeResourceIds.value]" + } } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." } } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. Name of the Storage Account. Must be lower-case." } - }, - "location": { + } + ], + "outputs": { + "anfFslogixVolumeResourceId": { "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } + "value": "[if(parameters('createFslogixStorage'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.capacityPoolResourceIds.value[0].volumeResourceIds[0], '')]" }, - "kind": { + "anfAppAttachVolumeResourceId": { "type": "string", - "defaultValue": "StorageV2", - "allowedValues": [ - "Storage", - "StorageV2", - "BlobStorage", - "FileStorage", - "BlockBlobStorage" - ], - "metadata": { - "description": "Optional. Type of Storage Account to create." - } + "value": "[if(and(parameters('createAppAttachStorage'), parameters('createFslogixStorage')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.capacityPoolResourceIds.value[1].volumeResourceIds[1], if(and(parameters('createAppAttachStorage'), not(parameters('createFslogixStorage'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.capacityPoolResourceIds.value[0].volumeResourceIds[0], ''))]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]" + ] + }, + { + "condition": "[equals(parameters('storageService'), 'ANF')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Get-ANF-SMB-Server-FQDN-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppVolumeResourceId": "[if(and(parameters('createFslogixDeployment'), equals(parameters('storageService'), 'ANF')), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfFslogixVolumeResourceId.value), if(and(parameters('createAppAttachDeployment'), equals(parameters('storageService'), 'ANF')), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfAppAttachVolumeResourceId.value), createObject('value', '')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "1092509597594508559" }, - "skuName": { + "name": "AVD LZA storage ANF volume SMB server FQDN", + "description": "This module returns the SMB server FQDN of an ANF volume.", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "netAppVolumeResourceId": { + "type": "string" + } + }, + "resources": [], + "outputs": { + "anfSmbServerFqdn": { "type": "string", - "defaultValue": "Standard_GRS", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS", - "Standard_RAGRS", - "Standard_ZRS", - "Premium_LRS", - "Premium_ZRS", - "Standard_GZRS", - "Standard_RAGZRS" - ], - "metadata": { - "description": "Optional. Storage Account Sku Name." - } + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('netAppVolumeResourceId'), '/')[2], split(parameters('netAppVolumeResourceId'), '/')[4]), 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', split(parameters('netAppVolumeResourceId'), '/')[8], split(parameters('netAppVolumeResourceId'), '/')[10], last(split(parameters('netAppVolumeResourceId'), '/'))), '2024-09-01').mountTargets[0].smbServerFqdn]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time')))]" + ] + }, + { + "condition": "[and(parameters('createFslogixDeployment'), not(equals(parameters('storageService'), 'ANF')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-FSLogix-ST-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storagePurpose": { + "value": "fslogix" + }, + "vmLocalUserName": { + "value": "[parameters('vmLocalUserName')]" + }, + "fileShareName": { + "value": "[variables('varFslogixFileShareName')]" + }, + "fileShareMultichannel": "[if(equals(variables('varFslogixStoragePerformance'), 'Premium'), createObject('value', true()), createObject('value', false()))]", + "storageSku": { + "value": "[variables('varFslogixStorageSku')]" + }, + "fileShareQuotaSize": { + "value": "[parameters('fslogixFileShareQuotaSize')]" + }, + "storageAccountFqdn": { + "value": "[variables('varFslogixStorageFqdn')]" + }, + "storageAccountName": { + "value": "[variables('varFslogixStorageName')]" + }, + "storageToDomainScript": { + "value": "[variables('varStorageToDomainScript')]" + }, + "storageToDomainScriptUri": { + "value": "[variables('varStorageToDomainScriptUri')]" + }, + "identityServiceProvider": { + "value": "[parameters('identityServiceProvider')]" + }, + "dscAgentPackageLocation": { + "value": "[variables('varStorageAzureFilesDscAgentPackageLocation')]" + }, + "storageCustomOuPath": { + "value": "[variables('varStorageCustomOuPath')]" + }, + "managementVmName": { + "value": "[variables('varManagementVmName')]" + }, + "deployPrivateEndpoint": { + "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" + }, + "keyVaultResourceId": { + "value": "[parameters('keyVaultResourceId')]" + }, + "storageOuPath": { + "value": "[variables('varOuStgPath')]" + }, + "managedIdentityClientId": { + "value": "[parameters('managedIdentityClientId')]" + }, + "securityPrincipalName": { + "value": "[parameters('securityPrincipalName')]" + }, + "domainJoinUserName": { + "value": "[parameters('domainJoinUserName')]" + }, + "serviceObjectsRgName": { + "value": "[parameters('serviceObjectsRgName')]" + }, + "identityDomainName": { + "value": "[parameters('identityDomainName')]" + }, + "identityDomainGuid": { + "value": "[parameters('identityDomainGuid')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "storageObjectsRgName": { + "value": "[parameters('storageObjectsRgName')]" + }, + "privateEndpointSubnetResourceId": { + "value": "[parameters('privateEndpointSubnetResourceId')]" + }, + "vmsSubnetResourceId": { + "value": "[parameters('vmsSubnetResourceId')]" + }, + "privateDnsZoneFilesResourceId": { + "value": "[parameters('privateDnsZoneFilesResourceId')]" + }, + "subId": { + "value": "[parameters('subId')]" + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]", + "alaWorkspaceResourceId": { + "value": "[parameters('alaWorkspaceResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4958601852198550361" }, - "accessTier": { + "name": "AVD LZA storage", + "description": "This module deploys storage account, azure files. domain join logic", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "subId": { "type": "string", - "defaultValue": "Hot", - "allowedValues": [ - "Premium", - "Hot", - "Cool" - ], "metadata": { - "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + "description": "AVD workload subscription ID, multiple subscriptions scenario." } }, - "largeFileSharesState": { + "storageObjectsRgName": { "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], "metadata": { - "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + "description": "Resource Group Name for Azure Files." } }, - "azureFilesIdentityBasedAuthentication": { - "type": "object", - "defaultValue": {}, + "identityServiceProvider": { + "type": "string", "metadata": { - "description": "Optional. Provides the identity based authentication settings for Azure Files." + "description": "Required, The service providing domain services for Azure Virtual Desktop." } }, - "defaultToOAuthAuthentication": { - "type": "bool", - "defaultValue": false, + "serviceObjectsRgName": { + "type": "string", "metadata": { - "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + "description": "Resource Group Name for management VM." } }, - "allowSharedKeyAccess": { - "type": "bool", - "defaultValue": true, + "storageAccountName": { + "type": "string", "metadata": { - "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + "description": "Storage account name." } }, - "privateEndpoints": { - "$ref": "#/definitions/privateEndpointType", + "fileShareName": { + "type": "string", "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Storage account file share name." } }, - "managementPolicyRules": { - "type": "array", - "nullable": true, + "privateEndpointSubnetResourceId": { + "type": "string", "metadata": { - "description": "Optional. The Storage Account ManagementPolicies Rules." + "description": "Private endpoint subnet ID." } }, - "networkAcls": { - "$ref": "#/definitions/networkAclsType", - "nullable": true, + "vmsSubnetResourceId": { + "type": "string", "metadata": { - "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + "description": "VMs subnet ID." } }, - "requireInfrastructureEncryption": { - "type": "bool", - "defaultValue": true, + "location": { + "type": "string", "metadata": { - "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + "description": "Location where to deploy resources." } }, - "allowCrossTenantReplication": { + "fileShareMultichannel": { "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Allow or disallow cross AAD tenant object replication." + "description": "File share SMB multichannel." } }, - "customDomainName": { + "identityDomainName": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + "description": "Identity domain name." } }, - "customDomainUseSubDomainName": { - "type": "bool", - "defaultValue": false, + "identityDomainGuid": { + "type": "string", "metadata": { - "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + "description": "AD domain GUID." } }, - "dnsEndpointType": { + "keyVaultResourceId": { "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "AzureDnsZone", - "Standard" - ], "metadata": { - "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." + "description": "Key Vault Resource ID." } }, - "blobServices": { - "type": "object", - "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", + "domainJoinUserName": { + "type": "string", "metadata": { - "description": "Optional. Blob service and containers to deploy." + "description": "AVD session host domain join credentials." } }, - "fileServices": { - "type": "object", - "defaultValue": {}, + "vmLocalUserName": { + "type": "string", "metadata": { - "description": "Optional. File service and shares to deploy." + "description": "AVD session host local admin credentials." } }, - "queueServices": { - "type": "object", - "defaultValue": {}, + "storageSku": { + "type": "string", "metadata": { - "description": "Optional. Queue service and queues to create." + "description": "Azure Files storage account SKU." } }, - "tableServices": { - "type": "object", - "defaultValue": {}, + "fileShareQuotaSize": { + "type": "int", "metadata": { - "description": "Optional. Table service and tables to create." + "description": "*Azure File share quota" } }, - "allowBlobPublicAccess": { - "type": "bool", - "defaultValue": false, + "privateDnsZoneFilesResourceId": { + "type": "string", "metadata": { - "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + "description": "Use Azure private DNS zones for private endpoints." } }, - "minimumTlsVersion": { + "storageToDomainScript": { "type": "string", - "defaultValue": "TLS1_2", - "allowedValues": [ - "TLS1_0", - "TLS1_1", - "TLS1_2" - ], "metadata": { - "description": "Optional. Set the minimum TLS version on request to storage." + "description": "Script name for adding storage account to Active Directory." } }, - "enableHierarchicalNamespace": { - "type": "bool", - "defaultValue": false, + "storageToDomainScriptUri": { + "type": "string", "metadata": { - "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + "description": "URI for the script for adding the storage account to Active Directory." } }, - "enableSftp": { - "type": "bool", - "defaultValue": false, + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + "description": "Tags to be applied to resources" } }, - "isLocalUserEnabled": { - "type": "bool", - "defaultValue": false, + "managementVmName": { + "type": "string", "metadata": { - "description": "Optional. Enables local users feature, if set to true." + "description": "Name for management virtual machine. for tools and to join Azure Files to domain." } }, - "enableNfsV3": { + "deployPrivateEndpoint": { "type": "bool", - "defaultValue": false, "metadata": { - "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + "description": "Optional. AVD Accelerator will deploy with private endpoints by default." } }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", + "alaWorkspaceResourceId": { + "type": "string", "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Log analytics workspace for diagnostic logs." } }, - "tags": { - "type": "object", - "nullable": true, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", "metadata": { - "description": "Optional. Tags of the resource." + "description": "Do not modify, used to set unique value for resource deployment." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "storagePurpose": { + "type": "string", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Sets purpose of the storage account." } }, - "allowedCopyScope": { + "dscAgentPackageLocation": { "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "AAD", - "PrivateLink" - ], "metadata": { - "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + "description": "Sets location of DSC Agent." } }, - "publicNetworkAccess": { + "storageCustomOuPath": { "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "Enabled", - "Disabled" - ], "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + "description": "Custom OU path for storage." } }, - "supportsHttpsTrafficOnly": { - "type": "bool", - "defaultValue": true, + "storageOuPath": { + "type": "string", "metadata": { - "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + "description": "OU Storage Path" } }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", + "managedIdentityClientId": { + "type": "string", "metadata": { - "description": "Optional. The customer managed key definition." + "description": "Managed Identity Client ID" } }, - "sasExpirationPeriod": { + "securityPrincipalName": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + "description": "Identity name array to grant RBAC role to access AVD application group and NTFS permissions." } }, - "keyType": { + "storageAccountFqdn": { "type": "string", - "nullable": true, - "allowedValues": [ - "Account", - "Service" - ], "metadata": { - "description": "Optional. The keyType to use with Queue & Table services." + "description": "storage account FDQN." } } }, "variables": { - "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]", + "varAzureCloudName": "[environment().name]", + "varWrklStoragePrivateEndpointName": "[format('pe-{0}-file', parameters('storageAccountName'))]", + "varSecurityPrincipalName": "[if(not(empty(parameters('securityPrincipalName'))), parameters('securityPrincipalName'), 'none')]", + "varAdminUserName": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('vmLocalUserName'), parameters('domainJoinUserName'))]", + "varStorageToDomainScriptArgs": "[format('-DscPath {0} -StorageAccountName {1} -StorageAccountRG {2} -StoragePurpose {3} -DomainName {4} -IdentityServiceProvider {5} -AzureCloudEnvironment {6} -SubscriptionId {7} -AdminUserName {8} -CustomOuPath {9} -OUName {10} -ShareName {11} -ClientId {12} -SecurityPrincipalName \"{13}\" -StorageAccountFqdn {14} ', parameters('dscAgentPackageLocation'), parameters('storageAccountName'), parameters('storageObjectsRgName'), parameters('storagePurpose'), parameters('identityDomainName'), parameters('identityServiceProvider'), variables('varAzureCloudName'), parameters('subId'), variables('varAdminUserName'), parameters('storageCustomOuPath'), parameters('storageOuPath'), parameters('fileShareName'), parameters('managedIdentityClientId'), variables('varSecurityPrincipalName'), parameters('storageAccountFqdn'))]", + "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]" }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" - }, - "storageAccount": { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2022-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "kind": "[parameters('kind')]", - "sku": { - "name": "[parameters('skuName')]" - }, - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "properties": { - "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", - "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", - "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", - "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", - "customDomain": { - "name": "[parameters('customDomainName')]", - "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" - }, - "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", - "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", - "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", - "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", - "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", - "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", - "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", - "isSftpEnabled": "[parameters('enableSftp')]", - "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", - "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", - "minimumTlsVersion": "[parameters('minimumTlsVersion')]", - "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", - "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", - "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKKeyVault" - ] - }, - "storageAccount_diagnosticSettings": { - "copy": { - "name": "storageAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_privateEndpoints": { - "copy": { - "name": "storageAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, + "resources": [ + { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subId'))]", + "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -28022,42 +32819,43 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + "value": "[parameters('storageAccountName')]" }, "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" - }, - "privateDnsZoneGroupName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" - }, - "privateDnsZoneResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + "value": "[parameters('location')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + "skuName": { + "value": "[parameters('storageSku')]" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "allowBlobPublicAccess": { + "value": false }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "publicNetworkAccess": "[if(parameters('deployPrivateEndpoint'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "kind": "[if(or(equals(parameters('storageSku'), 'Premium_LRS'), equals(parameters('storageSku'), 'Premium_ZRS')), createObject('value', 'FileStorage'), createObject('value', 'StorageV2'))]", + "largeFileSharesState": "[if(or(equals(parameters('storageSku'), 'Standard_LRS'), equals(parameters('storageSku'), 'Standard_ZRS')), createObject('value', 'Enabled'), createObject('value', 'Disabled'))]", + "azureFilesIdentityBasedAuthentication": "[if(not(equals(parameters('identityServiceProvider'), 'EntraID')), createObject('value', createObject('directoryServiceOptions', if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDS', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), 'AADKERB', 'none')), 'activeDirectoryProperties', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), createObject('domainGuid', parameters('identityDomainGuid'), 'domainName', parameters('identityDomainName')), createObject()))), createObject('value', null()))]", + "accessTier": { + "value": "Hot" }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "networkAcls": "[if(parameters('deployPrivateEndpoint'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', parameters('vmsSubnetResourceId'), 'action', 'Allow')), 'ipRules', createArray())))]", + "fileServices": { + "value": { + "shares": [ + { + "name": "[parameters('fileShareName')]", + "shareQuota": "[parameters('fileShareQuotaSize')]" + } + ], + "protocolSettings": "[if(parameters('fileShareMultichannel'), createObject('smb', createObject('multichannel', createObject('enabled', parameters('fileShareMultichannel')))), createObject())]", + "diagnosticSettings": "[variables('varDiagnosticSettings')]" + } }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "privateEndpoints": "[if(parameters('deployPrivateEndpoint'), createObject('value', createArray(createObject('name', variables('varWrklStoragePrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklStoragePrivateEndpointName')), 'service', 'file', 'privateDnsZoneGroupName', split(parameters('privateDnsZoneFilesResourceId'), '/')[8], 'privateDnsZoneResourceIds', createArray(parameters('privateDnsZoneFilesResourceId'))))), createObject('value', createArray()))]", + "tags": { + "value": "[parameters('tags')]" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" } }, "template": { @@ -28067,343 +32865,640 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "4120048060064073955" + "version": "0.34.44.8038", + "templateHash": "15994741654178645865" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint.", + "name": "Storage Accounts", + "description": "This module deploys a Storage Account.", "owner": "Azure/module-maintainers" }, "definitions": { - "roleAssignmentType": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + } + }, + "privateEndpointType": { "type": "array", "items": { "type": "object", "properties": { - "roleDefinitionIdOrName": { + "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Optional. The name of the private endpoint." } }, - "principalId": { + "location": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. The location to deploy the private endpoint to." } }, - "principalType": { + "service": { "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." } }, - "description": { + "subnetResourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "condition": { + "privateDnsZoneGroupName": { "type": "string", "nullable": true, "metadata": { - "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\"." + "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." } }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, - "delegatedManagedIdentityResourceId": { - "type": "string", + "isManualConnection": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. Manual PrivateLink Service Connections." } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "ipConfigurationsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { + }, + "manualConnectionRequestMessage": { "type": "string", + "nullable": true, + "maxLength": 140, "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." } }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } } } }, + "nullable": true, "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true - }, - "manualPrivateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." + "description": "Optional. Custom DNS configurations." } }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } } } }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "tags": { + "type": "object", + "nullable": true, "metadata": { - "description": "Required. Properties of private link service connection." + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } } }, "nullable": true }, - "privateLinkServiceConnectionsType": { + "diagnosticSettingType": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the private link service connection." + "description": "Optional. The name of diagnostic setting." } }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, + "nullable": true, "metadata": { - "description": "Required. Properties of private link service connection." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } - } - } - }, - "nullable": true - }, - "customDnsConfigType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { + }, + "logAnalyticsDestinationType": { "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, + "workspaceResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } } }, "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true } }, "parameters": { "name": { "type": "string", + "maxLength": 24, "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Required. Name of the Storage Account. Must be lower-case." } }, - "subnetResourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Optional. Location for all resources." } }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "nullable": true, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Optional. The managed identity definition for this resource." } }, - "customNetworkInterfaceName": { + "kind": { "type": "string", - "nullable": true, + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. Type of Storage Account to create." } }, - "ipConfigurations": { - "$ref": "#/definitions/ipConfigurationsType", + "skuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS", + "Premium_ZRS", + "Standard_GZRS", + "Standard_RAGZRS" + ], "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. Storage Account Sku Name." } }, - "privateDnsZoneGroupName": { + "accessTier": { "type": "string", - "nullable": true, + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool" + ], "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." } }, - "privateDnsZoneResourceIds": { + "largeFileSharesState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + } + }, + "azureFilesIdentityBasedAuthentication": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Provides the identity based authentication settings for Azure Files." + } + }, + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "managementPolicyRules": { "type": "array", "nullable": true, "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. The Storage Account ManagementPolicies Rules." } }, - "location": { + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + } + }, + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." } }, - "lock": { - "$ref": "#/definitions/lockType", + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." } }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", + "dnsEndpointType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AzureDnsZone", + "Standard" + ], "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." } }, - "tags": { + "blobServices": { "type": "object", - "nullable": true, + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + "description": "Optional. Blob service and containers to deploy." } }, - "customDnsConfigs": { - "$ref": "#/definitions/customDnsConfigType", + "fileServices": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. Custom DNS configurations." + "description": "Optional. File service and shares to deploy." } }, - "manualPrivateLinkServiceConnections": { - "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "queueServices": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + "description": "Optional. Queue service and queues to create." } }, - "privateLinkServiceConnections": { - "$ref": "#/definitions/privateLinkServiceConnectionsType", + "tableServices": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource." + "description": "Optional. Table service and tables to create." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_0", + "TLS1_1", + "TLS1_2" + ], + "metadata": { + "description": "Optional. Set the minimum TLS version on request to storage." + } + }, + "enableHierarchicalNamespace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + } + }, + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables local users feature, if set to true." + } + }, + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." } }, "enableTelemetry": { @@ -28412,28 +33507,84 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "allowedCopyScope": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AAD", + "PrivateLink" + ], + "metadata": { + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } } }, "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" }, "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" + }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -28449,73 +33600,105 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", "name": "[parameters('name')]", "location": "[parameters('location')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", "tags": "[parameters('tags')]", + "properties": { + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", + "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", + "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", + "customDomain": { + "name": "[parameters('customDomainName')]", + "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" + }, + "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", + "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", + "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", + "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", + "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", + "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", + "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", + "isSftpEnabled": "[parameters('enableSftp')]", + "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", + "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", + "minimumTlsVersion": "[parameters('minimumTlsVersion')]", + "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", + "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null } } ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "privateEndpoint" + "storageAccount" ] }, - "privateEndpoint_roleAssignments": { + "storageAccount_privateEndpoints": { "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -28523,422 +33706,654 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, - "privateEndpointName": { - "value": "[parameters('name')]" + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "11244630631275470040" + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group.", - "owner": "Azure/module-maintainers" + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } }, "parameters": { - "privateEndpointName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "Required. Name of the private endpoint resource to create." } }, - "privateDNSResourceIds": { + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { "type": "array", - "minLength": 1, - "maxLength": 5, + "nullable": true, "metadata": { - "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "name": { + "customNetworkInterfaceName": { "type": "string", - "defaultValue": "default", + "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", - "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } } - ] - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] } - ], + }, "outputs": { - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the private endpoint DNS zone group." + "description": "The resource group the private endpoint was deployed into." }, - "value": "[parameters('name')]" + "value": "[resourceGroup().name]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "description": "The resource ID of the private endpoint." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" }, - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "The name of the private endpoint." }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" - }, - "groupId": { - "type": "string", - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_fileServices": { - "condition": "[not(empty(parameters('fileServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" - }, - "protocolSettings": { - "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" - }, - "shareDeleteRetentionPolicy": { - "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" - }, - "shares": { - "value": "[tryGet(parameters('fileServices'), 'shares')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "5174215295464783855" - }, - "name": "Storage Account File Share Services", - "description": "This module deploys a Storage Account File Share Service.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "value": "[parameters('name')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" } } } }, - "nullable": true - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the file service." - } - }, - "protocolSettings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Protocol settings for file service." - } - }, - "shareDeleteRetentionPolicy": { - "type": "object", - "defaultValue": { - "enabled": true, - "days": 7 - }, - "metadata": { - "description": "Optional. The service properties for soft delete." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "shares": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. File shares to create." - } - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-04-01", - "name": "[parameters('storageAccountName')]" - }, - "fileServices": { - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "protocolSettings": "[parameters('protocolSettings')]", - "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" - } - }, - "fileServices_diagnosticSettings": { - "copy": { - "name": "fileServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, "dependsOn": [ - "fileServices" + "storageAccount" ] }, - "fileServices_shares": { - "copy": { - "name": "fileServices_shares", - "count": "[length(coalesce(parameters('shares'), createArray()))]" - }, + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -28946,28 +34361,19 @@ "mode": "Incremental", "parameters": { "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "fileServicesName": { "value": "[parameters('name')]" }, - "name": { - "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" - }, - "accessTier": { - "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" - }, - "enabledProtocols": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" }, - "rootSquash": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" }, - "shareQuota": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" } }, "template": { @@ -28977,74 +34383,128 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "823140844991744662" + "version": "0.34.44.8038", + "templateHash": "5572402757180298542" }, - "name": "Storage Account File Shares", - "description": "This module deploys a Storage Account File Share.", + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service.", "owner": "Azure/module-maintainers" }, "definitions": { - "roleAssignmentType": { + "diagnosticSettingType": { "type": "array", "items": { "type": "object", "properties": { - "roleDefinitionIdOrName": { + "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Optional. The name of diagnostic setting." } }, - "principalId": { - "type": "string", + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "principalType": { + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { "type": "string", "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" + "AzureDiagnostics", + "Dedicated" ], "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "description": { + "workspaceResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "condition": { + "storageAccountResourceId": { "type": "string", "nullable": true, "metadata": { - "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\"." + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "conditionVersion": { + "eventHubAuthorizationRuleResourceId": { "type": "string", - "allowedValues": [ - "2.0" - ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." } }, - "delegatedManagedIdentityResourceId": { + "eventHubName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } } @@ -29060,295 +34520,550 @@ "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "fileServicesName": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." - } - }, "name": { "type": "string", + "defaultValue": "default", "metadata": { - "description": "Required. The name of the file share to create." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "TransactionOptimized", - "allowedValues": [ - "Premium", - "Hot", - "Cool", - "TransactionOptimized" - ], - "metadata": { - "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + "description": "Optional. The name of the file service." } }, - "shareQuota": { - "type": "int", - "defaultValue": 5120, + "protocolSettings": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + "description": "Optional. Protocol settings for file service." } }, - "enabledProtocols": { - "type": "string", - "defaultValue": "SMB", - "allowedValues": [ - "NFS", - "SMB" - ], + "shareDeleteRetentionPolicy": { + "type": "object", + "defaultValue": { + "enabled": true, + "days": 7 + }, "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + "description": "Optional. The service properties for soft delete." } }, - "rootSquash": { - "type": "string", - "defaultValue": "NoRootSquash", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + "description": "Optional. The diagnostic settings of the service." } }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", + "shares": { + "type": "array", + "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. File shares to create." } } }, "resources": { - "storageAccount::fileService": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" - }, "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2023-04-01", "name": "[parameters('storageAccountName')]" }, - "fileShare": { - "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2023-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", "properties": { - "accessTier": "[parameters('accessTier')]", - "shareQuota": "[parameters('shareQuota')]", - "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", - "enabledProtocols": "[parameters('enabledProtocols')]" + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" } }, - "fileShare_roleAssignments": { - "condition": "[not(empty(parameters('roleAssignments')))]", + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", + "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "fileShareResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" }, "roleAssignments": { - "value": "[parameters('roleAssignments')]" + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "16821934161134527264" + "version": "0.34.44.8038", + "templateHash": "2846593244669729605" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true } }, "parameters": { - "roleAssignments": { - "type": "array", + "storageAccountName": { + "type": "string", + "maxLength": 24, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "fileShareResourceId": { + "fileServicesName": { "type": "string", + "defaultValue": "default", "metadata": { - "description": "Required. The resource id of the file share to assign the roles to." + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." } - } - }, - "variables": { - "$fxv#0": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "scope": { - "type": "string", - "metadata": { - "description": "Required. The scope to deploy the role assignment to." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The role definition Id to assign." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "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\"" - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "defaultValue": "2.0", - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[[parameters('scope')]", - "name": "[[parameters('name')]", - "properties": { - "roleDefinitionId": "[[parameters('roleDefinitionId')]", - "principalId": "[[parameters('principalId')]", - "description": "[[parameters('description')]", - "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", - "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" - } - } - ] }, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "TransactionOptimized", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } } }, - "resources": [ - { - "copy": { - "name": "fileShare_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" + } + }, + "fileShare_roleAssignments": { + "condition": "[not(empty(parameters('roleAssignments')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2021-04-01", - "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", "properties": { - "mode": "Incremental", "expressionEvaluationOptions": { - "scope": "Outer" + "scope": "inner" }, - "template": "[variables('$fxv#0')]", + "mode": "Incremental", "parameters": { - "scope": { - "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" + "fileShareResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" }, - "name": { - "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" - }, - "roleDefinitionId": { - "value": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]" - }, - "principalId": { - "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" - }, - "principalType": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" - }, - "description": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "11422901802944437310" + } }, - "condition": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" + "parameters": { + "roleAssignments": { + "type": "array", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "fileShareResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the file share to assign the roles to." + } + } }, - "conditionVersion": { - "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "description": "[[parameters('description')]", + "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + }, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } }, - "delegatedManagedIdentityResourceId": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - } + "resources": [ + { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2021-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" + }, + "name": { + "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" + }, + "roleDefinitionId": { + "value": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]" + }, + "principalId": { + "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "condition": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": { + "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" + }, + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + } + } + } + ] } - } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" } - ] + } } }, "dependsOn": [ - "fileShare" + "fileServices", + "storageAccount" ] } }, @@ -29356,1624 +35071,717 @@ "name": { "type": "string", "metadata": { - "description": "The name of the deployed file share." + "description": "The name of the deployed file share service." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed file share." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed file share." + "description": "The resource ID of the deployed file share service." }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "fileServices", - "storageAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed file share service." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed file share service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed file share service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed storage account." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed storage account." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed storage account." - }, - "value": "[resourceGroup().name]" - }, - "primaryBlobEndpoint": { - "type": "string", - "metadata": { - "description": "The primary blob endpoint reference if blob services are deployed." - }, - "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('storageAccount', '2022-09-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[not(equals(parameters('identityServiceProvider'), 'EntraID'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Add-{0}-Storage-Setup-{1}', parameters('storagePurpose'), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "virtualMachineName": { - "value": "[parameters('managementVmName')]" - }, - "file": { - "value": "[parameters('storageToDomainScript')]" - }, - "scriptArguments": { - "value": "[variables('varStorageToDomainScriptArgs')]" - }, - "adminUserPassword": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.KeyVault/vaults', parameters('wrklKvName'))), 'secretName', 'vmLocalUserPassword')), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.KeyVault/vaults', parameters('wrklKvName'))), 'secretName', 'domainJoinUserPassword')))]", - "baseScriptUri": { - "value": "[parameters('storageToDomainScriptUri')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "4206601194007058149" - }, - "name": "AVD LZA storage", - "description": "Configures domain join settings on storage account via VM custom script extension", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Virtual machine name." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy compute services." - } - }, - "baseScriptUri": { - "type": "string", - "metadata": { - "description": "Location for the AVD agent installation package." - } - }, - "file": { - "type": "string" - }, - "scriptArguments": { - "type": "string", - "metadata": { - "description": "Arguments for domain join script." - } - }, - "adminUserPassword": { - "type": "securestring", - "metadata": { - "description": "Domain join user password." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - } - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('VM-Ext-AVM-{0}', parameters('time'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "AzureFilesDomainJoin" - }, - "virtualMachineName": { - "value": "[parameters('virtualMachineName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "CustomScriptExtension" - }, - "typeHandlerVersion": { - "value": "1.10" - }, - "autoUpgradeMinorVersion": { - "value": true - }, - "enableAutomaticUpgrade": { - "value": false - }, - "settings": { - "value": {} - }, - "protectedSettings": { - "value": { - "fileUris": "[array(parameters('baseScriptUri'))]", - "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -File {0} {1} -AdminUserPassword {2} -verbose', parameters('file'), parameters('scriptArguments'), parameters('adminUserPassword'))]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] } }, "outputs": { - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the extension." + "description": "The resource ID of the deployed storage account." }, - "value": "[parameters('name')]" + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" }, - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the extension." + "description": "The name of the deployed storage account." }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + "value": "[parameters('name')]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the Resource Group the extension was created in." + "description": "The resource group of the deployed storage account." }, "value": "[resourceGroup().name]" }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('extension', '2022-11-01', 'full').location]" + "value": "[reference('storageAccount', '2022-09-01', 'full').location]" } } } } - } - ] - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time')))]" - ] - } - ], - "outputs": { - "storageAccountResourceId": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))), '2022-09-01').outputs.resourceId.value]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]" - ] - }, - { - "condition": "[variables('varCreateAppAttachDeployment')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-AppA-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storagePurpose": { - "value": "AppAttach" - }, - "vmLocalUserName": { - "value": "[parameters('avdVmLocalUserName')]" - }, - "fileShareName": { - "value": "[variables('varAppAttachFileShareName')]" - }, - "fileShareMultichannel": "[if(equals(parameters('appAttachStoragePerformance'), 'Premium'), createObject('value', true()), createObject('value', false()))]", - "storageSku": { - "value": "[variables('varAppAttachStorageSku')]" - }, - "fileShareQuotaSize": { - "value": "[parameters('appAttachFileShareQuotaSize')]" - }, - "storageAccountFqdn": { - "value": "[variables('varAppAttachStorageFqdn')]" - }, - "storageAccountName": { - "value": "[variables('varAppAttachStorageName')]" - }, - "storageToDomainScript": { - "value": "[variables('varStorageToDomainScript')]" - }, - "storageToDomainScriptUri": { - "value": "[variables('varStorageToDomainScriptUri')]" - }, - "identityServiceProvider": { - "value": "[parameters('avdIdentityServiceProvider')]" - }, - "dscAgentPackageLocation": { - "value": "[variables('varStorageAzureFilesDscAgentPackageLocation')]" - }, - "storageCustomOuPath": { - "value": "[variables('varStorageCustomOuPath')]" - }, - "managementVmName": { - "value": "[variables('varManagementVmName')]" - }, - "deployPrivateEndpoint": { - "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" - }, - "ouStgPath": { - "value": "[variables('varOuStgPath')]" - }, - "managedIdentityClientId": "[if(and(variables('varCreateStorageDeployment'), not(equals(parameters('avdIdentityServiceProvider'), 'EntraID'))), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time'))), '2022-09-01').outputs.managedIdentityStorageClientId.value), createObject('value', ''))]", - "securityPrincipalName": { - "value": "[variables('varSecurityPrincipalName')]" - }, - "domainJoinUserName": { - "value": "[parameters('avdDomainJoinUserName')]" - }, - "wrklKvName": { - "value": "[variables('varWrklKvName')]" - }, - "serviceObjectsRgName": { - "value": "[variables('varServiceObjectsRgName')]" - }, - "identityDomainName": { - "value": "[parameters('identityDomainName')]" - }, - "identityDomainGuid": { - "value": "[parameters('identityDomainGuid')]" - }, - "location": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostLocation')), createObject('value', parameters('avdManagementPlaneLocation')))]", - "storageObjectsRgName": { - "value": "[variables('varStorageObjectsRgName')]" - }, - "privateEndpointSubnetId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName'))), createObject('value', parameters('existingVnetPrivateEndpointSubnetResourceId')))]", - "vmsSubnetId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", - "vnetPrivateDnsZoneFilesId": "[if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.azureFilesDnsZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneFilesId')))]", - "workloadSubsId": { - "value": "[parameters('avdWorkloadSubsId')]" - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]", - "alaWorkspaceResourceId": "[if(parameters('avdDeployMonitoring'), if(parameters('deployAlaWorkspace'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.avdAlaWorkspaceResourceId.value), createObject('value', parameters('alaExistingWorkspaceResourceId'))), createObject('value', ''))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "8619049573819403821" - }, - "name": "AVD LZA storage", - "description": "This module deploys storage account, azure files. domain join logic", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "workloadSubsId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "storageObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group Name for Azure Files." - } - }, - "identityServiceProvider": { - "type": "string", - "metadata": { - "description": "Required, The service providing domain services for Azure Virtual Desktop." - } - }, - "serviceObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group Name for management VM." - } - }, - "storageAccountName": { - "type": "string", - "metadata": { - "description": "Storage account name." - } - }, - "fileShareName": { - "type": "string", - "metadata": { - "description": "Storage account file share name." - } - }, - "privateEndpointSubnetId": { - "type": "string", - "metadata": { - "description": "Private endpoint subnet ID." - } - }, - "vmsSubnetId": { - "type": "string", - "metadata": { - "description": "VMs subnet ID." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy resources." - } - }, - "fileShareMultichannel": { - "type": "bool", - "metadata": { - "description": "File share SMB multichannel." - } - }, - "identityDomainName": { - "type": "string", - "metadata": { - "description": "Identity domain name." - } - }, - "identityDomainGuid": { - "type": "string", - "metadata": { - "description": "AD domain GUID." - } - }, - "wrklKvName": { - "type": "string", - "metadata": { - "description": "Keyvault name to get credentials from." - } - }, - "domainJoinUserName": { - "type": "string", - "metadata": { - "description": "AVD session host domain join credentials." - } - }, - "vmLocalUserName": { - "type": "string", - "metadata": { - "description": "AVD session host local admin credentials." - } - }, - "storageSku": { - "type": "string", - "metadata": { - "description": "Azure Files storage account SKU." - } - }, - "fileShareQuotaSize": { - "type": "int", - "metadata": { - "description": "*Azure File share quota" - } - }, - "vnetPrivateDnsZoneFilesId": { - "type": "string", - "metadata": { - "description": "Use Azure private DNS zones for private endpoints." - } - }, - "storageToDomainScript": { - "type": "string", - "metadata": { - "description": "Script name for adding storage account to Active Directory." - } - }, - "storageToDomainScriptUri": { - "type": "string", - "metadata": { - "description": "URI for the script for adding the storage account to Active Directory." - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "managementVmName": { - "type": "string", - "metadata": { - "description": "Name for management virtual machine. for tools and to join Azure Files to domain." - } - }, - "deployPrivateEndpoint": { - "type": "bool", - "metadata": { - "description": "Optional. AVD Accelerator will deploy with private endpoints by default." - } - }, - "alaWorkspaceResourceId": { - "type": "string", - "metadata": { - "description": "Log analytics workspace for diagnostic logs." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - }, - "storagePurpose": { - "type": "string", - "metadata": { - "description": "Sets purpose of the storage account." - } - }, - "dscAgentPackageLocation": { - "type": "string", - "metadata": { - "description": "Sets location of DSC Agent." - } - }, - "storageCustomOuPath": { - "type": "string", - "metadata": { - "description": "Custom OU path for storage." - } - }, - "ouStgPath": { - "type": "string", - "metadata": { - "description": "OU Storage Path" - } - }, - "managedIdentityClientId": { - "type": "string", - "metadata": { - "description": "Managed Identity Client ID" - } - }, - "securityPrincipalName": { - "type": "string", - "metadata": { - "description": "Identity name array to grant RBAC role to access AVD application group and NTFS permissions." - } - }, - "storageAccountFqdn": { - "type": "string", - "metadata": { - "description": "storage account FDQN." - } - } - }, - "variables": { - "varAzureCloudName": "[environment().name]", - "varWrklStoragePrivateEndpointName": "[format('pe-{0}-file', parameters('storageAccountName'))]", - "varSecurityPrincipalName": "[if(not(empty(parameters('securityPrincipalName'))), parameters('securityPrincipalName'), 'none')]", - "varAdminUserName": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('vmLocalUserName'), parameters('domainJoinUserName'))]", - "varStorageToDomainScriptArgs": "[format('-DscPath {0} -StorageAccountName {1} -StorageAccountRG {2} -StoragePurpose {3} -DomainName {4} -IdentityServiceProvider {5} -AzureCloudEnvironment {6} -SubscriptionId {7} -AdminUserName {8} -CustomOuPath {9} -OUName {10} -ShareName {11} -ClientId {12} -SecurityPrincipalName \"{13}\" -StorageAccountFqdn {14} ', parameters('dscAgentPackageLocation'), parameters('storageAccountName'), parameters('storageObjectsRgName'), parameters('storagePurpose'), parameters('identityDomainName'), parameters('identityServiceProvider'), variables('varAzureCloudName'), parameters('workloadSubsId'), variables('varAdminUserName'), parameters('storageCustomOuPath'), parameters('ouStgPath'), parameters('fileShareName'), parameters('managedIdentityClientId'), variables('varSecurityPrincipalName'), parameters('storageAccountFqdn'))]", - "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]" - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('storageAccountName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "skuName": { - "value": "[parameters('storageSku')]" - }, - "allowBlobPublicAccess": { - "value": false - }, - "publicNetworkAccess": "[if(parameters('deployPrivateEndpoint'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "kind": "[if(or(equals(parameters('storageSku'), 'Premium_LRS'), equals(parameters('storageSku'), 'Premium_ZRS')), createObject('value', 'FileStorage'), createObject('value', 'StorageV2'))]", - "largeFileSharesState": "[if(or(equals(parameters('storageSku'), 'Standard_LRS'), equals(parameters('storageSku'), 'Standard_ZRS')), createObject('value', 'Enabled'), createObject('value', 'Disabled'))]", - "azureFilesIdentityBasedAuthentication": "[if(not(equals(parameters('identityServiceProvider'), 'EntraID')), createObject('value', createObject('directoryServiceOptions', if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDS', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), 'AADKERB', 'none')), 'activeDirectoryProperties', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), createObject('domainGuid', parameters('identityDomainGuid'), 'domainName', parameters('identityDomainName')), createObject()))), createObject('value', null()))]", - "accessTier": { - "value": "Hot" - }, - "networkAcls": "[if(parameters('deployPrivateEndpoint'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', parameters('vmsSubnetId'), 'action', 'Allow')), 'ipRules', createArray())))]", - "fileServices": { - "value": { - "shares": [ - { - "name": "[parameters('fileShareName')]", - "shareQuota": "[mul(parameters('fileShareQuotaSize'), 100)]" - } - ], - "protocolSettings": "[if(parameters('fileShareMultichannel'), createObject('smb', createObject('multichannel', createObject('enabled', parameters('fileShareMultichannel')))), createObject())]", - "diagnosticSettings": "[variables('varDiagnosticSettings')]" - } - }, - "privateEndpoints": "[if(parameters('deployPrivateEndpoint'), createObject('value', createArray(createObject('name', variables('varWrklStoragePrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointSubnetId'), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklStoragePrivateEndpointName')), 'service', 'file', 'privateDnsZoneGroupName', split(parameters('vnetPrivateDnsZoneFilesId'), '/')[8], 'privateDnsZoneResourceIds', createArray(parameters('vnetPrivateDnsZoneFilesId'))))), createObject('value', createArray()))]", - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "11421348829572406411" }, - "name": "Storage Accounts", - "description": "This module deploys a Storage Account.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "managedIdentitiesType": { - "type": "object", + { + "condition": "[not(equals(parameters('identityServiceProvider'), 'EntraID'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Add-{0}-Storage-Setup-{1}', parameters('storagePurpose'), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } - } - }, - "nullable": true - }, - "networkAclsType": { - "type": "object", - "properties": { - "resourceAccessRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "metadata": { - "description": "Required. The ID of the tenant in which the resource resides in." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." - } - } - } + "virtualMachineName": { + "value": "[parameters('managementVmName')]" }, - "nullable": true, - "metadata": { - "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." - } - }, - "bypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "AzureServices, Logging", - "AzureServices, Logging, Metrics", - "AzureServices, Metrics", - "Logging", - "Logging, Metrics", - "Metrics", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." - } - }, - "virtualNetworkRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the virtual network rules." - } - }, - "ipRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the IP ACL rules." + "file": { + "value": "[parameters('storageToDomainScript')]" + }, + "scriptArguments": { + "value": "[variables('varStorageToDomainScriptArgs')]" + }, + "adminUserPassword": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'vmLocalUserPassword')), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'domainJoinUserPassword')))]", + "baseScriptUri": { + "value": "[parameters('storageToDomainScriptUri')]" } }, - "defaultAction": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. Specifies the default action of allow or deny when no other rules match." - } - } - } - }, - "privateEndpointType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." - } + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "7337889415739790800" + }, + "name": "AVD LZA storage", + "description": "Configures domain join settings on storage account via VM custom script extension", + "owner": "Azure/avdaccelerator" }, - "privateDnsZoneResourceIds": { - "type": "array", - "items": { + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Virtual machine name." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy compute services." + } + }, + "baseScriptUri": { + "type": "string", + "metadata": { + "description": "Location for the AVD agent installation package." + } + }, + "file": { "type": "string" }, - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." - } - } + "scriptArguments": { + "type": "string", + "metadata": { + "description": "Arguments for domain join script." } }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." + "adminUserPassword": { + "type": "securestring", + "metadata": { + "description": "Domain join user password." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } } }, - "ipConfigurations": { - "type": "array", - "items": { - "type": "object", + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('VM-Ext-AVM-{0}', parameters('time'))]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "AzureFilesDomainJoin" + }, + "virtualMachineName": { + "value": "[parameters('virtualMachineName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "CustomScriptExtension" + }, + "typeHandlerVersion": { + "value": "1.10" + }, + "autoUpgradeMinorVersion": { + "value": true + }, + "enableAutomaticUpgrade": { + "value": false + }, + "settings": { + "value": {} + }, + "protectedSettings": { + "value": { + "fileUris": "[array(parameters('baseScriptUri'))]", + "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -File {0} {1} -AdminUserPassword {2} -verbose', parameters('file'), parameters('scriptArguments'), parameters('adminUserPassword'))]" + } } }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { "type": "string", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." } }, - "memberName": { + "name": { "type": "string", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Required. The name of the virtual machine extension." } }, - "privateIPAddress": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." + "description": "Optional. Tags of the resource." } } }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - } - }, - "nullable": true - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } } } } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." - } + ] } }, - "nullable": true + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time')))]" + ] + } + ], + "outputs": { + "storageAccountResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))), '2022-09-01').outputs.resourceId.value]" } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]" + ] + }, + { + "condition": "[and(parameters('createFslogixDeployment'), not(equals(parameters('storageService'), 'ANF')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-AppA-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storagePurpose": { + "value": "AppAttach" + }, + "vmLocalUserName": { + "value": "[parameters('vmLocalUserName')]" + }, + "fileShareName": { + "value": "[variables('varAppAttachFileShareName')]" + }, + "fileShareMultichannel": "[if(equals(variables('varAppAttachStoragePerformance'), 'Premium'), createObject('value', true()), createObject('value', false()))]", + "storageSku": { + "value": "[variables('varAppAttachStorageSku')]" + }, + "fileShareQuotaSize": { + "value": "[parameters('appAttachFileShareQuotaSize')]" + }, + "storageAccountFqdn": { + "value": "[variables('varAppAttachStorageFqdn')]" + }, + "storageAccountName": { + "value": "[variables('varAppAttachStorageName')]" + }, + "storageToDomainScript": { + "value": "[variables('varStorageToDomainScript')]" + }, + "storageToDomainScriptUri": { + "value": "[variables('varStorageToDomainScriptUri')]" + }, + "identityServiceProvider": { + "value": "[parameters('identityServiceProvider')]" + }, + "dscAgentPackageLocation": { + "value": "[variables('varStorageAzureFilesDscAgentPackageLocation')]" + }, + "storageCustomOuPath": { + "value": "[variables('varStorageCustomOuPath')]" + }, + "managementVmName": { + "value": "[variables('varManagementVmName')]" + }, + "deployPrivateEndpoint": { + "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" + }, + "storageOuPath": { + "value": "[variables('varOuStgPath')]" + }, + "managedIdentityClientId": { + "value": "[parameters('managedIdentityClientId')]" + }, + "securityPrincipalName": { + "value": "[parameters('securityPrincipalName')]" + }, + "domainJoinUserName": { + "value": "[parameters('domainJoinUserName')]" + }, + "keyVaultResourceId": { + "value": "[parameters('keyVaultResourceId')]" + }, + "serviceObjectsRgName": { + "value": "[parameters('serviceObjectsRgName')]" + }, + "identityDomainName": { + "value": "[parameters('identityDomainName')]" + }, + "identityDomainGuid": { + "value": "[parameters('identityDomainGuid')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "storageObjectsRgName": { + "value": "[parameters('storageObjectsRgName')]" + }, + "privateEndpointSubnetResourceId": { + "value": "[parameters('privateEndpointSubnetResourceId')]" + }, + "vmsSubnetResourceId": { + "value": "[parameters('vmsSubnetResourceId')]" + }, + "privateDnsZoneFilesResourceId": { + "value": "[parameters('privateDnsZoneFilesResourceId')]" + }, + "subId": { + "value": "[parameters('subId')]" + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]", + "alaWorkspaceResourceId": { + "value": "[parameters('alaWorkspaceResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4958601852198550361" + }, + "name": "AVD LZA storage", + "description": "This module deploys storage account, azure files. domain join logic", + "owner": "Azure/avdaccelerator" }, "parameters": { - "name": { + "subId": { "type": "string", - "maxLength": 24, "metadata": { - "description": "Required. Name of the Storage Account. Must be lower-case." + "description": "AVD workload subscription ID, multiple subscriptions scenario." } }, - "location": { + "storageObjectsRgName": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location for all resources." + "description": "Resource Group Name for Azure Files." } }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", + "identityServiceProvider": { + "type": "string", "metadata": { - "description": "Optional. The managed identity definition for this resource." + "description": "Required, The service providing domain services for Azure Virtual Desktop." } }, - "kind": { + "serviceObjectsRgName": { "type": "string", - "defaultValue": "StorageV2", - "allowedValues": [ - "Storage", - "StorageV2", - "BlobStorage", - "FileStorage", - "BlockBlobStorage" - ], "metadata": { - "description": "Optional. Type of Storage Account to create." + "description": "Resource Group Name for management VM." } }, - "skuName": { + "storageAccountName": { "type": "string", - "defaultValue": "Standard_GRS", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS", - "Standard_RAGRS", - "Standard_ZRS", - "Premium_LRS", - "Premium_ZRS", - "Standard_GZRS", - "Standard_RAGZRS" - ], "metadata": { - "description": "Optional. Storage Account Sku Name." + "description": "Storage account name." } }, - "accessTier": { + "fileShareName": { "type": "string", - "defaultValue": "Hot", - "allowedValues": [ - "Premium", - "Hot", - "Cool" - ], "metadata": { - "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + "description": "Storage account file share name." } }, - "largeFileSharesState": { + "privateEndpointSubnetResourceId": { "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], "metadata": { - "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + "description": "Private endpoint subnet ID." } }, - "azureFilesIdentityBasedAuthentication": { - "type": "object", - "defaultValue": {}, + "vmsSubnetResourceId": { + "type": "string", "metadata": { - "description": "Optional. Provides the identity based authentication settings for Azure Files." + "description": "VMs subnet ID." } }, - "defaultToOAuthAuthentication": { - "type": "bool", - "defaultValue": false, + "location": { + "type": "string", "metadata": { - "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + "description": "Location where to deploy resources." } }, - "allowSharedKeyAccess": { + "fileShareMultichannel": { "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + "description": "File share SMB multichannel." } }, - "privateEndpoints": { - "$ref": "#/definitions/privateEndpointType", + "identityDomainName": { + "type": "string", "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Identity domain name." } }, - "managementPolicyRules": { - "type": "array", - "nullable": true, + "identityDomainGuid": { + "type": "string", "metadata": { - "description": "Optional. The Storage Account ManagementPolicies Rules." + "description": "AD domain GUID." } }, - "networkAcls": { - "$ref": "#/definitions/networkAclsType", - "nullable": true, + "keyVaultResourceId": { + "type": "string", "metadata": { - "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + "description": "Key Vault Resource ID." } }, - "requireInfrastructureEncryption": { - "type": "bool", - "defaultValue": true, + "domainJoinUserName": { + "type": "string", "metadata": { - "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + "description": "AVD session host domain join credentials." } }, - "allowCrossTenantReplication": { - "type": "bool", - "defaultValue": true, + "vmLocalUserName": { + "type": "string", "metadata": { - "description": "Optional. Allow or disallow cross AAD tenant object replication." + "description": "AVD session host local admin credentials." } }, - "customDomainName": { + "storageSku": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + "description": "Azure Files storage account SKU." } }, - "customDomainUseSubDomainName": { - "type": "bool", - "defaultValue": false, + "fileShareQuotaSize": { + "type": "int", "metadata": { - "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + "description": "*Azure File share quota" } }, - "dnsEndpointType": { + "privateDnsZoneFilesResourceId": { "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "AzureDnsZone", - "Standard" - ], - "metadata": { - "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." - } - }, - "blobServices": { - "type": "object", - "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", "metadata": { - "description": "Optional. Blob service and containers to deploy." + "description": "Use Azure private DNS zones for private endpoints." } }, - "fileServices": { - "type": "object", - "defaultValue": {}, + "storageToDomainScript": { + "type": "string", "metadata": { - "description": "Optional. File service and shares to deploy." + "description": "Script name for adding storage account to Active Directory." } }, - "queueServices": { - "type": "object", - "defaultValue": {}, + "storageToDomainScriptUri": { + "type": "string", "metadata": { - "description": "Optional. Queue service and queues to create." + "description": "URI for the script for adding the storage account to Active Directory." } }, - "tableServices": { + "tags": { "type": "object", "defaultValue": {}, "metadata": { - "description": "Optional. Table service and tables to create." - } - }, - "allowBlobPublicAccess": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + "description": "Tags to be applied to resources" } }, - "minimumTlsVersion": { + "managementVmName": { "type": "string", - "defaultValue": "TLS1_2", - "allowedValues": [ - "TLS1_0", - "TLS1_1", - "TLS1_2" - ], - "metadata": { - "description": "Optional. Set the minimum TLS version on request to storage." - } - }, - "enableHierarchicalNamespace": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." - } - }, - "enableSftp": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." - } - }, - "isLocalUserEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables local users feature, if set to true." - } - }, - "enableNfsV3": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "tags": { - "type": "object", - "nullable": true, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Name for management virtual machine. for tools and to join Azure Files to domain." } }, - "enableTelemetry": { + "deployPrivateEndpoint": { "type": "bool", - "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. AVD Accelerator will deploy with private endpoints by default." } }, - "allowedCopyScope": { + "alaWorkspaceResourceId": { "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "AAD", - "PrivateLink" - ], "metadata": { - "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + "description": "Log analytics workspace for diagnostic logs." } }, - "publicNetworkAccess": { + "time": { "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." - } - }, - "supportsHttpsTrafficOnly": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", + "defaultValue": "[utcNow()]", "metadata": { - "description": "Optional. The customer managed key definition." + "description": "Do not modify, used to set unique value for resource deployment." } }, - "sasExpirationPeriod": { + "storagePurpose": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + "description": "Sets purpose of the storage account." } }, - "keyType": { + "dscAgentPackageLocation": { "type": "string", - "nullable": true, - "allowedValues": [ - "Account", - "Service" - ], "metadata": { - "description": "Optional. The keyType to use with Queue & Table services." + "description": "Sets location of DSC Agent." } - } - }, - "variables": { - "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } + "storageCustomOuPath": { + "type": "string", + "metadata": { + "description": "Custom OU path for storage." } }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + "storageOuPath": { + "type": "string", + "metadata": { + "description": "OU Storage Path" + } }, - "storageAccount": { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2022-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "kind": "[parameters('kind')]", - "sku": { - "name": "[parameters('skuName')]" - }, - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "properties": { - "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", - "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", - "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", - "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", - "customDomain": { - "name": "[parameters('customDomainName')]", - "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" - }, - "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", - "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", - "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", - "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", - "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", - "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", - "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", - "isSftpEnabled": "[parameters('enableSftp')]", - "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", - "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", - "minimumTlsVersion": "[parameters('minimumTlsVersion')]", - "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", - "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", - "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" - }, - "dependsOn": [ - "cMKKeyVault::cMKKey", - "cMKKeyVault" - ] + "managedIdentityClientId": { + "type": "string", + "metadata": { + "description": "Managed Identity Client ID" + } }, - "storageAccount_diagnosticSettings": { - "copy": { - "name": "storageAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "storageAccount" - ] + "securityPrincipalName": { + "type": "string", + "metadata": { + "description": "Identity name array to grant RBAC role to access AVD application group and NTFS permissions." + } }, - "storageAccount_privateEndpoints": { - "copy": { - "name": "storageAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, + "storageAccountFqdn": { + "type": "string", + "metadata": { + "description": "storage account FDQN." + } + } + }, + "variables": { + "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]", + "varAzureCloudName": "[environment().name]", + "varWrklStoragePrivateEndpointName": "[format('pe-{0}-file', parameters('storageAccountName'))]", + "varSecurityPrincipalName": "[if(not(empty(parameters('securityPrincipalName'))), parameters('securityPrincipalName'), 'none')]", + "varAdminUserName": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('vmLocalUserName'), parameters('domainJoinUserName'))]", + "varStorageToDomainScriptArgs": "[format('-DscPath {0} -StorageAccountName {1} -StorageAccountRG {2} -StoragePurpose {3} -DomainName {4} -IdentityServiceProvider {5} -AzureCloudEnvironment {6} -SubscriptionId {7} -AdminUserName {8} -CustomOuPath {9} -OUName {10} -ShareName {11} -ClientId {12} -SecurityPrincipalName \"{13}\" -StorageAccountFqdn {14} ', parameters('dscAgentPackageLocation'), parameters('storageAccountName'), parameters('storageObjectsRgName'), parameters('storagePurpose'), parameters('identityDomainName'), parameters('identityServiceProvider'), variables('varAzureCloudName'), parameters('subId'), variables('varAdminUserName'), parameters('storageCustomOuPath'), parameters('storageOuPath'), parameters('fileShareName'), parameters('managedIdentityClientId'), variables('varSecurityPrincipalName'), parameters('storageAccountFqdn'))]", + "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]" + }, + "resources": [ + { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subId'))]", + "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -30981,42 +35789,43 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + "value": "[parameters('storageAccountName')]" }, "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" - }, - "privateDnsZoneGroupName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" - }, - "privateDnsZoneResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + "value": "[parameters('location')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + "skuName": { + "value": "[parameters('storageSku')]" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "allowBlobPublicAccess": { + "value": false }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "publicNetworkAccess": "[if(parameters('deployPrivateEndpoint'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "kind": "[if(or(equals(parameters('storageSku'), 'Premium_LRS'), equals(parameters('storageSku'), 'Premium_ZRS')), createObject('value', 'FileStorage'), createObject('value', 'StorageV2'))]", + "largeFileSharesState": "[if(or(equals(parameters('storageSku'), 'Standard_LRS'), equals(parameters('storageSku'), 'Standard_ZRS')), createObject('value', 'Enabled'), createObject('value', 'Disabled'))]", + "azureFilesIdentityBasedAuthentication": "[if(not(equals(parameters('identityServiceProvider'), 'EntraID')), createObject('value', createObject('directoryServiceOptions', if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDS', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), 'AADKERB', 'none')), 'activeDirectoryProperties', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), createObject('domainGuid', parameters('identityDomainGuid'), 'domainName', parameters('identityDomainName')), createObject()))), createObject('value', null()))]", + "accessTier": { + "value": "Hot" }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "networkAcls": "[if(parameters('deployPrivateEndpoint'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', parameters('vmsSubnetResourceId'), 'action', 'Allow')), 'ipRules', createArray())))]", + "fileServices": { + "value": { + "shares": [ + { + "name": "[parameters('fileShareName')]", + "shareQuota": "[parameters('fileShareQuotaSize')]" + } + ], + "protocolSettings": "[if(parameters('fileShareMultichannel'), createObject('smb', createObject('multichannel', createObject('enabled', parameters('fileShareMultichannel')))), createObject())]", + "diagnosticSettings": "[variables('varDiagnosticSettings')]" + } }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "privateEndpoints": "[if(parameters('deployPrivateEndpoint'), createObject('value', createArray(createObject('name', variables('varWrklStoragePrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklStoragePrivateEndpointName')), 'service', 'file', 'privateDnsZoneGroupName', split(parameters('privateDnsZoneFilesResourceId'), '/')[8], 'privateDnsZoneResourceIds', createArray(parameters('privateDnsZoneFilesResourceId'))))), createObject('value', createArray()))]", + "tags": { + "value": "[parameters('tags')]" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" } }, "template": { @@ -31026,248 +35835,392 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "4120048060064073955" + "version": "0.34.44.8038", + "templateHash": "15994741654178645865" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint.", + "name": "Storage Accounts", + "description": "This module deploys a Storage Account.", "owner": "Azure/module-maintainers" }, "definitions": { - "roleAssignmentType": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + } + }, + "privateEndpointType": { "type": "array", "items": { "type": "object", "properties": { - "roleDefinitionIdOrName": { + "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Optional. The name of the private endpoint." } }, - "principalId": { + "location": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. The location to deploy the private endpoint to." } }, - "principalType": { + "service": { "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." } }, - "description": { + "subnetResourceId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "condition": { + "privateDnsZoneGroupName": { "type": "string", "nullable": true, "metadata": { - "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\"." + "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." } }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, - "delegatedManagedIdentityResourceId": { - "type": "string", + "isManualConnection": { + "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. Manual PrivateLink Service Connections." } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "ipConfigurationsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { + }, + "manualConnectionRequestMessage": { "type": "string", + "nullable": true, + "maxLength": 140, "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." } }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } } } }, + "nullable": true, "metadata": { - "description": "Required. Properties of private endpoint IP configurations." + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } - } - } - }, - "nullable": true - }, - "manualPrivateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the private link service connection." + "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, - "properties": { + "tags": { "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, + "nullable": true, "metadata": { - "description": "Required. Properties of private link service connection." + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } } }, "nullable": true }, - "privateLinkServiceConnectionsType": { + "diagnosticSettingType": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The name of the private link service connection." + "description": "Optional. The name of diagnostic setting." } }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } } } }, + "nullable": true, "metadata": { - "description": "Required. Properties of private link service connection." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } - } - } - }, - "nullable": true - }, - "customDnsConfigType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { + }, + "logAnalyticsDestinationType": { "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, + "workspaceResourceId": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." } } }, @@ -31277,92 +36230,245 @@ "parameters": { "name": { "type": "string", + "maxLength": 24, "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "Required. Name of the Storage Account. Must be lower-case." } }, - "subnetResourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Optional. Location for all resources." } }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "nullable": true, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Optional. The managed identity definition for this resource." } }, - "customNetworkInterfaceName": { + "kind": { "type": "string", - "nullable": true, + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Optional. Type of Storage Account to create." } }, - "ipConfigurations": { - "$ref": "#/definitions/ipConfigurationsType", + "skuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS", + "Premium_ZRS", + "Standard_GZRS", + "Standard_RAGZRS" + ], "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. Storage Account Sku Name." } }, - "privateDnsZoneGroupName": { + "accessTier": { "type": "string", - "nullable": true, + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool" + ], "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." } }, - "privateDnsZoneResourceIds": { + "largeFileSharesState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + } + }, + "azureFilesIdentityBasedAuthentication": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Provides the identity based authentication settings for Azure Files." + } + }, + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "managementPolicyRules": { "type": "array", "nullable": true, "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. The Storage Account ManagementPolicies Rules." } }, - "location": { + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + } + }, + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "", "metadata": { - "description": "Optional. Location for all Resources." + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." } }, - "lock": { - "$ref": "#/definitions/lockType", + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." } }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", + "dnsEndpointType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AzureDnsZone", + "Standard" + ], "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." } }, - "tags": { + "blobServices": { "type": "object", - "nullable": true, + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + "description": "Optional. Blob service and containers to deploy." } }, - "customDnsConfigs": { - "$ref": "#/definitions/customDnsConfigType", + "fileServices": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. Custom DNS configurations." + "description": "Optional. File service and shares to deploy." } }, - "manualPrivateLinkServiceConnections": { - "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "queueServices": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + "description": "Optional. Queue service and queues to create." } }, - "privateLinkServiceConnections": { - "$ref": "#/definitions/privateLinkServiceConnectionsType", + "tableServices": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource." + "description": "Optional. Table service and tables to create." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_0", + "TLS1_1", + "TLS1_2" + ], + "metadata": { + "description": "Optional. Set the minimum TLS version on request to storage." + } + }, + "enableHierarchicalNamespace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + } + }, + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables local users feature, if set to true." + } + }, + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." } }, "enableTelemetry": { @@ -31371,28 +36477,84 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "allowedCopyScope": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AAD", + "PrivateLink" + ], + "metadata": { + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } } }, "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" }, "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" + }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -31408,73 +36570,105 @@ } } }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", "name": "[parameters('name')]", "location": "[parameters('location')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", "tags": "[parameters('tags')]", + "properties": { + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", + "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", + "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", + "customDomain": { + "name": "[parameters('customDomainName')]", + "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" + }, + "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", + "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", + "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", + "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", + "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", + "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", + "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", + "isSftpEnabled": "[parameters('enableSftp')]", + "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", + "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", + "minimumTlsVersion": "[parameters('minimumTlsVersion')]", + "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", + "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null } } ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "privateEndpoint" + "storageAccount" ] }, - "privateEndpoint_roleAssignments": { + "storageAccount_privateEndpoints": { "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -31482,422 +36676,654 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, - "privateEndpointName": { - "value": "[parameters('name')]" + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.25.53.49325", - "templateHash": "11244630631275470040" + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group.", - "owner": "Azure/module-maintainers" + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } }, "parameters": { - "privateEndpointName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "Required. Name of the private endpoint resource to create." } }, - "privateDNSResourceIds": { + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { "type": "array", - "minLength": 1, - "maxLength": 5, + "nullable": true, "metadata": { - "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "name": { + "customNetworkInterfaceName": { "type": "string", - "defaultValue": "default", + "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", - "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } } } - ] - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + "dependsOn": [ + "privateEndpoint" + ] }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" - }, - "groupId": { - "type": "string", - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_fileServices": { - "condition": "[not(empty(parameters('fileServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" - }, - "protocolSettings": { - "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" - }, - "shareDeleteRetentionPolicy": { - "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" - }, - "shares": { - "value": "[tryGet(parameters('fileServices'), 'shares')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "5174215295464783855" - }, - "name": "Storage Account File Share Services", - "description": "This module deploys a Storage Account File Share Service.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" } }, - "enabled": { - "type": "bool", - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } } } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + }, + "dependsOn": [ + "privateEndpoint" + ] } }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" } } } }, - "nullable": true - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the file service." - } - }, - "protocolSettings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Protocol settings for file service." - } - }, - "shareDeleteRetentionPolicy": { - "type": "object", - "defaultValue": { - "enabled": true, - "days": 7 - }, - "metadata": { - "description": "Optional. The service properties for soft delete." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "shares": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. File shares to create." - } - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-04-01", - "name": "[parameters('storageAccountName')]" - }, - "fileServices": { - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "protocolSettings": "[parameters('protocolSettings')]", - "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" - } - }, - "fileServices_diagnosticSettings": { - "copy": { - "name": "fileServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, "dependsOn": [ - "fileServices" + "storageAccount" ] }, - "fileServices_shares": { - "copy": { - "name": "fileServices_shares", - "count": "[length(coalesce(parameters('shares'), createArray()))]" - }, + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -31905,28 +37331,19 @@ "mode": "Incremental", "parameters": { "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "fileServicesName": { "value": "[parameters('name')]" }, - "name": { - "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" - }, - "accessTier": { - "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" - }, - "enabledProtocols": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" }, - "rootSquash": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" }, - "shareQuota": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" } }, "template": { @@ -31936,74 +37353,128 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "823140844991744662" + "version": "0.34.44.8038", + "templateHash": "5572402757180298542" }, - "name": "Storage Account File Shares", - "description": "This module deploys a Storage Account File Share.", + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service.", "owner": "Azure/module-maintainers" }, "definitions": { - "roleAssignmentType": { + "diagnosticSettingType": { "type": "array", "items": { "type": "object", "properties": { - "roleDefinitionIdOrName": { + "name": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + "description": "Optional. The name of diagnostic setting." } }, - "principalId": { - "type": "string", + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } }, - "principalType": { + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { "type": "string", "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" + "AzureDiagnostics", + "Dedicated" ], "nullable": true, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." } }, - "description": { + "workspaceResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "condition": { + "storageAccountResourceId": { "type": "string", "nullable": true, "metadata": { - "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\"." + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "conditionVersion": { + "eventHubAuthorizationRuleResourceId": { "type": "string", - "allowedValues": [ - "2.0" - ], "nullable": true, "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." } }, - "delegatedManagedIdentityResourceId": { + "eventHubName": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } } @@ -32019,295 +37490,550 @@ "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "fileServicesName": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." - } - }, "name": { "type": "string", + "defaultValue": "default", "metadata": { - "description": "Required. The name of the file share to create." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "TransactionOptimized", - "allowedValues": [ - "Premium", - "Hot", - "Cool", - "TransactionOptimized" - ], - "metadata": { - "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + "description": "Optional. The name of the file service." } }, - "shareQuota": { - "type": "int", - "defaultValue": 5120, + "protocolSettings": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + "description": "Optional. Protocol settings for file service." } }, - "enabledProtocols": { - "type": "string", - "defaultValue": "SMB", - "allowedValues": [ - "NFS", - "SMB" - ], + "shareDeleteRetentionPolicy": { + "type": "object", + "defaultValue": { + "enabled": true, + "days": 7 + }, "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + "description": "Optional. The service properties for soft delete." } }, - "rootSquash": { - "type": "string", - "defaultValue": "NoRootSquash", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + "description": "Optional. The diagnostic settings of the service." } }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", + "shares": { + "type": "array", + "nullable": true, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. File shares to create." } } }, "resources": { - "storageAccount::fileService": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" - }, "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2023-04-01", "name": "[parameters('storageAccountName')]" }, - "fileShare": { - "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2023-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", "properties": { - "accessTier": "[parameters('accessTier')]", - "shareQuota": "[parameters('shareQuota')]", - "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", - "enabledProtocols": "[parameters('enabledProtocols')]" + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" } }, - "fileShare_roleAssignments": { - "condition": "[not(empty(parameters('roleAssignments')))]", + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", + "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "fileShareResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" }, "roleAssignments": { - "value": "[parameters('roleAssignments')]" + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "16821934161134527264" + "version": "0.34.44.8038", + "templateHash": "2846593244669729605" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true } }, "parameters": { - "roleAssignments": { - "type": "array", + "storageAccountName": { + "type": "string", + "maxLength": 24, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "fileShareResourceId": { + "fileServicesName": { "type": "string", + "defaultValue": "default", "metadata": { - "description": "Required. The resource id of the file share to assign the roles to." + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." } - } - }, - "variables": { - "$fxv#0": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "scope": { - "type": "string", - "metadata": { - "description": "Required. The scope to deploy the role assignment to." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The role definition Id to assign." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "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\"" - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "defaultValue": "2.0", - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[[parameters('scope')]", - "name": "[[parameters('name')]", - "properties": { - "roleDefinitionId": "[[parameters('roleDefinitionId')]", - "principalId": "[[parameters('principalId')]", - "description": "[[parameters('description')]", - "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", - "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" - } - } - ] }, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + "accessTier": { + "type": "string", + "defaultValue": "TransactionOptimized", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } } }, - "resources": [ - { - "copy": { - "name": "fileShare_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" + } + }, + "fileShare_roleAssignments": { + "condition": "[not(empty(parameters('roleAssignments')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2021-04-01", - "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", "properties": { - "mode": "Incremental", "expressionEvaluationOptions": { - "scope": "Outer" + "scope": "inner" }, - "template": "[variables('$fxv#0')]", + "mode": "Incremental", "parameters": { - "scope": { - "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" - }, - "name": { - "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" - }, - "roleDefinitionId": { - "value": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]" - }, - "principalId": { - "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" - }, - "principalType": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" + "fileShareResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" }, - "description": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "11422901802944437310" + } }, - "condition": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" + "parameters": { + "roleAssignments": { + "type": "array", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "fileShareResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the file share to assign the roles to." + } + } }, - "conditionVersion": { - "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "description": "[[parameters('description')]", + "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + }, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } }, - "delegatedManagedIdentityResourceId": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - } + "resources": [ + { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2021-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" + }, + "name": { + "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" + }, + "roleDefinitionId": { + "value": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]" + }, + "principalId": { + "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "condition": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": { + "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" + }, + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + } + } + } + ] } - } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" } - ] + } } }, "dependsOn": [ - "fileShare" + "fileServices", + "storageAccount" ] } }, @@ -32315,21 +38041,21 @@ "name": { "type": "string", "metadata": { - "description": "The name of the deployed file share." + "description": "The name of the deployed file share service." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed file share." + "description": "The resource ID of the deployed file share service." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed file share." + "description": "The resource group of the deployed file share service." }, "value": "[resourceGroup().name]" } @@ -32337,401 +38063,394 @@ } }, "dependsOn": [ - "fileServices", "storageAccount" ] } }, "outputs": { - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the deployed file share service." + "description": "The resource ID of the deployed storage account." }, - "value": "[parameters('name')]" + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" }, - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the deployed file share service." + "description": "The name of the deployed storage account." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + "value": "[parameters('name')]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed file share service." + "description": "The resource group of the deployed storage account." }, "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2022-09-01', 'full').location]" } } } - }, - "dependsOn": [ - "storageAccount" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed storage account." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed storage account." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed storage account." - }, - "value": "[resourceGroup().name]" - }, - "primaryBlobEndpoint": { - "type": "string", - "metadata": { - "description": "The primary blob endpoint reference if blob services are deployed." - }, - "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('storageAccount', '2022-09-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[not(equals(parameters('identityServiceProvider'), 'EntraID'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Add-{0}-Storage-Setup-{1}', parameters('storagePurpose'), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "virtualMachineName": { - "value": "[parameters('managementVmName')]" - }, - "file": { - "value": "[parameters('storageToDomainScript')]" - }, - "scriptArguments": { - "value": "[variables('varStorageToDomainScriptArgs')]" - }, - "adminUserPassword": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.KeyVault/vaults', parameters('wrklKvName'))), 'secretName', 'vmLocalUserPassword')), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.KeyVault/vaults', parameters('wrklKvName'))), 'secretName', 'domainJoinUserPassword')))]", - "baseScriptUri": { - "value": "[parameters('storageToDomainScriptUri')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "4206601194007058149" - }, - "name": "AVD LZA storage", - "description": "Configures domain join settings on storage account via VM custom script extension", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Virtual machine name." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy compute services." - } - }, - "baseScriptUri": { - "type": "string", - "metadata": { - "description": "Location for the AVD agent installation package." - } - }, - "file": { - "type": "string" - }, - "scriptArguments": { - "type": "string", - "metadata": { - "description": "Arguments for domain join script." - } - }, - "adminUserPassword": { - "type": "securestring", - "metadata": { - "description": "Domain join user password." } }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - } - }, - "resources": [ { + "condition": "[not(equals(parameters('identityServiceProvider'), 'EntraID'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('VM-Ext-AVM-{0}', parameters('time'))]", + "name": "[format('Add-{0}-Storage-Setup-{1}', parameters('storagePurpose'), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "AzureFilesDomainJoin" - }, - "virtualMachineName": { - "value": "[parameters('virtualMachineName')]" - }, "location": { "value": "[parameters('location')]" }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "CustomScriptExtension" - }, - "typeHandlerVersion": { - "value": "1.10" - }, - "autoUpgradeMinorVersion": { - "value": true + "virtualMachineName": { + "value": "[parameters('managementVmName')]" }, - "enableAutomaticUpgrade": { - "value": false + "file": { + "value": "[parameters('storageToDomainScript')]" }, - "settings": { - "value": {} + "scriptArguments": { + "value": "[variables('varStorageToDomainScriptArgs')]" }, - "protectedSettings": { - "value": { - "fileUris": "[array(parameters('baseScriptUri'))]", - "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -File {0} {1} -AdminUserPassword {2} -verbose', parameters('file'), parameters('scriptArguments'), parameters('adminUserPassword'))]" - } + "adminUserPassword": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'vmLocalUserPassword')), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'domainJoinUserPassword')))]", + "baseScriptUri": { + "value": "[parameters('storageToDomainScriptUri')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" + "version": "0.34.44.8038", + "templateHash": "7337889415739790800" }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" + "name": "AVD LZA storage", + "description": "Configures domain join settings on storage account via VM custom script extension", + "owner": "Azure/avdaccelerator" }, "parameters": { "virtualMachineName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." + "description": "Virtual machine name." } }, "location": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. The location the extension is deployed to." + "description": "Location where to deploy compute services." } }, - "publisher": { + "baseScriptUri": { "type": "string", "metadata": { - "description": "Required. The name of the extension handler publisher." + "description": "Location for the AVD agent installation package." } }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } + "file": { + "type": "string" }, - "typeHandlerVersion": { + "scriptArguments": { "type": "string", "metadata": { - "description": "Required. Specifies the version of the script handler." + "description": "Arguments for domain join script." } }, - "autoUpgradeMinorVersion": { - "type": "bool", + "adminUserPassword": { + "type": "securestring", "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + "description": "Domain join user password." } }, - "forceUpdateTag": { + "time": { "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, + "defaultValue": "[utcNow()]", "metadata": { - "description": "Optional. Tags of the resource." + "description": "Do not modify, used to set unique value for resource deployment." } } }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('VM-Ext-AVM-{0}', parameters('time'))]", "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "AzureFilesDomainJoin" + }, + "virtualMachineName": { + "value": "[parameters('virtualMachineName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "CustomScriptExtension" + }, + "typeHandlerVersion": { + "value": "1.10" + }, + "autoUpgradeMinorVersion": { + "value": true + }, + "enableAutomaticUpgrade": { + "value": false + }, + "settings": { + "value": {} + }, + "protectedSettings": { + "value": { + "fileUris": "[array(parameters('baseScriptUri'))]", + "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -File {0} {1} -AdminUserPassword {2} -verbose', parameters('file'), parameters('scriptArguments'), parameters('adminUserPassword'))]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } } } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } + ] } - } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time')))]" + ] } - ] + ], + "outputs": { + "storageAccountResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))), '2022-09-01').outputs.resourceId.value]" + } + } } }, "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time')))]" + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]" ] } ], "outputs": { - "storageAccountResourceId": { + "fslogixFileSharePath": { + "type": "string", + "value": "[if(parameters('createFslogixDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('\\\\{0}.file.{1}\\{2}', variables('varFslogixStorageName'), environment().suffixes.storage, variables('varFslogixFileShareName')), if(equals(parameters('storageService'), 'ANF'), format('\\\\{0}\\{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Get-ANF-SMB-Server-FQDN-{0}', parameters('time'))), '2022-09-01').outputs.anfSmbServerFqdn.value, last(split(reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfFslogixVolumeResourceId.value, '/'))), '')), '')]" + }, + "appAttachFileSharePath": { + "type": "string", + "value": "[if(parameters('createAppAttachDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('\\\\{0}.file.{1}\\{2}', variables('varAppAttachStorageName'), environment().suffixes.storage, variables('varAppAttachFileShareName')), if(equals(parameters('storageService'), 'ANF'), format('\\\\{0}\\{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Get-ANF-SMB-Server-FQDN-{0}', parameters('time'))), '2022-09-01').outputs.anfSmbServerFqdn.value, last(split(reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfAppAttachVolumeResourceId.value, '/'))), '')), '')]" + }, + "fslogixStorageAccountResourceId": { + "type": "string", + "value": "[if(and(parameters('createFslogixDeployment'), equals(parameters('storageService'), 'AzureFiles')), reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-FSLogix-ST-{0}', parameters('time'))), '2022-09-01').outputs.storageAccountResourceId.value, '')]" + }, + "appAttachStorageAccountResourceId": { "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))), '2022-09-01').outputs.resourceId.value]" + "value": "[if(and(parameters('createAppAttachDeployment'), equals(parameters('storageService'), 'AzureFiles')), reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-AppA-{0}', parameters('time'))), '2022-09-01').outputs.storageAccountResourceId.value, '')]" } } } }, "dependsOn": [ "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-FSLogix-{0}', parameters('time')))]", "[subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]", "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]", "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]" + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]", + "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time')))]" ] }, { @@ -32752,7 +38471,7 @@ }, "mode": "Incremental", "parameters": { - "asgResourceId": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createAvdFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', format('{0}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.applicationSecurityGroupResourceId.value)), createObject('value', ''))]", + "asgResourceId": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', format('{0}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.applicationSecurityGroupResourceId.value)), createObject('value', ''))]", "availability": { "value": "[parameters('availability')]" }, @@ -32766,7 +38485,7 @@ "value": "[variables('varComputeObjectsRgName')]" }, "configureFslogix": { - "value": "[parameters('createAvdFslogixDeployment')]" + "value": "[parameters('createFslogixDeployment')]" }, "count": "[if(and(equals(range(1, variables('varSessionHostBatchCount'))[copyIndex()], variables('varSessionHostBatchCount')), greater(variables('varMaxSessionHostsDivisionRemainderValue'), 0)), createObject('value', variables('varMaxSessionHostsDivisionRemainderValue')), createObject('value', variables('varMaxSessionHostsPerTemplate')))]", "countIndex": "[if(equals(range(1, variables('varSessionHostBatchCount'))[copyIndex()], 1), createObject('value', parameters('avdSessionHostCountIndex')), createObject('value', add(mul(sub(range(1, variables('varSessionHostBatchCount'))[copyIndex()], 1), variables('varMaxSessionHostsPerTemplate')), parameters('avdSessionHostCountIndex'))))]", @@ -32799,10 +38518,8 @@ "encryptionAtHost": { "value": "[parameters('diskZeroTrust')]" }, - "fslogixSharePath": { - "value": "[variables('varFslogixSharePath')]" - }, - "fslogixStorageAccountResourceId": "[if(equals(parameters('avdIdentityServiceProvider'), 'EntraID'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-FSLogix-{0}', parameters('time'))), '2022-09-01').outputs.storageAccountResourceId.value), createObject('value', ''))]", + "fslogixSharePath": "[if(parameters('createFslogixDeployment'), createObject('value', reference(subscriptionResourceId(format('{0}', parameters('avdWorkloadSubsId')), 'Microsoft.Resources/deployments', format('SMB-Storage-{0}', parameters('time'))), '2022-09-01').outputs.fslogixFileSharePath.value), createObject('value', ''))]", + "fslogixStorageAccountResourceId": "[if(and(equals(parameters('avdIdentityServiceProvider'), 'EntraID'), parameters('createFslogixDeployment')), createObject('value', reference(subscriptionResourceId(format('{0}', parameters('avdWorkloadSubsId')), 'Microsoft.Resources/deployments', format('SMB-Storage-{0}', parameters('time'))), '2022-09-01').outputs.fslogixStorageAccountResourceId.value), createObject('value', ''))]", "hostPoolResourceId": { "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', format('AVD-MGMT-Plane-{0}', parameters('time'))), '2022-09-01').outputs.hostPoolResourceId.value]" }, @@ -32864,8 +38581,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "14644484978386040734" + "version": "0.34.44.8038", + "templateHash": "13361150904998745536" } }, "parameters": { @@ -33246,8 +38963,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "11050393703898934384" + "version": "0.34.44.8038", + "templateHash": "13031055217657209142" }, "name": "Virtual Machines", "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", @@ -34076,8 +39793,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "11733090358061195696" + "version": "0.34.44.8038", + "templateHash": "4081873631846149092" } }, "definitions": { @@ -35629,8 +41346,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -35835,8 +41552,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -36036,8 +41753,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -36244,8 +41961,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -36445,8 +42162,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -36643,8 +42360,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -36902,8 +42619,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -37106,8 +42823,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6738255057321581868" + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -37291,8 +43008,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "6919490302839277834" + "version": "0.34.44.8038", + "templateHash": "5134409313697181849" } }, "parameters": { @@ -37384,8 +43101,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "1457171873160232908" + "version": "0.34.44.8038", + "templateHash": "1149225665070592315" } }, "parameters": { @@ -37518,10 +43235,10 @@ }, "dependsOn": [ "baselineResourceGroups", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-FSLogix-{0}', parameters('time')))]", "[subscriptionResourceId('Microsoft.Resources/deployments', format('AVD-MGMT-Plane-{0}', parameters('time')))]", "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]", "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", + "[subscriptionResourceId(format('{0}', parameters('avdWorkloadSubsId')), 'Microsoft.Resources/deployments', format('SMB-Storage-{0}', parameters('time')))]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]", "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time')))]" ] @@ -37555,8 +43272,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "13528932355889121125" + "version": "0.34.44.8038", + "templateHash": "12630662508259220166" } }, "parameters": { @@ -37645,8 +43362,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "14608202935063519743" + "version": "0.34.44.8038", + "templateHash": "15296566503434303805" } }, "parameters": { @@ -37791,8 +43508,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "11624908005940613332" + "version": "0.34.44.8038", + "templateHash": "10386382608825992636" }, "name": "Policy Assignments (Resource Group scope)", "description": "This module deploys a Policy Assignment at a Resource Group scope.", @@ -38042,8 +43759,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "15388209522748095710" + "version": "0.34.44.8038", + "templateHash": "8141314117626850328" }, "name": "Policy Insights Remediations (Resource Group scope)", "description": "This module deploys a Policy Insights Remediation on a Resource Group scope.", @@ -38215,8 +43932,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "17890795729608815451" + "version": "0.34.44.8038", + "templateHash": "17973539529965183406" } }, "parameters": { diff --git a/workload/bicep/deploy-baseline.bicep b/workload/bicep/deploy-baseline.bicep index 6bc5ce384..08acb585a 100644 --- a/workload/bicep/deploy-baseline.bicep +++ b/workload/bicep/deploy-baseline.bicep @@ -680,7 +680,7 @@ var varZtKvName = avdUseCustomNaming ? '${ztKvPrefixCustomName}-${varComputeStorageResourcesNamingStandard}-${varNamingUniqueStringTwoChar}' : 'kv-key-${varComputeStorageResourcesNamingStandard}-${varNamingUniqueStringTwoChar}' // max length limit 24 characters var varZtKvPrivateEndpointName = 'pe-${varZtKvName}-vault' -var varBaseScriptUri = 'https://raw.githubusercontent.com/azure/avdaccelerator/main/workload/' +var varBaseScriptUri = 'https://raw.githubusercontent.com/azure/avdaccelerator/anf-fslogix/workload/' var varSessionHostConfigurationScriptUri = '${varBaseScriptUri}scripts/Set-SessionHostConfiguration.ps1' var varSessionHostConfigurationScript = 'Set-SessionHostConfiguration.ps1' var varMaxSessionHostsPerTemplate = 10 diff --git a/workload/bicep/deploy-baseline.json b/workload/bicep/deploy-baseline.json new file mode 100644 index 000000000..befe571e0 --- /dev/null +++ b/workload/bicep/deploy-baseline.json @@ -0,0 +1,44083 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "18159930501355149539" + }, + "name": "AVD Accelerator - Baseline Deployment", + "description": "AVD Accelerator - Deployment Baseline", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "deploymentPrefix": { + "type": "string", + "defaultValue": "AVD1", + "minLength": 2, + "maxLength": 4, + "metadata": { + "description": "The name of the resource group to deploy. (Default: AVD1)" + } + }, + "deploymentEnvironment": { + "type": "string", + "defaultValue": "Dev", + "allowedValues": [ + "Dev", + "Test", + "Prod" + ], + "metadata": { + "description": "The name of the resource group to deploy. (Default: Dev)" + } + }, + "diskEncryptionKeyExpirationInDays": { + "type": "int", + "defaultValue": 60, + "minValue": 30, + "maxValue": 730, + "metadata": { + "description": "This value is used to set the expiration date on the disk encryption key. (Default: 60)" + } + }, + "avdSessionHostLocation": { + "type": "string", + "metadata": { + "description": "Required. Location where to deploy compute services." + } + }, + "avdManagementPlaneLocation": { + "type": "string", + "metadata": { + "description": "Required. Location where to deploy AVD management plane." + } + }, + "avdWorkloadSubsId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario. (Default: \"\")" + } + }, + "avdServicePrincipalObjectId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Azure Virtual Desktop Enterprise Application object ID (Enterprise app name: Azure Virtual Desktop) . (Default: \"\")" + } + }, + "avdArmServicePrincipalObjectId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Azure Virtual Desktop ARM Enterprise Application Object Id (Enterprise app name: Azure Virtual Desktop ARM Provider). Required for the deployment of App Attach File Share with EntraID identity provider. (Default: \"\")" + } + }, + "avdVmLocalUserName": { + "type": "string", + "metadata": { + "description": "AVD session host local username." + } + }, + "avdVmLocalUserPassword": { + "type": "securestring", + "metadata": { + "description": "AVD session host local password." + } + }, + "avdIdentityServiceProvider": { + "type": "string", + "defaultValue": "ADDS", + "allowedValues": [ + "ADDS", + "EntraDS", + "EntraID", + "EntraIDKerberos" + ], + "metadata": { + "description": "Required, The service providing domain services for Azure Virtual Desktop. (Default: ADDS)" + } + }, + "createIntuneEnrollment": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Required, Enroll session hosts on Intune. (Default: false)" + } + }, + "avdSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Identity ID(s) to grant RBAC role to access AVD application group and NTFS permissions. (Default: [])" + } + }, + "identityDomainName": { + "type": "string", + "defaultValue": "none", + "metadata": { + "description": "FQDN of on-premises AD domain, used for FSLogix storage configuration and NTFS setup. (Default: \"none\")" + } + }, + "identityDomainGuid": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "GUID of on-premises AD domain, used for FSLogix storage configuration and NTFS setup. (Default: \"\")" + } + }, + "avdDomainJoinUserName": { + "type": "string", + "defaultValue": "none", + "metadata": { + "description": "AVD session host domain join user principal name. (Default: \"none\")" + } + }, + "avdDomainJoinUserPassword": { + "type": "securestring", + "defaultValue": "none", + "metadata": { + "description": "AVD session host domain join password. (Default: \"none\")" + } + }, + "avdOuPath": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "OU path to join AVd VMs. (Default: \"\")" + } + }, + "avdHostPoolType": { + "type": "string", + "defaultValue": "Pooled", + "allowedValues": [ + "Personal", + "Pooled" + ], + "metadata": { + "description": "AVD host pool type. (Default: Pooled)" + } + }, + "hostPoolPreferredAppGroupType": { + "type": "string", + "defaultValue": "Desktop", + "allowedValues": [ + "Desktop", + "RemoteApp" + ], + "metadata": { + "description": "Optional. The type of preferred application group type, default to Desktop Application Group." + } + }, + "hostPoolPublicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled", + "EnabledForClientsOnly", + "EnabledForSessionHostsOnly" + ], + "metadata": { + "description": "Enables or Disables public network access on the host pool. (Default: Enabled.)" + } + }, + "workspacePublicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Default to Enabled. Enables or Disables public network access on the workspace." + } + }, + "avdPersonalAssignType": { + "type": "string", + "defaultValue": "Automatic", + "allowedValues": [ + "Automatic", + "Direct" + ], + "metadata": { + "description": "AVD host pool type. (Default: Automatic)" + } + }, + "avdHostPoolLoadBalancerType": { + "type": "string", + "defaultValue": "BreadthFirst", + "allowedValues": [ + "BreadthFirst", + "DepthFirst" + ], + "metadata": { + "description": "AVD host pool load balacing type. (Default: BreadthFirst)" + } + }, + "hostPoolMaxSessions": { + "type": "int", + "defaultValue": 8, + "metadata": { + "description": "AVD host pool maximum number of user sessions per session host. (Default: 8)" + } + }, + "avdStartVmOnConnect": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "AVD host pool start VM on Connect. (Default: true)" + } + }, + "avdHostPoolRdpProperties": { + "type": "string", + "defaultValue": "audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2", + "metadata": { + "description": "AVD host pool Custom RDP properties. (Default: audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2)" + } + }, + "avdDeployScalingPlan": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "AVD deploy scaling plan. (Default: true)" + } + }, + "createAvdVnet": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Create new virtual network. (Default: true)" + } + }, + "existingVnetAvdSubnetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Existing virtual network subnet for AVD. (Default: \"\")" + } + }, + "existingVnetPrivateEndpointSubnetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Existing virtual network subnet for private endpoints. (Default: \"\")" + } + }, + "existingVnetAnfSubnetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Existing virtual network subnet for ANF. (Default: \"\")" + } + }, + "existingHubVnetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Existing hub virtual network for peering. (Default: \"\")" + } + }, + "avdVnetworkAddressPrefixes": { + "type": "string", + "defaultValue": "10.10.0.0/16", + "metadata": { + "description": "AVD virtual network address prefixes. (Default: 10.10.0.0/16)" + } + }, + "vNetworkAvdSubnetAddressPrefix": { + "type": "string", + "defaultValue": "10.10.1.0/24", + "metadata": { + "description": "AVD virtual network subnet address prefix. (Default: 10.10.1.0/24)" + } + }, + "vNetworkPrivateEndpointSubnetAddressPrefix": { + "type": "string", + "defaultValue": "10.10.2.0/27", + "metadata": { + "description": "private endpoints virtual network subnet address prefix. (Default: 10.10.2.0/27)" + } + }, + "vNetworkAnfSubnetAddressPrefix": { + "type": "string", + "defaultValue": "10.10.3.0/26", + "metadata": { + "description": "ANF virtual network subnet address prefix. (Default: 10.10.3.0/26)" + } + }, + "customDnsIps": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "custom DNS servers IPs. (Default: \"\")" + } + }, + "deployDDoSNetworkProtection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Deploy DDoS Network Protection for virtual network. (Default: true)" + } + }, + "deployPrivateEndpointKeyvaultStorage": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy private endpoints for key vault and storage. (Default: true)" + } + }, + "deployAvdPrivateLinkService": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Deploys the private link for AVD. Requires resource provider registration or re-registration. (Default: false)" + } + }, + "createPrivateDnsZones": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Create new Azure private DNS zones for private endpoints. (Default: true)" + } + }, + "avdVnetPrivateDnsZoneConnectionResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The ResourceID of the AVD Private DNS Zone for Connection. (privatelink.wvd.azure.com). Only required if createPrivateDNSZones is set to false." + } + }, + "avdVnetPrivateDnsZoneDiscoveryResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The ResourceID of the AVD Private DNS Zone for Discovery. (privatelink-global.wvd.azure.com). Only required if createPrivateDNSZones is set to false." + } + }, + "avdVnetPrivateDnsZoneFilesId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Use existing Azure private DNS zone for Azure files. (Default: \"\")" + } + }, + "avdVnetPrivateDnsZoneKeyvaultId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Use existing Azure private DNS zone for key vault privatelink.vaultcore.azure.net or privatelink.vaultcore.usgovcloudapi.net. (Default: \"\")" + } + }, + "vNetworkGatewayOnHub": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Does the hub contains a virtual network gateway. (Default: false)" + } + }, + "createFslogixDeployment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy Fslogix setup. (Default: true)" + } + }, + "storageService": { + "type": "string", + "defaultValue": "AzureFiles", + "allowedValues": [ + "ANF", + "AzureFiles" + ], + "metadata": { + "description": "Type of storage service to deploy for FSLogix. (Default: AzureFiles)" + } + }, + "createAppAttachDeployment": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Deploy App Attach setup. (Default: false)" + } + }, + "fslogixFileShareQuotaSize": { + "type": "int", + "defaultValue": 100, + "metadata": { + "description": "Fslogix file share size in GB. (Default: 100)" + } + }, + "appAttachFileShareQuotaSize": { + "type": "int", + "defaultValue": 100, + "metadata": { + "description": "App Attach file share size in GB. (Default: 100)" + } + }, + "avdDeploySessionHosts": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy new session hosts. (Default: true)" + } + }, + "deployGpuPolicies": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Deploy VM GPU extension policies. (Default: false)" + } + }, + "avdDeployMonitoring": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Deploy AVD monitoring resources and setings. (Default: false)" + } + }, + "deployAlaWorkspace": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploy AVD Azure log analytics workspace. (Default: true)" + } + }, + "deployCustomPolicyMonitoring": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Create and assign custom Azure Policy for diagnostic settings for the AVD Log Analytics workspace. (Default: false)" + } + }, + "avdAlaWorkspaceDataRetention": { + "type": "int", + "defaultValue": 90, + "metadata": { + "description": "AVD Azure log analytics workspace data retention. (Default: 90)" + } + }, + "alaExistingWorkspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Existing Azure log analytics workspace resource ID to connect to. (Default: \"\")" + } + }, + "avdDeploySessionHostsCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 100, + "metadata": { + "description": "Quantity of session hosts to deploy. (Default: 1)" + } + }, + "avdSessionHostCountIndex": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "The session host number to begin with for the deployment. This is important when adding virtual machines to ensure the names do not conflict. (Default: 1)" + } + }, + "availability": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "None", + "AvailabilityZones" + ], + "metadata": { + "description": "When set to AvailabilityZones, VMs are distributed across availability zones, when set to None, VMs are deployed at regional level." + } + }, + "zoneRedundantStorage": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "When true, Zone Redundant Storage (ZRS) is used, when set to false, Locally Redundant Storage (LRS) is used. (Default: false)" + } + }, + "availabilityZones": { + "type": "array", + "defaultValue": [ + "1", + "2", + "3" + ], + "allowedValues": [ + "1", + "2", + "3" + ], + "metadata": { + "description": "The Availability Zones to use for the session hosts." + } + }, + "fslogixStoragePerformance": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Standard", + "Premium", + "Ultra" + ], + "metadata": { + "description": "SKU for FSLogix storage. Recommended tier is Premium for storage account and Standard for ANF. (Default: Premium)" + } + }, + "appAttachStoragePerformance": { + "type": "string", + "defaultValue": "Premium", + "allowedValues": [ + "Standard", + "Premium", + "Ultra" + ], + "metadata": { + "description": "SKU for App Attach storage. RRecommended tier is Premium for storage account and Standard for ANF. (Default: Premium)" + } + }, + "diskZeroTrust": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enables a zero trust configuration on the session host disks. (Default: false)" + } + }, + "avdSessionHostsSize": { + "type": "string", + "defaultValue": "Standard_D4ads_v5", + "metadata": { + "description": "Session host VM size. (Default: Standard_D4ads_v5)" + } + }, + "avdSessionHostDiskType": { + "type": "string", + "defaultValue": "Premium_LRS", + "metadata": { + "description": "OS disk type for session host. (Default: Premium_LRS)" + } + }, + "customOsDiskSizeGB": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Custom OS Disk Size." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enables accelerated Networking on the session hosts.\nIf using a Azure Compute Gallery Image, the Image Definition must have been configured with\nthe \\'isAcceleratedNetworkSupported\\' property set to \\'true\\'.\n" + } + }, + "securityType": { + "type": "string", + "defaultValue": "TrustedLaunch", + "allowedValues": [ + "Standard", + "TrustedLaunch" + ], + "metadata": { + "description": "Specifies the securityType of the virtual machine. \"ConfidentialVM\" and \"TrustedLaunch\" require a Gen2 Image. (Default: TrustedLaunch)" + } + }, + "secureBootEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch or ConfidentialVM to enable UefiSettings. (Default: true)" + } + }, + "vTpmEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch or ConfidentialVM to enable UefiSettings. (Default: true)" + } + }, + "useSharedImage": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Set to deploy image from Azure Compute Gallery. (Default: false)" + } + }, + "mpImageOffer": { + "type": "string", + "defaultValue": "Office-365", + "metadata": { + "description": "AVD OS image offer. (Default: Office-365)" + } + }, + "mpImageSku": { + "type": "string", + "defaultValue": "win11-24h2-avd-m365", + "metadata": { + "description": "AVD OS image SKU. (Default: win11-24h2-avd-m365)" + } + }, + "avdCustomImageDefinitionId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Source custom image ID. (Default: \"\")" + } + }, + "managementVmOsImage": { + "type": "string", + "defaultValue": "winServer_2022_Datacenter_smalldisk_g2", + "metadata": { + "description": "Management VM image SKU (Default: winServer_2022_Datacenter_smalldisk_g2)" + } + }, + "storageOuPath": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "OU name for Azure Storage Account or Azure Netapp Files. It is recommended to create a new AD Organizational Unit (OU) in AD and disable password expiration policy on computer accounts or service logon accounts accordingly. (Default: \"\")" + } + }, + "avdUseCustomNaming": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "AVD resources custom naming. (Default: false)" + } + }, + "avdServiceObjectsRgCustomName": { + "type": "string", + "defaultValue": "rg-avd-app1-dev-use2-service-objects", + "maxLength": 90, + "metadata": { + "description": "AVD service resources resource group custom name. (Default: rg-avd-app1-dev-use2-service-objects)" + } + }, + "avdNetworkObjectsRgCustomName": { + "type": "string", + "defaultValue": "rg-avd-app1-dev-use2-network", + "maxLength": 90, + "metadata": { + "description": "AVD network resources resource group custom name. (Default: rg-avd-app1-dev-use2-network)" + } + }, + "avdComputeObjectsRgCustomName": { + "type": "string", + "defaultValue": "rg-avd-app1-dev-use2-pool-compute", + "maxLength": 90, + "metadata": { + "description": "AVD network resources resource group custom name. (Default: rg-avd-app1-dev-use2-pool-compute)" + } + }, + "avdStorageObjectsRgCustomName": { + "type": "string", + "defaultValue": "rg-avd-app1-dev-use2-storage", + "maxLength": 90, + "metadata": { + "description": "AVD network resources resource group custom name. (Default: rg-avd-app1-dev-use2-storage)" + } + }, + "avdMonitoringRgCustomName": { + "type": "string", + "defaultValue": "rg-avd-dev-use2-monitoring", + "maxLength": 90, + "metadata": { + "description": "AVD monitoring resource group custom name. (Default: rg-avd-dev-use2-monitoring)" + } + }, + "avdVnetworkCustomName": { + "type": "string", + "defaultValue": "vnet-app1-dev-use2-001", + "maxLength": 64, + "metadata": { + "description": "AVD virtual network custom name. (Default: vnet-app1-dev-use2-001)" + } + }, + "avdAlaWorkspaceCustomName": { + "type": "string", + "defaultValue": "log-avd-app1-dev-use2", + "maxLength": 64, + "metadata": { + "description": "AVD Azure log analytics workspace custom name. (Default: log-avd-app1-dev-use2)" + } + }, + "avdVnetworkSubnetCustomName": { + "type": "string", + "defaultValue": "snet-avd-app1-dev-use2-001", + "maxLength": 80, + "metadata": { + "description": "AVD virtual network subnet custom name. (Default: snet-avd-app1-dev-use2-001)" + } + }, + "privateEndpointVnetworkSubnetCustomName": { + "type": "string", + "defaultValue": "snet-pe-app1-dev-use2-001", + "maxLength": 80, + "metadata": { + "description": "private endpoints virtual network subnet custom name. (Default: snet-pe-app1-dev-use2-001)" + } + }, + "anfVnetworkSubnetCustomName": { + "type": "string", + "defaultValue": "snet-anf-app1-dev-use2-001", + "maxLength": 80, + "metadata": { + "description": "ANF virtual network subnet custom name. (Default: snet-anf-app1-dev-use2-001)" + } + }, + "avdNetworksecurityGroupCustomName": { + "type": "string", + "defaultValue": "nsg-avd-app1-dev-use2-001", + "maxLength": 80, + "metadata": { + "description": "AVD network security group custom name. (Default: nsg-avd-app1-dev-use2-001)" + } + }, + "privateEndpointNetworksecurityGroupCustomName": { + "type": "string", + "defaultValue": "nsg-pe-app1-dev-use2-001", + "maxLength": 80, + "metadata": { + "description": "Private endpoint network security group custom name. (Default: nsg-pe-app1-dev-use2-001)" + } + }, + "anfNetworksecurityGroupCustomName": { + "type": "string", + "defaultValue": "nsg-anf-app1-dev-use2-001", + "maxLength": 80, + "metadata": { + "description": "ANF network security group custom name. (Default: nsg-anf-app1-dev-use2-001)" + } + }, + "avdRouteTableCustomName": { + "type": "string", + "defaultValue": "route-avd-app1-dev-use2-001", + "maxLength": 80, + "metadata": { + "description": "AVD route table custom name. (Default: route-avd-app1-dev-use2-001)" + } + }, + "privateEndpointRouteTableCustomName": { + "type": "string", + "defaultValue": "route-pe-app1-dev-use2-001", + "maxLength": 80, + "metadata": { + "description": "Private endpoint route table custom name. (Default: route-avd-app1-dev-use2-001)" + } + }, + "avdApplicationSecurityGroupCustomName": { + "type": "string", + "defaultValue": "asg-app1-dev-use2-001", + "maxLength": 80, + "metadata": { + "description": "AVD application security custom name. (Default: asg-app1-dev-use2-001)" + } + }, + "avdWorkSpaceCustomName": { + "type": "string", + "defaultValue": "vdws-app1-dev-use2-001", + "maxLength": 64, + "metadata": { + "description": "AVD workspace custom name. (Default: vdws-app1-dev-use2-001)" + } + }, + "avdWorkSpaceCustomFriendlyName": { + "type": "string", + "defaultValue": "App1 - Dev - East US 2 - 001", + "maxLength": 64, + "metadata": { + "description": "AVD workspace custom friendly (Display) name. (Default: App1 - Dev - East US 2 - 001)" + } + }, + "avdHostPoolCustomName": { + "type": "string", + "defaultValue": "vdpool-app1-dev-use2-001", + "maxLength": 64, + "metadata": { + "description": "AVD host pool custom name. (Default: vdpool-app1-dev-use2-001)" + } + }, + "avdHostPoolCustomFriendlyName": { + "type": "string", + "defaultValue": "App1 - Dev - East US 2 - 001", + "maxLength": 64, + "metadata": { + "description": "AVD host pool custom friendly (Display) name. (Default: App1 - East US - Dev - 001)" + } + }, + "avdScalingPlanCustomName": { + "type": "string", + "defaultValue": "vdscaling-app1-dev-use2-001", + "maxLength": 64, + "metadata": { + "description": "AVD scaling plan custom name. (Default: vdscaling-app1-dev-use2-001)" + } + }, + "avdApplicationGroupCustomName": { + "type": "string", + "defaultValue": "vdag-desktop-app1-dev-use2-001", + "maxLength": 64, + "metadata": { + "description": "AVD desktop application group custom name. (Default: vdag-desktop-app1-dev-use2-001)" + } + }, + "avdApplicationGroupCustomFriendlyName": { + "type": "string", + "defaultValue": "Desktops - App1 - Dev - East US 2 - 001", + "maxLength": 64, + "metadata": { + "description": "AVD desktop application group custom friendly (Display) name. (Default: Desktops - App1 - East US - Dev - 001)" + } + }, + "avdSessionHostCustomNamePrefix": { + "type": "string", + "defaultValue": "vmapp1duse2", + "maxLength": 11, + "metadata": { + "description": "AVD session host prefix custom name. (Default: vmapp1duse2)" + } + }, + "storageAccountPrefixCustomName": { + "type": "string", + "defaultValue": "st", + "maxLength": 2, + "metadata": { + "description": "AVD FSLogix and App Attach storage account prefix custom name. (Default: st)" + } + }, + "anfAccountCustomName": { + "type": "string", + "defaultValue": "anf-acc-app1-dev-use2-001", + "metadata": { + "description": "AVD FSLogix and App Attach storage account prefix custom name. (Default: anf-acc-app1-dev-use2-001)" + } + }, + "fslogixFileShareCustomName": { + "type": "string", + "defaultValue": "fslogix-pc-app1-dev-use2-001", + "metadata": { + "description": "FSLogix file share name. (Default: fslogix-pc-app1-dev-001)" + } + }, + "appAttachFileShareCustomName": { + "type": "string", + "defaultValue": "appa-app1-dev-use2-001", + "metadata": { + "description": "App Attach file share name. (Default: appa-app1-dev-001)" + } + }, + "avdWrklKvPrefixCustomName": { + "type": "string", + "defaultValue": "kv-sec", + "maxLength": 6, + "metadata": { + "description": "AVD keyvault prefix custom name (with Zero Trust to store credentials to domain join and local admin). (Default: kv-sec)" + } + }, + "ztDiskEncryptionSetCustomNamePrefix": { + "type": "string", + "defaultValue": "des-zt", + "maxLength": 6, + "metadata": { + "description": "AVD disk encryption set custom name. (Default: des-zt)" + } + }, + "ztKvPrefixCustomName": { + "type": "string", + "defaultValue": "kv-key", + "maxLength": 6, + "metadata": { + "description": "AVD key vault custom name for zero trust and store store disk encryption key (Default: kv-key)" + } + }, + "createResourceTags": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Apply tags on resources and resource groups. (Default: false)" + } + }, + "workloadNameTag": { + "type": "string", + "defaultValue": "Contoso-Workload", + "metadata": { + "description": "The name of workload for tagging purposes. (Default: Contoso-Workload)" + } + }, + "workloadTypeTag": { + "type": "string", + "defaultValue": "Light", + "allowedValues": [ + "", + "Light", + "Medium", + "High", + "Power" + ], + "metadata": { + "description": "Reference to the size of the VM for your workloads (Default: Light)" + } + }, + "dataClassificationTag": { + "type": "string", + "defaultValue": "Non-business", + "allowedValues": [ + "", + "Non-business", + "Public", + "General", + "Confidential", + "Highly-confidential" + ], + "metadata": { + "description": "Sensitivity of data hosted (Default: Non-business)" + } + }, + "departmentTag": { + "type": "string", + "defaultValue": "Contoso-AVD", + "metadata": { + "description": "Department that owns the deployment, (Dafult: Contoso-AVD)" + } + }, + "workloadCriticalityTag": { + "type": "string", + "defaultValue": "Low", + "allowedValues": [ + "", + "Low", + "Medium", + "High", + "Mission-critical", + "Custom" + ], + "metadata": { + "description": "Criticality of the workload. (Default: Low)" + } + }, + "workloadCriticalityCustomValueTag": { + "type": "string", + "defaultValue": "Contoso-Critical", + "metadata": { + "description": "Tag value for custom criticality value. (Default: Contoso-Critical)" + } + }, + "applicationNameTag": { + "type": "string", + "defaultValue": "Contoso-App", + "metadata": { + "description": "Details about the application." + } + }, + "workloadSlaTag": { + "type": "string", + "defaultValue": "Contoso-SLA", + "metadata": { + "description": "Service level agreement level of the worload. (Contoso-SLA)" + } + }, + "opsTeamTag": { + "type": "string", + "defaultValue": "workload-admins@Contoso.com", + "metadata": { + "description": "Team accountable for day-to-day operations. (workload-admins@Contoso.com)" + } + }, + "ownerTag": { + "type": "string", + "defaultValue": "workload-owner@Contoso.com", + "metadata": { + "description": "Organizational owner of the AVD deployment. (Default: workload-owner@Contoso.com)" + } + }, + "costCenterTag": { + "type": "string", + "defaultValue": "Contoso-CC", + "metadata": { + "description": "Cost center of owner team. (Default: Contoso-CC)" + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable usage and telemetry feedback to Microsoft." + } + }, + "enableKvPurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable purge protection for the keyvaults. (Default: true)" + } + }, + "deployAntiMalwareExt": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Deploys anti malware extension on session hosts. (Default: true)" + } + }, + "customStaticRoutes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Additional customer-provided static routes to be added to the route tables." + } + }, + "deployDefender": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable Microsoft Defender on the subscription. (Default: false)" + } + }, + "enableDefForServers": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable Microsoft Defender for servers. (Default: true)" + } + }, + "enableDefForStorage": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable Microsoft Defender for storage. (Default: true)" + } + }, + "enableDefForKeyVault": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable Microsoft Defender for Key Vault. (Default: true)" + } + }, + "enableDefForArm": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable Microsoft Defender for Azure Resource Manager. (Default: true)" + } + } + }, + "variables": { + "$fxv#0": { + "australiacentral": { + "acronym": "auc", + "timeDifference": "+10:00", + "timeZone": "AUS Eastern Standard Time" + }, + "australiacentral2": { + "acronym": "auc2", + "timeDifference": "+10:00", + "timeZone": "AUS Eastern Standard Time" + }, + "australiaeast": { + "acronym": "aue", + "timeDifference": "+10:00", + "timeZone": "AUS Eastern Standard Time" + }, + "australiasoutheast": { + "acronym": "ause", + "timeDifference": "+10:00", + "timeZone": "AUS Eastern Standard Time" + }, + "brazilsouth": { + "acronym": "brs", + "timeDifference": "-3:00", + "timeZone": "E. South America Standard Time" + }, + "brazilsoutheast": { + "acronym": "brse", + "timeDifference": "-3:00", + "timeZone": "E. South America Standard Time" + }, + "canadacentral": { + "acronym": "cac", + "timeDifference": "-5:00", + "timeZone": "Eastern Standard Time" + }, + "canadaeast": { + "acronym": "cae", + "timeDifference": "-5:00", + "timeZone": "Eastern Standard Time" + }, + "centralindia": { + "acronym": "inc", + "timeDifference": "+5:30", + "timeZone": "India Standard Time" + }, + "centralus": { + "acronym": "usc", + "timeDifference": "-6:00", + "timeZone": "Central Standard Time" + }, + "chinaeast": { + "acronym": "cne", + "timeDifference": "+8:00", + "timeZone": "China Standard Time" + }, + "chinaeast2": { + "acronym": "cne2", + "timeDifference": "+8:00", + "timeZone": "China Standard Time" + }, + "chinanorth": { + "acronym": "cnn", + "timeDifference": "+8:00", + "timeZone": "China Standard Time" + }, + "chinanorth2": { + "acronym": "cnn2", + "timeDifference": "+8:00", + "timeZone": "China Standard Time" + }, + "chinanorth3": { + "acronym": "cnn3", + "timeDifference": "+8:00", + "timeZone": "China Standard Time" + }, + "eastasia": { + "acronym": "ase", + "timeDifference": "+8:00", + "timeZone": "China Standard Time" + }, + "eastus": { + "acronym": "use", + "timeDifference": "-5:00", + "timeZone": "Eastern Standard Time" + }, + "eastus2": { + "acronym": "use2", + "timeDifference": "-5:00", + "timeZone": "Eastern Standard Time" + }, + "francecentral": { + "acronym": "frc", + "timeDifference": "+1:00", + "timeZone": "Central Europe Standard Time" + }, + "francesouth": { + "acronym": "frs", + "timeDifference": "+1:00", + "timeZone": "Central Europe Standard Time" + }, + "germanynorth": { + "acronym": "den", + "timeDifference": "+1:00", + "timeZone": "Central Europe Standard Time" + }, + "germanywestcentral": { + "acronym": "dewc", + "timeDifference": "+1:00", + "timeZone": "Central Europe Standard Time" + }, + "japaneast": { + "acronym": "jpe", + "timeDifference": "+9:00", + "timeZone": "Tokyo Standard Time" + }, + "japanwest": { + "acronym": "jpw", + "timeDifference": "+9:00", + "timeZone": "Tokyo Standard Time" + }, + "jioindiacentral": { + "acronym": "injc", + "timeDifference": "+5:30", + "timeZone": "India Standard Time" + }, + "jioindiawest": { + "acronym": "injw", + "timeDifference": "+5:30", + "timeZone": "India Standard Time" + }, + "koreacentral": { + "acronym": "krc", + "timeDifference": "+9:00", + "timeZone": "Korea Standard Time" + }, + "koreasouth": { + "acronym": "krs", + "timeDifference": "+9:00", + "timeZone": "Korea Standard Time" + }, + "northcentralus": { + "acronym": "usnc", + "timeDifference": "-6:00", + "timeZone": "Central Standard Time" + }, + "northeurope": { + "acronym": "eun", + "timeDifference": "0:00", + "timeZone": "GMT Standard Time" + }, + "norwayeast": { + "acronym": "noe", + "timeDifference": "+1:00", + "timeZone": "Central Europe Standard Time" + }, + "norwaywest": { + "acronym": "now", + "timeDifference": "+1:00", + "timeZone": "Central Europe Standard Time" + }, + "italynorth": { + "acronym": "itn", + "timeDifference": "+1:00", + "timeZone": "Central Europe Standard Time" + }, + "southafricanorth": { + "acronym": "zan", + "timeDifference": "+2:00", + "timeZone": "South Africa Standard Time" + }, + "southafricawest": { + "acronym": "zaw", + "timeDifference": "+2:00", + "timeZone": "South Africa Standard Time" + }, + "southcentralus": { + "acronym": "ussc", + "timeDifference": "-6:00", + "timeZone": "Central Standard Time" + }, + "southeastasia": { + "acronym": "asse", + "timeDifference": "+8:00", + "timeZone": "Singapore Standard Time" + }, + "southindia": { + "acronym": "ins", + "timeDifference": "+5:30", + "timeZone": "India Standard Time" + }, + "swedencentral": { + "acronym": "sec", + "timeDifference": "+1:00", + "timeZone": "Central Europe Standard Time" + }, + "switzerlandnorth": { + "acronym": "chn", + "timeDifference": "+1:00", + "timeZone": "Central Europe Standard Time" + }, + "switzerlandwest": { + "acronym": "chw", + "timeDifference": "+1:00", + "timeZone": "Central Europe Standard Time" + }, + "uaecentral": { + "acronym": "aec", + "timeDifference": "+3:00", + "timeZone": "Arabian Standard Time" + }, + "uaenorth": { + "acronym": "aen", + "timeDifference": "+3:00", + "timeZone": "Arabian Standard Time" + }, + "uksouth": { + "acronym": "uks", + "timeDifference": "0:00", + "timeZone": "GMT Standard Time" + }, + "ukwest": { + "acronym": "ukw", + "timeDifference": "0:00", + "timeZone": "GMT Standard Time" + }, + "usdodcentral": { + "acronym": "dodc", + "timeDifference": "-6:00", + "timeZone": "Central Standard Time" + }, + "usdodeast": { + "acronym": "dode", + "timeDifference": "-5:00", + "timeZone": "Eastern Standard Time" + }, + "usgovarizona": { + "acronym": "az", + "timeDifference": "-7:00", + "timeZone": "Mountain Standard Time" + }, + "usgovtexas": { + "acronym": "tx", + "timeDifference": "-6:00", + "timeZone": "Central Standard Time" + }, + "usgovvirginia": { + "acronym": "va", + "timeDifference": "-5:00", + "timeZone": "Eastern Standard Time" + }, + "westcentralus": { + "acronym": "uswc", + "timeDifference": "-7:00", + "timeZone": "Mountain Standard Time" + }, + "westeurope": { + "acronym": "euw", + "timeDifference": "+1:00", + "timeZone": "Central Europe Standard Time" + }, + "westindia": { + "acronym": "inw", + "timeDifference": "+5:30", + "timeZone": "India Standard Time" + }, + "westus": { + "acronym": "usw", + "timeDifference": "-8:00", + "timeZone": "Pacific Standard Time" + }, + "westus2": { + "acronym": "usw2", + "timeDifference": "-8:00", + "timeZone": "Pacific Standard Time" + }, + "westus3": { + "acronym": "usw3", + "timeDifference": "-7:00", + "timeZone": "Mountain Standard Time" + } + }, + "varDeploymentPrefixLowercase": "[toLower(parameters('deploymentPrefix'))]", + "varAzureCloudName": "[environment().name]", + "varDeploymentEnvironmentLowercase": "[toLower(parameters('deploymentEnvironment'))]", + "varDeploymentEnvironmentOneCharacter": "[if(equals(parameters('deploymentEnvironment'), 'Dev'), 'd', if(equals(parameters('deploymentEnvironment'), 'Test'), 't', if(equals(parameters('deploymentEnvironment'), 'Prod'), 'p', '')))]", + "varNamingUniqueStringTwoChar": "[take(format('{0}', uniqueString(parameters('avdWorkloadSubsId'), variables('varDeploymentPrefixLowercase'), parameters('time'))), 2)]", + "varSessionHostLocationAcronym": "[variables('varLocations')[variables('varSessionHostLocationLowercase')].acronym]", + "varManagementPlaneLocationAcronym": "[variables('varLocations')[variables('varManagementPlaneLocationLowercase')].acronym]", + "varLocations": "[variables('$fxv#0')]", + "varTimeZoneSessionHosts": "[variables('varLocations')[variables('varSessionHostLocationLowercase')].timeZone]", + "varManagementPlaneNamingStandard": "[format('{0}-{1}-{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentLowercase'), variables('varManagementPlaneLocationAcronym'))]", + "varComputeStorageResourcesNamingStandard": "[format('{0}-{1}-{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentLowercase'), variables('varSessionHostLocationAcronym'))]", + "varDiskEncryptionSetName": "[if(parameters('avdUseCustomNaming'), format('{0}-{1}-001', parameters('ztDiskEncryptionSetCustomNamePrefix'), variables('varComputeStorageResourcesNamingStandard')), format('des-zt-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", + "varSessionHostLocationLowercase": "[toLower(replace(parameters('avdSessionHostLocation'), ' ', ''))]", + "varManagementPlaneLocationLowercase": "[toLower(replace(parameters('avdManagementPlaneLocation'), ' ', ''))]", + "varServiceObjectsRgName": "[if(parameters('avdUseCustomNaming'), parameters('avdServiceObjectsRgCustomName'), format('rg-avd-{0}-service-objects', variables('varManagementPlaneNamingStandard')))]", + "varNetworkObjectsRgName": "[if(parameters('avdUseCustomNaming'), parameters('avdNetworkObjectsRgCustomName'), format('rg-avd-{0}-network', variables('varComputeStorageResourcesNamingStandard')))]", + "varComputeObjectsRgName": "[if(parameters('avdUseCustomNaming'), parameters('avdComputeObjectsRgCustomName'), format('rg-avd-{0}-pool-compute', variables('varComputeStorageResourcesNamingStandard')))]", + "varStorageObjectsRgName": "[if(parameters('avdUseCustomNaming'), parameters('avdStorageObjectsRgCustomName'), format('rg-avd-{0}-storage', variables('varComputeStorageResourcesNamingStandard')))]", + "varMonitoringRgName": "[if(parameters('avdUseCustomNaming'), parameters('avdMonitoringRgCustomName'), format('rg-avd-{0}-{1}-monitoring', variables('varDeploymentEnvironmentLowercase'), variables('varManagementPlaneLocationAcronym')))]", + "varVnetName": "[if(parameters('avdUseCustomNaming'), parameters('avdVnetworkCustomName'), format('vnet-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", + "varHubVnetName": "[if(and(parameters('createAvdVnet'), not(empty(parameters('existingHubVnetResourceId')))), split(parameters('existingHubVnetResourceId'), '/')[8], '')]", + "varVnetPeeringName": "[format('peer-{0}', variables('varHubVnetName'))]", + "varRemoteVnetPeeringName": "[format('peer-{0}', variables('varVnetName'))]", + "varVnetAvdSubnetName": "[if(parameters('avdUseCustomNaming'), parameters('avdVnetworkSubnetCustomName'), format('snet-avd-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", + "varVnetPrivateEndpointSubnetName": "[if(parameters('avdUseCustomNaming'), parameters('privateEndpointVnetworkSubnetCustomName'), format('snet-pe-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", + "varVnetAnfSubnetName": "[if(parameters('avdUseCustomNaming'), parameters('anfVnetworkSubnetCustomName'), format('snet-anf-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", + "varAvdNetworksecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('avdNetworksecurityGroupCustomName'), format('nsg-avd-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", + "varPrivateEndpointNetworksecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('privateEndpointNetworksecurityGroupCustomName'), format('nsg-pe-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", + "varAnfNetworksecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('anfNetworksecurityGroupCustomName'), format('nsg-anf-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", + "varAvdRouteTableName": "[if(parameters('avdUseCustomNaming'), parameters('avdRouteTableCustomName'), format('route-avd-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", + "varPrivateEndpointRouteTableName": "[if(parameters('avdUseCustomNaming'), parameters('privateEndpointRouteTableCustomName'), format('route-pe-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", + "varApplicationSecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('avdApplicationSecurityGroupCustomName'), format('asg-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", + "varDDosProtectionPlanName": "[format('ddos-{0}', variables('varVnetName'))]", + "varWorkSpaceName": "[if(parameters('avdUseCustomNaming'), parameters('avdWorkSpaceCustomName'), format('vdws-{0}-001', variables('varManagementPlaneNamingStandard')))]", + "varWorkSpaceFriendlyName": "[if(parameters('avdUseCustomNaming'), parameters('avdWorkSpaceCustomFriendlyName'), format('Workspace {0} {1} {2} 001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('avdManagementPlaneLocation')))]", + "varHostPoolName": "[if(parameters('avdUseCustomNaming'), parameters('avdHostPoolCustomName'), format('vdpool-{0}-001', variables('varManagementPlaneNamingStandard')))]", + "varHostFriendlyName": "[if(parameters('avdUseCustomNaming'), parameters('avdHostPoolCustomFriendlyName'), format('Hostpool {0} {1} {2} 001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('avdManagementPlaneLocation')))]", + "varHostPoolPreferredAppGroupType": "[toLower(parameters('hostPoolPreferredAppGroupType'))]", + "varApplicationGroupName": "[if(parameters('avdUseCustomNaming'), parameters('avdApplicationGroupCustomName'), format('vdag-{0}-{1}-001', variables('varHostPoolPreferredAppGroupType'), variables('varManagementPlaneNamingStandard')))]", + "varApplicationGroupFriendlyName": "[if(parameters('avdUseCustomNaming'), parameters('avdApplicationGroupCustomFriendlyName'), format('{0} {1} {2} {3} 001', variables('varHostPoolPreferredAppGroupType'), parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('avdManagementPlaneLocation')))]", + "varDeployScalingPlan": "[if(equals(variables('varAzureCloudName'), 'AzureChinaCloud'), false(), parameters('avdDeployScalingPlan'))]", + "varCreateAppAttachDeployment": "[if(equals(variables('varAzureCloudName'), 'AzureChinaCloud'), false(), parameters('createAppAttachDeployment'))]", + "varScalingPlanName": "[if(parameters('avdUseCustomNaming'), parameters('avdScalingPlanCustomName'), format('vdscaling-{0}-001', variables('varManagementPlaneNamingStandard')))]", + "varPrivateEndPointConnectionName": "[format('pe-{0}-connection', variables('varHostPoolName'))]", + "varPrivateEndPointDiscoveryName": "[format('pe-{0}-discovery', variables('varWorkSpaceName'))]", + "varPrivateEndPointWorkspaceName": "[format('pe-{0}-global', variables('varWorkSpaceName'))]", + "varScalingPlanExclusionTag": "[format('exclude-{0}', variables('varScalingPlanName'))]", + "varScalingPlanWeekdaysScheduleName": "[format('Weekdays-{0}', variables('varManagementPlaneNamingStandard'))]", + "varScalingPlanWeekendScheduleName": "[format('Weekend-{0}', variables('varManagementPlaneNamingStandard'))]", + "varWrklKvName": "[if(parameters('avdUseCustomNaming'), format('{0}-{1}-{2}', parameters('avdWrklKvPrefixCustomName'), variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')), format('kv-sec-{0}-{1}', variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')))]", + "varWrklKvPrivateEndpointName": "[format('pe-{0}-vault', variables('varWrklKvName'))]", + "varWrklKeyVaultSku": "[if(or(equals(variables('varAzureCloudName'), 'AzureCloud'), equals(variables('varAzureCloudName'), 'AzureUSGovernment')), 'premium', if(equals(variables('varAzureCloudName'), 'AzureChinaCloud'), 'standard', null()))]", + "varSessionHostNamePrefix": "[if(parameters('avdUseCustomNaming'), parameters('avdSessionHostCustomNamePrefix'), format('vm{0}{1}{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentOneCharacter'), variables('varSessionHostLocationAcronym')))]", + "varStorageManagedIdentityName": "[format('id-storage-{0}-001', variables('varComputeStorageResourcesNamingStandard'))]", + "varAlaWorkspaceName": "[if(parameters('avdUseCustomNaming'), parameters('avdAlaWorkspaceCustomName'), format('log-avd-{0}-{1}', variables('varDeploymentEnvironmentLowercase'), variables('varManagementPlaneLocationAcronym')))]", + "varDataCollectionRulesName": "[format('microsoft-avdi-{0}', variables('varSessionHostLocationLowercase'))]", + "varZtKvName": "[if(parameters('avdUseCustomNaming'), format('{0}-{1}-{2}', parameters('ztKvPrefixCustomName'), variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')), format('kv-key-{0}-{1}', variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')))]", + "varZtKvPrivateEndpointName": "[format('pe-{0}-vault', variables('varZtKvName'))]", + "varBaseScriptUri": "https://raw.githubusercontent.com/azure/avdaccelerator/anf-fslogix/workload/", + "varSessionHostConfigurationScriptUri": "[format('{0}scripts/Set-SessionHostConfiguration.ps1', variables('varBaseScriptUri'))]", + "varSessionHostConfigurationScript": "Set-SessionHostConfiguration.ps1", + "varMaxSessionHostsPerTemplate": 10, + "varMaxSessionHostsDivisionValue": "[div(parameters('avdDeploySessionHostsCount'), variables('varMaxSessionHostsPerTemplate'))]", + "varMaxSessionHostsDivisionRemainderValue": "[mod(parameters('avdDeploySessionHostsCount'), variables('varMaxSessionHostsPerTemplate'))]", + "varSessionHostBatchCount": "[if(greater(variables('varMaxSessionHostsDivisionRemainderValue'), 0), add(variables('varMaxSessionHostsDivisionValue'), 1), variables('varMaxSessionHostsDivisionValue'))]", + "varHostPoolAgentUpdateSchedule": [ + { + "dayOfWeek": "Tuesday", + "hour": 18 + }, + { + "dayOfWeek": "Friday", + "hour": 17 + } + ], + "varPersonalScalingPlanSchedules": [ + { + "daysOfWeek": [ + "Monday", + "Wednesday", + "Thursday", + "Friday" + ], + "name": "[variables('varScalingPlanWeekdaysScheduleName')]", + "offPeakStartTime": { + "hour": 20, + "minute": 0 + }, + "offPeakStartVMOnConnect": "Enable", + "offPeakMinutesToWaitOnDisconnect": 30, + "offPeakActionOnDisconnect": "Hibernate", + "offPeakMinutesToWaitOnLogoff": 0, + "offPeakActionOnLogoff": "Deallocate", + "peakStartTime": { + "hour": 9, + "minute": 0 + }, + "peakStartVMOnConnect": "Enable", + "peakMinutesToWaitOnDisconnect": 30, + "peakActionOnDisconnect": "Hibernate", + "peakMinutesToWaitOnLogoff": 0, + "peakActionOnLogoff": "Deallocate", + "rampDownStartTime": { + "hour": 18, + "minute": 0 + }, + "rampDownStartVMOnConnect": "Enable", + "rampDownMinutesToWaitOnDisconnect": 30, + "rampDownActionOnDisconnect": "Hibernate", + "rampDownMinutesToWaitOnLogoff": 0, + "rampDownActionOnLogoff": "Deallocate", + "rampUpStartTime": { + "hour": 7, + "minute": 0 + }, + "rampUpAutoStartHosts": "WithAssignedUser", + "rampUpStartVMOnConnect": "Enable", + "rampUpMinutesToWaitOnDisconnect": 30, + "rampUpActionOnDisconnect": "Hibernate", + "rampUpMinutesToWaitOnLogoff": 0, + "rampUpActionOnLogoff": "Deallocate" + }, + { + "daysOfWeek": [ + "Tuesday" + ], + "name": "[format('{0}-agent-updates', variables('varScalingPlanWeekdaysScheduleName'))]", + "offPeakStartTime": { + "hour": 20, + "minute": 0 + }, + "offPeakStartVMOnConnect": "Enable", + "offPeakMinutesToWaitOnDisconnect": 30, + "offPeakActionOnDisconnect": "Hibernate", + "offPeakMinutesToWaitOnLogoff": 0, + "offPeakActionOnLogoff": "Deallocate", + "peakStartTime": { + "hour": 9, + "minute": 0 + }, + "peakStartVMOnConnect": "Enable", + "peakMinutesToWaitOnDisconnect": 30, + "peakActionOnDisconnect": "Hibernate", + "peakMinutesToWaitOnLogoff": 0, + "peakActionOnLogoff": "Deallocate", + "rampDownStartTime": { + "hour": 18, + "minute": 0 + }, + "rampDownStartVMOnConnect": "Enable", + "rampDownMinutesToWaitOnDisconnect": 30, + "rampDownActionOnDisconnect": "Hibernate", + "rampDownMinutesToWaitOnLogoff": 0, + "rampDownActionOnLogoff": "Deallocate", + "rampUpStartTime": { + "hour": 7, + "minute": 0 + }, + "rampUpAutoStartHosts": "WithAssignedUser", + "rampUpStartVMOnConnect": "Enable", + "rampUpMinutesToWaitOnDisconnect": 30, + "rampUpActionOnDisconnect": "Hibernate", + "rampUpMinutesToWaitOnLogoff": 0, + "rampUpActionOnLogoff": "Deallocate" + }, + { + "daysOfWeek": [ + "Saturday", + "Sunday" + ], + "name": "[variables('varScalingPlanWeekendScheduleName')]", + "offPeakStartTime": { + "hour": 18, + "minute": 0 + }, + "offPeakStartVMOnConnect": "Enable", + "offPeakMinutesToWaitOnDisconnect": 30, + "offPeakActionOnDisconnect": "Hibernate", + "offPeakMinutesToWaitOnLogoff": 0, + "offPeakActionOnLogoff": "Deallocate", + "peakStartTime": { + "hour": 10, + "minute": 0 + }, + "peakStartVMOnConnect": "Enable", + "peakMinutesToWaitOnDisconnect": 30, + "peakActionOnDisconnect": "Hibernate", + "peakMinutesToWaitOnLogoff": 0, + "peakActionOnLogoff": "Deallocate", + "rampDownStartTime": { + "hour": 16, + "minute": 0 + }, + "rampDownStartVMOnConnect": "Enable", + "rampDownMinutesToWaitOnDisconnect": 30, + "rampDownActionOnDisconnect": "Hibernate", + "rampDownMinutesToWaitOnLogoff": 0, + "rampDownActionOnLogoff": "Deallocate", + "rampUpStartTime": { + "hour": 9, + "minute": 0 + }, + "rampUpAutoStartHosts": "None", + "rampUpStartVMOnConnect": "Enable", + "rampUpMinutesToWaitOnDisconnect": 30, + "rampUpActionOnDisconnect": "Hibernate", + "rampUpMinutesToWaitOnLogoff": 0, + "rampUpActionOnLogoff": "Deallocate" + } + ], + "varPooledScalingPlanSchedules": [ + { + "daysOfWeek": [ + "Monday", + "Wednesday", + "Thursday", + "Friday" + ], + "name": "[variables('varScalingPlanWeekdaysScheduleName')]", + "offPeakLoadBalancingAlgorithm": "DepthFirst", + "offPeakStartTime": { + "hour": 20, + "minute": 0 + }, + "peakLoadBalancingAlgorithm": "DepthFirst", + "peakStartTime": { + "hour": 9, + "minute": 0 + }, + "rampDownCapacityThresholdPct": 90, + "rampDownForceLogoffUsers": true, + "rampDownLoadBalancingAlgorithm": "DepthFirst", + "rampDownMinimumHostsPct": 0, + "rampDownNotificationMessage": "You will be logged off in 30 min. Make sure to save your work.", + "rampDownStartTime": { + "hour": 18, + "minute": 0 + }, + "rampDownStopHostsWhen": "ZeroActiveSessions", + "rampDownWaitTimeMinutes": 30, + "rampUpCapacityThresholdPct": 80, + "rampUpLoadBalancingAlgorithm": "BreadthFirst", + "rampUpMinimumHostsPct": 20, + "rampUpStartTime": { + "hour": 7, + "minute": 0 + } + }, + { + "daysOfWeek": [ + "Tuesday" + ], + "name": "[format('{0}-agent-updates', variables('varScalingPlanWeekdaysScheduleName'))]", + "offPeakLoadBalancingAlgorithm": "DepthFirst", + "offPeakStartTime": { + "hour": 20, + "minute": 0 + }, + "peakLoadBalancingAlgorithm": "DepthFirst", + "peakStartTime": { + "hour": 9, + "minute": 0 + }, + "rampDownCapacityThresholdPct": 90, + "rampDownForceLogoffUsers": true, + "rampDownLoadBalancingAlgorithm": "DepthFirst", + "rampDownMinimumHostsPct": 0, + "rampDownNotificationMessage": "You will be logged off in 30 min. Make sure to save your work.", + "rampDownStartTime": { + "hour": 19, + "minute": 0 + }, + "rampDownStopHostsWhen": "ZeroActiveSessions", + "rampDownWaitTimeMinutes": 30, + "rampUpCapacityThresholdPct": 80, + "rampUpLoadBalancingAlgorithm": "BreadthFirst", + "rampUpMinimumHostsPct": 20, + "rampUpStartTime": { + "hour": 7, + "minute": 0 + } + }, + { + "daysOfWeek": [ + "Saturday", + "Sunday" + ], + "name": "[variables('varScalingPlanWeekendScheduleName')]", + "offPeakLoadBalancingAlgorithm": "DepthFirst", + "offPeakStartTime": { + "hour": 18, + "minute": 0 + }, + "peakLoadBalancingAlgorithm": "DepthFirst", + "peakStartTime": { + "hour": 10, + "minute": 0 + }, + "rampDownCapacityThresholdPct": 90, + "rampDownForceLogoffUsers": true, + "rampDownLoadBalancingAlgorithm": "DepthFirst", + "rampDownMinimumHostsPct": 0, + "rampDownNotificationMessage": "You will be logged off in 30 min. Make sure to save your work.", + "rampDownStartTime": { + "hour": 16, + "minute": 0 + }, + "rampDownStopHostsWhen": "ZeroActiveSessions", + "rampDownWaitTimeMinutes": 30, + "rampUpCapacityThresholdPct": 90, + "rampUpLoadBalancingAlgorithm": "DepthFirst", + "rampUpMinimumHostsPct": 0, + "rampUpStartTime": { + "hour": 9, + "minute": 0 + } + } + ], + "varAllDnsServers": "[format('{0},168.63.129.16', parameters('customDnsIps'))]", + "varDnsServers": "[if(empty(parameters('customDnsIps')), createArray(), split(variables('varAllDnsServers'), ','))]", + "varCreateVnetPeering": "[if(not(empty(parameters('existingHubVnetResourceId'))), true(), false())]", + "varTagsWithValues": "[union(if(empty(parameters('workloadNameTag')), createObject(), createObject('WorkloadName', parameters('workloadNameTag'))), if(empty(parameters('workloadTypeTag')), createObject(), createObject('WorkloadType', parameters('workloadTypeTag'))), if(empty(parameters('dataClassificationTag')), createObject(), createObject('DataClassification', parameters('dataClassificationTag'))), if(empty(parameters('departmentTag')), createObject(), createObject('Department', parameters('departmentTag'))), if(empty(parameters('workloadCriticalityTag')), createObject(), createObject('Criticality', if(equals(parameters('workloadCriticalityTag'), 'Custom'), parameters('workloadCriticalityCustomValueTag'), parameters('workloadCriticalityTag')))), if(empty(parameters('applicationNameTag')), createObject(), createObject('ApplicationName', parameters('applicationNameTag'))), if(empty(parameters('workloadSlaTag')), createObject(), createObject('ServiceClass', parameters('workloadSlaTag'))), if(empty(parameters('opsTeamTag')), createObject(), createObject('OpsTeam', parameters('opsTeamTag'))), if(empty(parameters('ownerTag')), createObject(), createObject('Owner', parameters('ownerTag'))), if(empty(parameters('costCenterTag')), createObject(), createObject('CostCenter', parameters('costCenterTag'))))]", + "varCustomResourceTags": "[if(parameters('createResourceTags'), variables('varTagsWithValues'), createObject())]", + "varAllComputeStorageTags": "[if(contains(parameters('avdIdentityServiceProvider'), 'EntraID'), createObject('IdentityServiceProvider', parameters('avdIdentityServiceProvider')), createObject('DomainName', parameters('identityDomainName'), 'IdentityServiceProvider', parameters('avdIdentityServiceProvider')))]", + "varAvdDefaultTags": { + "cm-resource-parent": "[format('/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.DesktopVirtualization/hostpools/{2}', parameters('avdWorkloadSubsId'), variables('varServiceObjectsRgName'), variables('varHostPoolName'))]", + "Environment": "[parameters('deploymentEnvironment')]", + "ServiceWorkload": "AVD", + "CreationTimeUTC": "[parameters('time')]" + }, + "varWorkloadKeyvaultTag": { + "Purpose": "Secrets for local admin and domain join credentials" + }, + "varZtKeyvaultTag": { + "Purpose": "Disk encryption keys for zero trust" + }, + "varTelemetryId": "[format('pid-2ce4228c-d72c-43fb-bb5b-cd8f3ba2138e-{0}', parameters('avdManagementPlaneLocation'))]", + "varResourceGroups": [ + { + "purpose": "Service-Objects", + "name": "[variables('varServiceObjectsRgName')]", + "location": "[parameters('avdManagementPlaneLocation')]", + "enableDefaultTelemetry": false, + "tags": "[if(parameters('createResourceTags'), union(variables('varCustomResourceTags'), variables('varAvdDefaultTags')), union(variables('varAvdDefaultTags'), variables('varAllComputeStorageTags')))]" + }, + { + "purpose": "Pool-Compute", + "name": "[variables('varComputeObjectsRgName')]", + "location": "[parameters('avdSessionHostLocation')]", + "enableDefaultTelemetry": false, + "tags": "[if(parameters('createResourceTags'), union(variables('varAllComputeStorageTags'), variables('varAvdDefaultTags')), union(variables('varAvdDefaultTags'), variables('varAllComputeStorageTags')))]" + } + ], + "varSecurityPrincipalId": "[if(not(empty(parameters('avdSecurityGroups'))), parameters('avdSecurityGroups')[0].objectId, '')]", + "varSecurityPrincipalName": "[if(not(empty(parameters('avdSecurityGroups'))), parameters('avdSecurityGroups')[0].displayName, '')]", + "varCreateStorageDeployment": "[if(or(parameters('createFslogixDeployment'), parameters('createAppAttachDeployment')), true(), false())]" + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[variables('varTelemetryId')]", + "location": "[parameters('avdManagementPlaneLocation')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } + }, + { + "condition": "[or(parameters('createAvdVnet'), parameters('createPrivateDnsZones'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Deploy-Network-RG-{0}', parameters('time'))]", + "subscriptionId": "[parameters('avdWorkloadSubsId')]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('varNetworkObjectsRgName')]" + }, + "location": { + "value": "[parameters('avdSessionHostLocation')]" + }, + "enableTelemetry": { + "value": false + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "5574722192240323807" + }, + "name": "Resource Groups", + "description": "This module deploys a Resource Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Resource Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location of the Resource Group. It uses the deployment's location when not provided." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the storage account resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.resources-resourcegroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "location": "[parameters('location')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "resourceGroup": { + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2021-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the resource group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the resource group." + }, + "value": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('resourceGroup', '2021-04-01', 'full').location]" + } + } + } + } + }, + { + "copy": { + "name": "baselineResourceGroups", + "count": "[length(variables('varResourceGroups'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}', variables('varResourceGroups')[copyIndex()].purpose, parameters('time'))]", + "subscriptionId": "[parameters('avdWorkloadSubsId')]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('varResourceGroups')[copyIndex()].name]" + }, + "location": { + "value": "[variables('varResourceGroups')[copyIndex()].location]" + }, + "enableTelemetry": { + "value": "[variables('varResourceGroups')[copyIndex()].enableDefaultTelemetry]" + }, + "tags": { + "value": "[variables('varResourceGroups')[copyIndex()].tags]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "5574722192240323807" + }, + "name": "Resource Groups", + "description": "This module deploys a Resource Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Resource Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location of the Resource Group. It uses the deployment's location when not provided." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the storage account resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.resources-resourcegroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "location": "[parameters('location')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "resourceGroup": { + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2021-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the resource group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the resource group." + }, + "value": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('resourceGroup', '2021-04-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[variables('varCreateStorageDeployment')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-RG-{0}', parameters('time'))]", + "subscriptionId": "[parameters('avdWorkloadSubsId')]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('varStorageObjectsRgName')]" + }, + "location": { + "value": "[parameters('avdSessionHostLocation')]" + }, + "enableTelemetry": { + "value": false + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varAllComputeStorageTags'), variables('varAvdDefaultTags'))), createObject('value', union(variables('varAvdDefaultTags'), variables('varAllComputeStorageTags'))))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "5574722192240323807" + }, + "name": "Resource Groups", + "description": "This module deploys a Resource Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Resource Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location of the Resource Group. It uses the deployment's location when not provided." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the storage account resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.resources-resourcegroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "location": "[parameters('location')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "resourceGroup": { + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2021-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the resource group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the resource group." + }, + "value": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('resourceGroup', '2021-04-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[parameters('avdDeployMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Monitoring-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('avdManagementPlaneLocation')]" + }, + "deployAlaWorkspace": { + "value": "[parameters('deployAlaWorkspace')]" + }, + "computeObjectsRgName": { + "value": "[variables('varComputeObjectsRgName')]" + }, + "serviceObjectsRgName": { + "value": "[variables('varServiceObjectsRgName')]" + }, + "dataCollectionRulesName": { + "value": "[variables('varDataCollectionRulesName')]" + }, + "storageObjectsRgName": "[if(variables('varCreateStorageDeployment'), createObject('value', variables('varStorageObjectsRgName')), createObject('value', ''))]", + "networkObjectsRgName": "[if(parameters('createAvdVnet'), createObject('value', variables('varNetworkObjectsRgName')), createObject('value', ''))]", + "monitoringRgName": { + "value": "[variables('varMonitoringRgName')]" + }, + "deployCustomPolicyMonitoring": { + "value": "[parameters('deployCustomPolicyMonitoring')]" + }, + "alaWorkspaceId": "[if(parameters('deployAlaWorkspace'), createObject('value', ''), createObject('value', parameters('alaExistingWorkspaceResourceId')))]", + "alaWorkspaceName": "[if(parameters('deployAlaWorkspace'), createObject('value', variables('varAlaWorkspaceName')), createObject('value', ''))]", + "alaWorkspaceDataRetention": { + "value": "[parameters('avdAlaWorkspaceDataRetention')]" + }, + "subscriptionId": { + "value": "[parameters('avdWorkloadSubsId')]" + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "8859176354402895974" + }, + "name": "AVD LZA insights monitoring", + "description": "This module deploys Log analytics workspace, DCR and policies", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy AVD management plane." + } + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "deployAlaWorkspace": { + "type": "bool", + "metadata": { + "description": "create new Azure log analytics workspace." + } + }, + "deployCustomPolicyMonitoring": { + "type": "bool", + "metadata": { + "description": "Create and assign custom Azure Policy for diagnostic settings for the AVD Log Analytics workspace." + } + }, + "alaWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Exisintg Azure log analytics workspace resource." + } + }, + "monitoringRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for monitoring resources." + } + }, + "computeObjectsRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for compute resources." + } + }, + "serviceObjectsRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for the service objects." + } + }, + "storageObjectsRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for the storage resources." + } + }, + "networkObjectsRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for the network resources." + } + }, + "alaWorkspaceName": { + "type": "string", + "metadata": { + "description": "Azure log analytics workspace name." + } + }, + "dataCollectionRulesName": { + "type": "string", + "metadata": { + "description": "Data collection rules name." + } + }, + "alaWorkspaceDataRetention": { + "type": "int", + "metadata": { + "description": " Azure log analytics workspace name data retention." + } + }, + "tags": { + "type": "object", + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + } + }, + "variables": { + "varAlaWorkspaceIdSplitId": "[split(parameters('alaWorkspaceId'), '/')]" + }, + "resources": [ + { + "condition": "[or(parameters('deployAlaWorkspace'), and(not(parameters('deployAlaWorkspace')), not(empty(parameters('alaWorkspaceId')))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Monitoing-RG-{0}', parameters('time'))]", + "subscriptionId": "[parameters('subscriptionId')]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('monitoringRgName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": false + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "5574722192240323807" + }, + "name": "Resource Groups", + "description": "This module deploys a Resource Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Resource Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. Location of the Resource Group. It uses the deployment's location when not provided." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the storage account resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.resources-resourcegroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "location": "[parameters('location')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "resourceGroup": { + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2021-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the resource group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the resource group." + }, + "value": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('resourceGroup', '2021-04-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[parameters('deployAlaWorkspace')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('LA-Workspace-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('monitoringRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "name": { + "value": "[parameters('alaWorkspaceName')]" + }, + "dataRetention": { + "value": "[parameters('alaWorkspaceDataRetention')]" + }, + "useResourcePermissions": { + "value": true + }, + "managedIdentities": { + "value": { + "systemAssigned": false + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "8971404674064738552" + }, + "name": "Log Analytics Workspaces", + "description": "This module deploys a Log Analytics Workspace.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "skuName": { + "type": "string", + "defaultValue": "PerGB2018", + "allowedValues": [ + "CapacityReservation", + "Free", + "LACluster", + "PerGB2018", + "PerNode", + "Premium", + "Standalone", + "Standard" + ], + "metadata": { + "description": "Optional. The name of the SKU." + } + }, + "skuCapacityReservationLevel": { + "type": "int", + "defaultValue": 100, + "minValue": 100, + "maxValue": 5000, + "metadata": { + "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." + } + }, + "storageInsightsConfigs": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of storage accounts to be read by the workspace." + } + }, + "dataRetention": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 730, + "metadata": { + "description": "Optional. Number of days data will be retained for." + } + }, + "dailyQuotaGb": { + "type": "int", + "defaultValue": -1, + "minValue": -1, + "metadata": { + "description": "Optional. The workspace daily quota for ingestion." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics ingestion." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics query." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." + } + }, + "useResourcePermissions": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Set to 'true' to use resource or workspace permissions and 'false' (or leave empty) to require workspace permissions." + } + }, + "forceCmkForQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether customer managed storage is mandatory for query management." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "features": { + "searchVersion": 1, + "enableLogAccessUsingOnlyResourcePermissions": "[parameters('useResourcePermissions')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" + }, + "retentionInDays": "[parameters('dataRetention')]", + "workspaceCapping": { + "dailyQuotaGb": "[parameters('dailyQuotaGb')]" + }, + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "forceCmkForQuery": "[parameters('forceCmkForQuery')]" + }, + "identity": "[variables('identity')]" + }, + "logAnalyticsWorkspace_storageInsightConfigs": { + "copy": { + "name": "logAnalyticsWorkspace_storageInsightConfigs", + "count": "[length(parameters('storageInsightsConfigs'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "containers": "[if(contains(parameters('storageInsightsConfigs')[copyIndex()], 'containers'), createObject('value', parameters('storageInsightsConfigs')[copyIndex()].containers), createObject('value', createArray()))]", + "tables": "[if(contains(parameters('storageInsightsConfigs')[copyIndex()], 'tables'), createObject('value', parameters('storageInsightsConfigs')[copyIndex()].tables), createObject('value', createArray()))]", + "storageAccountResourceId": { + "value": "[parameters('storageInsightsConfigs')[copyIndex()].storageAccountResourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4384156253703622371" + }, + "name": "Log Analytics Workspace Storage Insight Configs", + "description": "This module deploys a Log Analytics Workspace Storage Insight Config.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the storage insights config." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource Manager ID of the storage account resource." + } + }, + "containers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The names of the Azure tables that the workspace should read." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" + }, + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "storageinsightconfig": { + "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "containers": "[parameters('containers')]", + "tables": "[parameters('tables')]", + "storageAccount": { + "id": "[parameters('storageAccountResourceId')]", + "key": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', last(split(parameters('storageAccountResourceId'), '/'))), '2022-09-01').keys[0].value]" + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage insights configuration." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the storage insight configuration is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the storage insights configuration." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed log analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed log analytics workspace." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed log analytics workspace." + }, + "value": "[parameters('name')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "The ID associated with the workspace." + }, + "value": "[reference('logAnalyticsWorkspace').customerId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('logAnalyticsWorkspace', '2022-10-01', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('logAnalyticsWorkspace', '2022-10-01', 'full'), 'identity'), 'principalId'), '')]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('Monitoing-RG-{0}', parameters('time')))]" + ] + }, + { + "condition": "[parameters('deployCustomPolicyMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Custom-Policy-Monitoring-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "alaWorkspaceId": "[if(parameters('deployAlaWorkspace'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', parameters('alaWorkspaceId')))]", + "location": { + "value": "[parameters('location')]" + }, + "subscriptionId": { + "value": "[parameters('subscriptionId')]" + }, + "computeObjectsRgName": { + "value": "[parameters('computeObjectsRgName')]" + }, + "serviceObjectsRgName": { + "value": "[parameters('serviceObjectsRgName')]" + }, + "storageObjectsRgName": { + "value": "[parameters('storageObjectsRgName')]" + }, + "networkObjectsRgName": { + "value": "[parameters('networkObjectsRgName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "16349959440930876908" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy AVD management plane." + } + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "alaWorkspaceId": { + "type": "string", + "metadata": { + "description": "Exisintg Azure log analytics workspace." + } + }, + "computeObjectsRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for the compute resources." + } + }, + "serviceObjectsRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for the service objects." + } + }, + "networkObjectsRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for the network resources." + } + }, + "storageObjectsRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for the storage resources." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + } + }, + "variables": { + "$fxv#0": { + "AVDScalingPlansDeployDiagnosticLogDeployLogAnalytics": { + "parameters": { + "logAnalytics": { + "value": "[[[parameters('logAnalytics')]" + }, + "effect": { + "value": "[[[parameters('AVDScalingPlansLogAnalyticsEffect')]" + }, + "profileName": { + "value": "[[[parameters('profileName')]" + } + } + }, + "NetworkNICDeployDiagnosticLogDeployLogAnalytics": { + "parameters": { + "logAnalytics": { + "value": "[[[parameters('logAnalytics')]" + }, + "effect": { + "value": "[[[parameters('NetworkNICLogAnalyticsEffect')]" + }, + "profileName": { + "value": "[[[parameters('profileName')]" + } + } + }, + "NetworkSecurityGroupsDeployDiagnosticLogDeployLogAnalytics": { + "parameters": { + "logAnalytics": { + "value": "[[[parameters('logAnalytics')]" + }, + "effect": { + "value": "[[[parameters('NetworkSecurityGroupsLogAnalyticsEffect')]" + }, + "profileName": { + "value": "[[[parameters('profileName')]" + } + } + }, + "AzureFilesDeployDiagnosticLogDeployLogAnalytics": { + "parameters": { + "logAnalytics": { + "value": "[[[parameters('logAnalytics')]" + }, + "effect": { + "value": "[[[parameters('AzureFilesLogAnalyticsEffect')]" + }, + "profileName": { + "value": "[[[parameters('profileName')]" + } + } + }, + "VirtualMachinesDeployDiagnosticLogDeployLogAnalytics": { + "parameters": { + "logAnalytics": { + "value": "[[[parameters('logAnalytics')]" + }, + "effect": { + "value": "[[[parameters('VirtualMachinesLogAnalyticsEffect')]" + }, + "profileName": { + "value": "[[[parameters('profileName')]" + } + } + }, + "VirtualNetworkDeployDiagnosticLogDeployLogAnalytics": { + "parameters": { + "logAnalytics": { + "value": "[[[parameters('logAnalytics')]" + }, + "effect": { + "value": "[[[parameters('VirtualNetworkLogAnalyticsEffect')]" + }, + "profileName": { + "value": "[[[parameters('profileName')]" + } + } + }, + "AVDAppGroupDeployDiagnosticLogDeployLogAnalytics": { + "parameters": { + "logAnalytics": { + "value": "[[[parameters('logAnalytics')]" + }, + "effect": { + "value": "[[[parameters('AVDAppGroupsLogAnalyticsEffect')]" + }, + "profileName": { + "value": "[[[parameters('profileName')]" + } + } + }, + "AVDHostPoolsDeployDiagnosticLogDeployLogAnalytics": { + "parameters": { + "logAnalytics": { + "value": "[[[parameters('logAnalytics')]" + }, + "effect": { + "value": "[[[parameters('AVDHostPoolsLogAnalyticsEffect')]" + }, + "profileName": { + "value": "[[[parameters('profileName')]" + } + } + }, + "AVDWorkspaceDeployDiagnosticLogDeployLogAnalytics": { + "parameters": { + "logAnalytics": { + "value": "[[[parameters('logAnalytics')]" + }, + "effect": { + "value": "[[[parameters('AVDWorkspaceLogAnalyticsEffect')]" + }, + "profileName": { + "value": "[[[parameters('profileName')]" + } + } + } + }, + "$fxv#1": "{\r\n \"name\": \"policy-deploy-diagnostics-avd-application-group\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for AVD Application group to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for AVD Application group to stream to a Log Analytics workspace when any application group which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all and categorys enabled.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.1\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.DesktopVirtualization/applicationGroups\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.DesktopVirtualization/applicationGroups/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"logs\": [\r\n {\r\n \"category\": \"Checkpoint\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Error\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Management\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", + "$fxv#10": "{\r\n \"name\": \"policy-set-deploy-avd-diagnostics-to-log-analytics\",\r\n \"type\": \"Microsoft.Authorization/policySetDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings to AVD Landing Zone\",\r\n \"description\": \"This policy set deploys the configurations of application Azure resources to forward diagnostic logs and metrics to an Azure Log Analytics workspace. See the list of policies of the services that are included \",\r\n \"metadata\": {\r\n \"version\": \"1.1.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"metadata\": {\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"strongType\": \"omsWorkspace\"\r\n },\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"NetworkSecurityGroupsLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for Network Security Groups to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for Network Security Groups to stream to a Log Analytics workspace when any Network Security Groups which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"NetworkNICLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for Network Interfaces to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for Network Interfaces to stream to a Log Analytics workspace when any Network Interfaces which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"VirtualNetworkLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for Virtual Network to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for Virtual Network to stream to a Log Analytics workspace when any Virtual Network which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"VirtualMachinesLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for Virtual Machines to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for Virtual Machines to stream to a Log Analytics workspace when any Virtual Machines which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"AVDScalingPlansLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for AVD Scaling Plans to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for AVD Scaling Plans to stream to a Log Analytics workspace when any application groups which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"AVDAppGroupsLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for AVD Application Groups to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for AVD Application groups to stream to a Log Analytics workspace when any application groups which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"AVDWorkspaceLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for AVD Workspace to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for AVD Workspace to stream to a Log Analytics workspace when any Workspace which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"AVDHostPoolsLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for AVD Host pools to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for AVD Host pools to stream to a Log Analytics workspace when any host pool which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"AzureFilesLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for Azure Files to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for Azure Files to stream to a Log Analytics workspace when any Azure Files share is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n }\r\n },\r\n \"policyDefinitions\": [\r\n {\r\n \"policyDefinitionReferenceId\": \"AVDScalingPlansDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-AVDScalingPlans\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('AVDScalingPlansLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"AVDAppGroupDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-AVDAppGroup\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('AVDAppGroupsLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"AVDWorkspaceDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-AVDWorkspace\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('AVDWorkspaceLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"AVDHostPoolsDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-AVDHostPools\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('AVDHostPoolsLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"NetworkSecurityGroupsDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-NetworkSecurityGroups\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('NetworkSecurityGroupsLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"NetworkNICDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-NIC\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('NetworkNICLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"VirtualNetworkDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-VirtualNetwork\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('VirtualNetworkLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"AzureFilesDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-AzureFiles\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('AzureFilesLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"VirtualMachinesDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-VM\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('VirtualMachinesLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n }\r\n ],\r\n \"policyDefinitionGroups\": null\r\n }\r\n }", + "$fxv#2": "{\r\n \"name\": \"policy-deploy-diagnostics-avd-host-pool\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for AVD Host Pools to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for AVD Host Pools to stream to a Log Analytics workspace when any Host Pools which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all and categorys enabled.\",\r\n \"metadata\": {\r\n \"version\": \"1.1.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.DesktopVirtualization/hostpools\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.DesktopVirtualization/hostpools/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"logs\": [\r\n {\r\n \"category\": \"Checkpoint\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Error\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Management\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Connection\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"HostRegistration\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"AgentHealthStatus\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"NetworkData\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"ConnectionGraphicsData\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"SessionHostManagement\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", + "$fxv#3": "{\r\n \"name\": \"policy-deploy-diagnostics-avd-scaling-plan\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for AVD Scaling Plans to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for AVD Scaling Plans to stream to a Log Analytics workspace when any Scaling Plan which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all and categorys enabled.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.DesktopVirtualization/scalingplans\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.DesktopVirtualization/scalingplans/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"logs\": [\r\n {\r\n \"category\": \"Autoscale\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", + "$fxv#4": "{\r\n \"name\": \"policy-deploy-diagnostics-avd-workspace\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for AVD Workspace to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for AVD Workspace to stream to a Log Analytics workspace when any Workspace which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all and categorys enabled.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.1\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.DesktopVirtualization/workspaces\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.DesktopVirtualization/workspaces/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"logs\": [\r\n {\r\n \"category\": \"Checkpoint\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Error\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Management\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Feed\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", + "$fxv#5": "{\r\n \"name\": \"policy-deploy-diagnostics-network-security-group\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for Network Security Groups to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for Network Security Groups to stream to a Log Analytics workspace when any Network Security Groups which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Network/networkSecurityGroups\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.Network/networkSecurityGroups/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"metrics\": [],\r\n \"logs\": [\r\n {\r\n \"category\": \"NetworkSecurityGroupEvent\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"NetworkSecurityGroupRuleCounter\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", + "$fxv#6": "{\r\n \"name\": \"policy-deploy-diagnostics-nic\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for Network Interfaces to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for Network Interfaces to stream to a Log Analytics workspace when any Network Interfaces which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable metrics\",\r\n \"description\": \"Whether to enable metrics stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Network/networkInterfaces\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/metrics.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.Network/networkInterfaces/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"metrics\": [\r\n {\r\n \"category\": \"AllMetrics\",\r\n \"timeGrain\": null,\r\n \"enabled\": \"[parameters('metricsEnabled')]\",\r\n \"retentionPolicy\": {\r\n \"enabled\": false,\r\n \"days\": 0\r\n }\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"metricsEnabled\": {\r\n \"value\": \"[parameters('metricsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", + "$fxv#7": "{\r\n \"name\": \"policy-deploy-diagnostics-virtual-machine\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for Virtual Machines to Log Analytics Workspace\",\r\n \"description\": \"CUstom - Deploys the diagnostic settings for Virtual Machines to stream to a Log Analytics workspace when any Virtual Machines which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable metrics\",\r\n \"description\": \"Whether to enable metrics stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Compute/virtualMachines\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/metrics.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.Compute/virtualMachines/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"metrics\": [\r\n {\r\n \"category\": \"AllMetrics\",\r\n \"enabled\": \"[parameters('metricsEnabled')]\",\r\n \"retentionPolicy\": {\r\n \"enabled\": false,\r\n \"days\": 0\r\n }\r\n }\r\n ],\r\n \"logs\": []\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"metricsEnabled\": {\r\n \"value\": \"[parameters('metricsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", + "$fxv#8": "{\r\n \"name\": \"policy-deploy-diagnostics-virtual-network\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for Virtual Network to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for Virtual Network to stream to a Log Analytics workspace when any Virtual Network which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable metrics\",\r\n \"description\": \"Whether to enable metrics stream to the Log Analytics workspace - True or False\"\r\n }\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Network/virtualNetworks\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/metrics.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"String\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.Network/virtualNetworks/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"metrics\": [\r\n {\r\n \"category\": \"AllMetrics\",\r\n \"enabled\": \"[parameters('metricsEnabled')]\",\r\n \"retentionPolicy\": {\r\n \"enabled\": false,\r\n \"days\": 0\r\n }\r\n }\r\n ],\r\n \"logs\": [\r\n {\r\n \"category\": \"VMProtectionAlerts\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"metricsEnabled\": {\r\n \"value\": \"[parameters('metricsEnabled')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", + "$fxv#9": "{\r\n \"name\": \"policy-deploy-diagnostics-azure-files\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"All\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for Azure Files to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for File Services to stream resource logs to a Log Analytics workspace when any file Service which is missing this diagnostic settings is created or updated.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Storage/storageAccounts/fileServices\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"[parameters('profileName')]\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/metrics.enabled\",\r\n \"equals\": \"[parameters('metricsEnabled')]\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"string\"\r\n },\r\n \"location\": {\r\n \"type\": \"string\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"string\"\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"bool\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"bool\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"string\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.Storage/storageAccounts/fileServices/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2021-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"metrics\": [\r\n {\r\n \"category\": \"Transaction\",\r\n \"enabled\": \"[parameters('metricsEnabled')]\"\r\n }\r\n ],\r\n \"logs\": [\r\n {\r\n \"category\": \"StorageRead\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"StorageWrite\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"StorageDelete\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('fullName')]\"\r\n },\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"metricsEnabled\": {\r\n \"value\": \"[parameters('metricsEnabled')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"parameters\": {\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n },\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"AuditIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"defaultValue\": \"DeployIfNotExists\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n },\r\n \"defaultValue\": \"setbypolicy\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\",\r\n \"assignPermissions\": true\r\n }\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"Boolean\",\r\n \"metadata\": {\r\n \"displayName\": \"Enable metrics\",\r\n \"description\": \"Whether to enable metrics stream to the Log Analytics workspace - True or False\"\r\n },\r\n \"allowedValues\": [\r\n true,\r\n false\r\n ],\r\n \"defaultValue\": true\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"Boolean\",\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n },\r\n \"allowedValues\": [\r\n true,\r\n false\r\n ],\r\n \"defaultValue\": true\r\n }\r\n }\r\n }\r\n}", + "varComputeServObjRgs": [ + { + "rgName": "[parameters('computeObjectsRgName')]" + }, + { + "rgName": "[parameters('serviceObjectsRgName')]" + } + ], + "varNetworkObjRgs": "[if(not(empty(parameters('networkObjectsRgName'))), createArray(createObject('rgName', parameters('networkObjectsRgName'))), createArray())]", + "varStorageObjRgs": "[if(not(empty(parameters('storageObjectsRgName'))), createArray(createObject('rgName', parameters('storageObjectsRgName'))), createArray())]", + "varPolicyAssignmentRgs": "[union(variables('varComputeServObjRgs'), variables('varNetworkObjRgs'), variables('varStorageObjRgs'))]", + "varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters": "[variables('$fxv#0')]", + "varCustomPolicyDefinitions": [ + { + "deploymentName": "App-Group-Diag", + "libDefinition": "[json(variables('$fxv#1'))]" + }, + { + "deploymentName": "Host-Pool-Diag", + "libDefinition": "[json(variables('$fxv#2'))]" + }, + { + "deploymentName": "Scaling-Plan-Diag", + "libDefinition": "[json(variables('$fxv#3'))]" + }, + { + "deploymentName": "Workspace-Diag", + "libDefinition": "[json(variables('$fxv#4'))]" + }, + { + "deploymentName": "NSG-Diag", + "libDefinition": "[json(variables('$fxv#5'))]" + }, + { + "deploymentName": "NIC-Diag", + "libDefinition": "[json(variables('$fxv#6'))]" + }, + { + "deploymentName": "VM-Diag", + "libDefinition": "[json(variables('$fxv#7'))]" + }, + { + "deploymentName": "vNet-Diag", + "libDefinition": "[json(variables('$fxv#8'))]" + }, + { + "deploymentName": "Azure-Files-Diag", + "libDefinition": "[json(variables('$fxv#9'))]" + } + ], + "varCustomPolicySetDefinitions": { + "deploymentName": "policy-set-avd-diagnostics", + "libSetDefinition": "[json(variables('$fxv#10'))]", + "libSetChildDefinitions": [ + { + "definitionReferenceId": "AVDAppGroupDeployDiagnosticLogDeployLogAnalytics", + "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-avd-application-group', parameters('subscriptionId'))]", + "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').AVDAppGroupDeployDiagnosticLogDeployLogAnalytics.parameters]" + }, + { + "definitionReferenceId": "AVDHostPoolsDeployDiagnosticLogDeployLogAnalytics", + "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-avd-host-pool', parameters('subscriptionId'))]", + "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').AVDHostPoolsDeployDiagnosticLogDeployLogAnalytics.parameters]" + }, + { + "definitionReferenceId": "AVDScalingPlansDeployDiagnosticLogDeployLogAnalytics", + "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-avd-scaling-plan', parameters('subscriptionId'))]", + "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').AVDScalingPlansDeployDiagnosticLogDeployLogAnalytics.parameters]" + }, + { + "definitionReferenceId": "AVDWorkspaceDeployDiagnosticLogDeployLogAnalytics", + "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-avd-workspace', parameters('subscriptionId'))]", + "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').AVDWorkspaceDeployDiagnosticLogDeployLogAnalytics.parameters]" + }, + { + "definitionReferenceId": "NetworkSecurityGroupsDeployDiagnosticLogDeployLogAnalytics", + "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-network-security-group', parameters('subscriptionId'))]", + "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').NetworkSecurityGroupsDeployDiagnosticLogDeployLogAnalytics.parameters]" + }, + { + "definitionReferenceId": "NetworkNICDeployDiagnosticLogDeployLogAnalytics", + "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-nic', parameters('subscriptionId'))]", + "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').NetworkNICDeployDiagnosticLogDeployLogAnalytics.parameters]" + }, + { + "definitionReferenceId": "VirtualMachinesDeployDiagnosticLogDeployLogAnalytics", + "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-virtual-machine', parameters('subscriptionId'))]", + "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').VirtualMachinesDeployDiagnosticLogDeployLogAnalytics.parameters]" + }, + { + "definitionReferenceId": "VirtualNetworkDeployDiagnosticLogDeployLogAnalytics", + "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-virtual-network', parameters('subscriptionId'))]", + "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').VirtualNetworkDeployDiagnosticLogDeployLogAnalytics.parameters]" + }, + { + "definitionReferenceId": "AzureFilesDeployDiagnosticLogDeployLogAnalytics", + "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-azure-files', parameters('subscriptionId'))]", + "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').AzureFilesDeployDiagnosticLogDeployLogAnalytics.parameters]" + } + ] + } + }, + "resources": [ + { + "copy": { + "name": "policyDefinitions", + "count": "[length(variables('varCustomPolicyDefinitions'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.name]" + }, + "displayName": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.displayName]" + }, + "metadata": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.metadata]" + }, + "mode": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.mode]" + }, + "parameters": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.parameters]" + }, + "policyRule": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.policyRule]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "15296566503434303805" + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. Specifies the name of the policy definition. Maximum length is 64 characters." + } + }, + "displayName": { + "type": "string", + "defaultValue": "", + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy definition. Maximum length is 128 characters." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The policy definition description." + } + }, + "mode": { + "type": "string", + "defaultValue": "All", + "allowedValues": [ + "All", + "Indexed", + "Microsoft.KeyVault.Data", + "Microsoft.ContainerService.Data", + "Microsoft.Kubernetes.Data", + "Microsoft.Network.Data" + ], + "metadata": { + "description": "Optional. The policy definition mode. Default is All, Some examples are All, Indexed, Microsoft.KeyVault.Data." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy Definition metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy definition parameters that can be used in policy definition references." + } + }, + "policyRule": { + "type": "object", + "metadata": { + "description": "Required. The Policy Rule details for the Policy Definition." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyDefinitions", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "properties": { + "policyType": "Custom", + "mode": "[parameters('mode')]", + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "parameters": "[if(not(empty(parameters('parameters'))), parameters('parameters'), null())]", + "policyRule": "[parameters('policyRule')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy Definition Name." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Definition resource ID." + }, + "value": "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name'))]" + }, + "roleDefinitionIds": { + "type": "array", + "metadata": { + "description": "Policy Definition Role Definition IDs." + }, + "value": "[if(contains(reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then, 'details'), if(contains(reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then.details, 'roleDefinitionIds'), reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then.details.roleDefinitionIds, createArray()), createArray())]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Policy-Set-Definition-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.name]" + }, + "description": { + "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.description]" + }, + "displayName": { + "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.displayName]" + }, + "metadata": { + "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.metadata]" + }, + "parameters": { + "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.parameters]" + }, + "policyDefinitions": { + "copy": [ + { + "name": "value", + "count": "[length(variables('varCustomPolicySetDefinitions').libSetChildDefinitions)]", + "input": "[createObject('policyDefinitionReferenceId', variables('varCustomPolicySetDefinitions').libSetChildDefinitions[copyIndex('value')].definitionReferenceId, 'policyDefinitionId', variables('varCustomPolicySetDefinitions').libSetChildDefinitions[copyIndex('value')].definitionId, 'parameters', variables('varCustomPolicySetDefinitions').libSetChildDefinitions[copyIndex('value')].definitionParameters)]" + } + ] + }, + "policyDefinitionGroups": { + "value": [] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "10756132163516015710" + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. Specifies the name of the policy Set Definition (Initiative). Maximum length is 64 characters for subscription scope." + } + }, + "displayName": { + "type": "string", + "defaultValue": "", + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the Set Definition (Initiative). Maximum length is 128 characters." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description name of the Set Definition (Initiative)." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The Set Definition (Initiative) metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "policyDefinitions": { + "type": "array", + "metadata": { + "description": "Required. The array of Policy definitions object to include for this policy set. Each object must include the Policy definition ID, and optionally other properties like parameters." + } + }, + "policyDefinitionGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The metadata describing groups of policy definition references within the Policy Set Definition (Initiative)." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The Set Definition (Initiative) parameters that can be used in policy definition references." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/policySetDefinitions", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "properties": { + "policyType": "Custom", + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "parameters": "[if(not(empty(parameters('parameters'))), parameters('parameters'), null())]", + "policyDefinitions": "[parameters('policyDefinitions')]", + "policyDefinitionGroups": "[if(not(empty(parameters('policyDefinitionGroups'))), parameters('policyDefinitionGroups'), createArray())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy Set Definition Name." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Set Definition resource ID." + }, + "value": "[subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "policyDefinitions" + ] + }, + { + "copy": { + "name": "policySetAssignment", + "count": "[length(variables('varPolicyAssignmentRgs'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Policy-Set-Assignment-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', variables('varPolicyAssignmentRgs')[copyIndex()].rgName)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "name": { + "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.name]" + }, + "description": { + "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.description]" + }, + "displayName": { + "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.displayName]" + }, + "metadata": { + "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.metadata]" + }, + "identity": { + "value": "SystemAssigned" + }, + "roleDefinitionIds": { + "value": [ + "/providers/Microsoft.Authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa", + "/providers/Microsoft.Authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293" + ] + }, + "parameters": { + "value": { + "logAnalytics": { + "value": "[parameters('alaWorkspaceId')]" + } + } + }, + "policyDefinitionId": { + "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policySetDefinitions/policy-set-deploy-avd-diagnostics-to-log-analytics', parameters('subscriptionId'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "10386382608825992636" + }, + "name": "Policy Assignments (Resource Group scope)", + "description": "This module deploys a Policy Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 64 characters for resource group scope." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. This message will be part of response in case of policy violation." + } + }, + "displayName": { + "type": "string", + "defaultValue": "", + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy assignment. Maximum length is 128 characters." + } + }, + "policyDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the ID of the policy definition or policy set definition being assigned." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Parameters for the policy assignment if needed." + } + }, + "identity": { + "type": "string", + "defaultValue": "SystemAssigned", + "allowedValues": [ + "SystemAssigned", + "UserAssigned", + "None" + ], + "metadata": { + "description": "Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions." + } + }, + "userAssignedIdentityId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource ID for the user assigned identity to assign to the policy assignment." + } + }, + "roleDefinitionIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "nonComplianceMessages": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The messages that describe why a resource is non-compliant with the policy." + } + }, + "enforcementMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "DoNotEnforce" + ], + "metadata": { + "description": "Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce." + } + }, + "notScopes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy excluded scopes." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "overrides": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition." + } + }, + "resourceSelectors": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The name of the resource group for the policy assignment. If not provided, will use the current scope for deployment." + } + } + }, + "variables": { + "identityVar": "[if(equals(parameters('identity'), 'SystemAssigned'), createObject('type', parameters('identity')), if(equals(parameters('identity'), 'UserAssigned'), createObject('type', parameters('identity'), 'userAssignedIdentities', createObject(format('{0}', parameters('userAssignedIdentityId')), createObject())), null()))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2022-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "policyDefinitionId": "[parameters('policyDefinitionId')]", + "parameters": "[parameters('parameters')]", + "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), parameters('nonComplianceMessages'), createArray())]", + "enforcementMode": "[parameters('enforcementMode')]", + "notScopes": "[if(not(empty(parameters('notScopes'))), parameters('notScopes'), createArray())]", + "overrides": "[if(not(empty(parameters('overrides'))), parameters('overrides'), createArray())]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), createArray())]" + }, + "identity": "[variables('identityVar')]" + }, + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('roleDefinitionIds'))]" + }, + "condition": "[and(not(empty(parameters('roleDefinitionIds'))), equals(parameters('identity'), 'SystemAssigned'))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), parameters('roleDefinitionIds')[copyIndex()], parameters('location'), parameters('name'))]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionIds')[copyIndex()]]", + "principalId": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy Assignment Name." + }, + "value": "[parameters('name')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Policy Assignment principal ID." + }, + "value": "[coalesce(tryGet(tryGet(reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Assignment resource ID." + }, + "value": "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the policy was assigned to." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId(format('{0}', parameters('subscriptionId')), 'Microsoft.Resources/deployments', format('Policy-Set-Definition-{0}', parameters('time')))]" + ] + }, + { + "copy": { + "name": "policySetRemediation", + "count": "[length(variables('varPolicyAssignmentRgs'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Remm-Diag-{0}-{1}', variables('varCustomPolicySetDefinitions').deploymentName, copyIndex())]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', variables('varPolicyAssignmentRgs')[copyIndex()].rgName)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-{1}', variables('varCustomPolicySetDefinitions').deploymentName, copyIndex())]" + }, + "policyAssignmentId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', variables('varPolicyAssignmentRgs')[copyIndex()].rgName)), 'Microsoft.Resources/deployments', format('Policy-Set-Assignment-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "8141314117626850328" + }, + "name": "Policy Insights Remediations (Resource Group scope)", + "description": "This module deploys a Policy Insights Remediation on a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specifies the name of the policy remediation." + } + }, + "failureThresholdPercentage": { + "type": "string", + "defaultValue": "1", + "metadata": { + "description": "Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail." + } + }, + "filtersLocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The filters that will be applied to determine which resources to remediate." + } + }, + "parallelDeployments": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "maxValue": 30, + "metadata": { + "description": "Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used." + } + }, + "resourceCount": { + "type": "int", + "defaultValue": 500, + "minValue": 1, + "maxValue": 50000, + "metadata": { + "description": "Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used." + } + }, + "resourceDiscoveryMode": { + "type": "string", + "defaultValue": "ExistingNonCompliant", + "allowedValues": [ + "ExistingNonCompliant", + "ReEvaluateCompliance" + ], + "metadata": { + "description": "Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified." + } + }, + "policyAssignmentId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the policy assignment that should be remediated." + } + }, + "policyDefinitionReferenceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location deployment metadata." + } + } + }, + "resources": [ + { + "type": "Microsoft.PolicyInsights/remediations", + "apiVersion": "2021-10-01", + "name": "[parameters('name')]", + "properties": { + "failureThreshold": { + "percentage": "[json(parameters('failureThresholdPercentage'))]" + }, + "filters": { + "locations": "[parameters('filtersLocations')]" + }, + "parallelDeployments": "[parameters('parallelDeployments')]", + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceId": "[parameters('policyDefinitionReferenceId')]", + "resourceCount": "[parameters('resourceCount')]", + "resourceDiscoveryMode": "[parameters('resourceDiscoveryMode')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the remediation." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the remediation." + }, + "value": "[resourceId('Microsoft.PolicyInsights/remediations', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed remediation." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[parameters('location')]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', variables('varPolicyAssignmentRgs')[copyIndex()].rgName)), 'Microsoft.Resources/deployments', format('Policy-Set-Assignment-{0}', parameters('time')))]" + ] + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time')))]", + "[subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('Monitoing-RG-{0}', parameters('time')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Mon-DCR-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('monitoringRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": "[if(parameters('deployAlaWorkspace'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time'))), '2022-09-01').outputs.location.value), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('varAlaWorkspaceIdSplitId')[2], variables('varAlaWorkspaceIdSplitId')[4]), 'Microsoft.OperationalInsights/workspaces', variables('varAlaWorkspaceIdSplitId')[8]), '2022-10-01', 'full').location))]", + "name": { + "value": "[parameters('dataCollectionRulesName')]" + }, + "alaWorkspaceId": "[if(parameters('deployAlaWorkspace'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', parameters('alaWorkspaceId')))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13560993199783159016" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Data colleciton rule name." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy resources." + } + }, + "alaWorkspaceId": { + "type": "string", + "metadata": { + "description": "Exisintg Azure log analytics workspace." + } + }, + "tags": { + "type": "object", + "metadata": { + "description": "Tags to be applied to resources" + } + } + }, + "variables": { + "varAlaWorkspaceName": "[split(parameters('alaWorkspaceId'), '/')[8]]" + }, + "resources": [ + { + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2022-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "Windows", + "identity": { + "type": "systemassigned" + }, + "properties": { + "dataFlows": [ + { + "streams": [ + "Microsoft-Perf", + "Microsoft-Event" + ], + "destinations": [ + "[variables('varAlaWorkspaceName')]" + ] + } + ], + "dataSources": { + "performanceCounters": [ + { + "streams": [ + "Microsoft-Perf" + ], + "samplingFrequencyInSeconds": 30, + "counterSpecifiers": [ + "\\LogicalDisk(C:)\\Avg. Disk Queue Length", + "\\LogicalDisk(C:)\\Current Disk Queue Length", + "\\Memory\\Available Mbytes", + "\\Memory\\Page Faults/sec", + "\\Memory\\Pages/sec", + "\\Memory\\% Committed Bytes In Use", + "\\PhysicalDisk(*)\\Avg. Disk Queue Length", + "\\PhysicalDisk(*)\\Avg. Disk sec/Read", + "\\PhysicalDisk(*)\\Avg. Disk sec/Transfer", + "\\PhysicalDisk(*)\\Avg. Disk sec/Write", + "\\Processor Information(_Total)\\% Processor Time", + "\\User Input Delay per Process(*)\\Max Input Delay", + "\\User Input Delay per Session(*)\\Max Input Delay", + "\\RemoteFX Network(*)\\Current TCP RTT", + "\\RemoteFX Network(*)\\Current UDP Bandwidth" + ], + "name": "perfCounterDataSource10" + }, + { + "streams": [ + "Microsoft-Perf" + ], + "samplingFrequencyInSeconds": 60, + "counterSpecifiers": [ + "\\LogicalDisk(C:)\\% Free Space", + "\\LogicalDisk(C:)\\Avg. Disk sec/Transfer", + "\\Terminal Services(*)\\Active Sessions", + "\\Terminal Services(*)\\Inactive Sessions", + "\\Terminal Services(*)\\Total Sessions" + ], + "name": "perfCounterDataSource30" + } + ], + "windowsEventLogs": [ + { + "streams": [ + "Microsoft-Event" + ], + "xPathQueries": [ + "Microsoft-Windows-TerminalServices-RemoteConnectionManager/Admin!*[System[(Level=2 or Level=3 or Level=4 or Level=0) ]]", + "Microsoft-Windows-TerminalServices-LocalSessionManager/Operational!*[System[(Level=2 or Level=3 or Level=4 or Level=0)]]", + "System!*", + "Microsoft-FSLogix-Apps/Operational!*[System[(Level=2 or Level=3 or Level=4 or Level=0)]]", + "Application!*[System[(Level=2 or Level=3)]]", + "Microsoft-FSLogix-Apps/Admin!*[System[(Level=2 or Level=3 or Level=4 or Level=0)]]" + ], + "name": "eventLogsDataSource" + } + ] + }, + "description": "AVD Insights settings", + "destinations": { + "logAnalytics": [ + { + "name": "[variables('varAlaWorkspaceName')]", + "workspaceResourceId": "[parameters('alaWorkspaceId')]" + } + ] + }, + "streamDeclarations": {} + } + } + ], + "outputs": { + "dataCollectionRulesId": { + "type": "string", + "value": "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time')))]", + "[subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('Monitoing-RG-{0}', parameters('time')))]" + ] + } + ], + "outputs": { + "avdAlaWorkspaceResourceId": { + "type": "string", + "value": "[if(parameters('deployAlaWorkspace'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, parameters('alaWorkspaceId'))]" + }, + "avdAlaWorkspaceId": { + "type": "string", + "value": "[if(parameters('deployAlaWorkspace'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time'))), '2022-09-01').outputs.logAnalyticsWorkspaceId.value, parameters('alaWorkspaceId'))]" + }, + "dataCollectionRuleId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('Mon-DCR-{0}', parameters('time'))), '2022-09-01').outputs.dataCollectionRulesId.value]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Deploy-Network-RG-{0}', parameters('time')))]", + "baselineResourceGroups", + "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]" + ] + }, + { + "condition": "[or(or(or(or(parameters('createAvdVnet'), parameters('createPrivateDnsZones')), parameters('avdDeploySessionHosts')), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Networking-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "createVnet": { + "value": "[parameters('createAvdVnet')]" + }, + "deployAsg": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', true()), createObject('value', false()))]", + "existingAvdSubnetResourceId": { + "value": "[parameters('existingVnetAvdSubnetResourceId')]" + }, + "createPrivateDnsZones": "[if(or(parameters('deployPrivateEndpointKeyvaultStorage'), parameters('deployAvdPrivateLinkService')), createObject('value', parameters('createPrivateDnsZones')), createObject('value', false()))]", + "applicationSecurityGroupName": { + "value": "[variables('varApplicationSecurityGroupName')]" + }, + "computeObjectsRgName": { + "value": "[variables('varComputeObjectsRgName')]" + }, + "networkObjectsRgName": { + "value": "[variables('varNetworkObjectsRgName')]" + }, + "avdNetworksecurityGroupName": { + "value": "[variables('varAvdNetworksecurityGroupName')]" + }, + "anfNetworksecurityGroupName": { + "value": "[variables('varAnfNetworksecurityGroupName')]" + }, + "privateEndpointNetworksecurityGroupName": { + "value": "[variables('varPrivateEndpointNetworksecurityGroupName')]" + }, + "avdRouteTableName": { + "value": "[variables('varAvdRouteTableName')]" + }, + "privateEndpointRouteTableName": { + "value": "[variables('varPrivateEndpointRouteTableName')]" + }, + "vnetAddressPrefixes": { + "value": "[parameters('avdVnetworkAddressPrefixes')]" + }, + "vnetName": { + "value": "[variables('varVnetName')]" + }, + "vnetPeeringName": { + "value": "[variables('varVnetPeeringName')]" + }, + "remoteVnetPeeringName": { + "value": "[variables('varRemoteVnetPeeringName')]" + }, + "vnetAvdSubnetName": { + "value": "[variables('varVnetAvdSubnetName')]" + }, + "vnetPrivateEndpointSubnetName": { + "value": "[variables('varVnetPrivateEndpointSubnetName')]" + }, + "vnetAnfSubnetName": { + "value": "[variables('varVnetAnfSubnetName')]" + }, + "createVnetPeering": { + "value": "[variables('varCreateVnetPeering')]" + }, + "deployDDoSNetworkProtection": { + "value": "[parameters('deployDDoSNetworkProtection')]" + }, + "ddosProtectionPlanName": { + "value": "[variables('varDDosProtectionPlanName')]" + }, + "deployPrivateEndpointSubnet": "[if(or(parameters('deployPrivateEndpointKeyvaultStorage'), parameters('deployAvdPrivateLinkService')), createObject('value', true()), createObject('value', false()))]", + "deployAnfSubnet": "[if(equals(parameters('storageService'), 'ANF'), createObject('value', true()), createObject('value', false()))]", + "deployAvdPrivateLinkService": { + "value": "[parameters('deployAvdPrivateLinkService')]" + }, + "vNetworkGatewayOnHub": { + "value": "[parameters('vNetworkGatewayOnHub')]" + }, + "existingHubVnetResourceId": { + "value": "[parameters('existingHubVnetResourceId')]" + }, + "location": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostLocation')), createObject('value', parameters('avdManagementPlaneLocation')))]", + "vnetAvdSubnetAddressPrefix": { + "value": "[parameters('vNetworkAvdSubnetAddressPrefix')]" + }, + "vnetPrivateEndpointSubnetAddressPrefix": { + "value": "[parameters('vNetworkPrivateEndpointSubnetAddressPrefix')]" + }, + "vnetAnfSubnetAddressPrefix": { + "value": "[parameters('vNetworkAnfSubnetAddressPrefix')]" + }, + "workloadSubsId": { + "value": "[parameters('avdWorkloadSubsId')]" + }, + "dnsServers": { + "value": "[variables('varDnsServers')]" + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]", + "alaWorkspaceResourceId": "[if(parameters('avdDeployMonitoring'), if(parameters('deployAlaWorkspace'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.avdAlaWorkspaceResourceId.value), createObject('value', parameters('alaExistingWorkspaceResourceId'))), createObject('value', ''))]", + "customStaticRoutes": { + "value": "[parameters('customStaticRoutes')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "9241376745009248833" + }, + "name": "AVD LZA networking", + "description": "This module deploys vNet, NSG, ASG, UDR, private DNs zones", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "workloadSubsId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario" + } + }, + "createVnet": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Create new virtual network." + } + }, + "deployAsg": { + "type": "bool", + "metadata": { + "description": "Deploy application security group." + } + }, + "existingAvdSubnetResourceId": { + "type": "string", + "metadata": { + "description": "Existing virtual network subnet for AVD." + } + }, + "computeObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name for the AVD session hosts" + } + }, + "networkObjectsRgName": { + "type": "string", + "metadata": { + "description": "If new virtual network required for the AVD machines. Resource Group name for the virtual network." + } + }, + "vnetName": { + "type": "string", + "metadata": { + "description": "Name of the virtual network if required to be created." + } + }, + "avdNetworksecurityGroupName": { + "type": "string", + "metadata": { + "description": "AVD Network Security Group Name" + } + }, + "privateEndpointNetworksecurityGroupName": { + "type": "string", + "metadata": { + "description": "Private endpoint Network Security Group Name" + } + }, + "anfNetworksecurityGroupName": { + "type": "string", + "metadata": { + "description": "ANF Network Security Group Name" + } + }, + "applicationSecurityGroupName": { + "type": "string", + "metadata": { + "description": "Created if a new VNet for AVD is created. Application Security Group (ASG) for the session hosts." + } + }, + "avdRouteTableName": { + "type": "string", + "metadata": { + "description": "Created if the new VNet for AVD is created. Route Table name for AVD." + } + }, + "privateEndpointRouteTableName": { + "type": "string", + "metadata": { + "description": "Created if the new VNet for AVD is created. Route Table name for private endpoints." + } + }, + "vNetworkGatewayOnHub": { + "type": "bool", + "metadata": { + "description": "Does the hub contain a virtual network gateway." + } + }, + "existingHubVnetResourceId": { + "type": "string", + "metadata": { + "description": "Existing hub virtual network for peering." + } + }, + "vnetPeeringName": { + "type": "string", + "metadata": { + "description": "VNet peering name for AVD VNet to vHub." + } + }, + "remoteVnetPeeringName": { + "type": "string", + "metadata": { + "description": "Remote VNet peering name for AVD VNet to vHub." + } + }, + "createVnetPeering": { + "type": "bool", + "metadata": { + "description": "Create virtual network peering to hub." + } + }, + "ddosProtectionPlanName": { + "type": "string", + "metadata": { + "description": "DDoS Protection Plan name." + } + }, + "deployDDoSNetworkProtection": { + "type": "bool", + "metadata": { + "description": "Deploy DDoS Network Protection for virtual network." + } + }, + "deployPrivateEndpointSubnet": { + "type": "bool", + "metadata": { + "description": "Optional. AVD Accelerator will deploy with private endpoints by default." + } + }, + "deployAnfSubnet": { + "type": "bool", + "metadata": { + "description": "Deploy with ANf subnet." + } + }, + "deployAvdPrivateLinkService": { + "type": "bool", + "metadata": { + "description": "Optional. Deploys private endpoints for the AVD Private Link Service. (Default: false)" + } + }, + "vnetAddressPrefixes": { + "type": "string", + "metadata": { + "description": "AVD VNet address prefixes." + } + }, + "vnetAvdSubnetName": { + "type": "string", + "metadata": { + "description": "AVD subnet Name." + } + }, + "vnetPrivateEndpointSubnetName": { + "type": "string", + "metadata": { + "description": "Private endpoint subnet Name." + } + }, + "vnetAnfSubnetName": { + "type": "string", + "metadata": { + "description": "ANF subnet Name." + } + }, + "vnetAvdSubnetAddressPrefix": { + "type": "string", + "metadata": { + "description": "AVD VNet subnet address prefix." + } + }, + "vnetPrivateEndpointSubnetAddressPrefix": { + "type": "string", + "metadata": { + "description": "Private endpoint VNet subnet address prefix." + } + }, + "vnetAnfSubnetAddressPrefix": { + "type": "string", + "metadata": { + "description": "ANF VNet subnet address prefix." + } + }, + "dnsServers": { + "type": "array", + "metadata": { + "description": "custom DNS servers IPs" + } + }, + "createPrivateDnsZones": { + "type": "bool", + "metadata": { + "description": "Optional. Use Azure private DNS zones for private endpoints." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Location where to deploy resources." + } + }, + "tags": { + "type": "object", + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "alaWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Log analytics workspace for diagnostic logs." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment" + } + }, + "customStaticRoutes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Additional customer-provided static routes to be added to the route tables." + } + } + }, + "variables": { + "varAzureCloudName": "[environment().name]", + "varCreateAvdStaticRoute": true, + "varExistingAvdVnetSubId": "[if(not(parameters('createVnet')), split(parameters('existingAvdSubnetResourceId'), '/')[2], '')]", + "varExistingAvdVnetSubRgName": "[if(not(parameters('createVnet')), split(parameters('existingAvdSubnetResourceId'), '/')[4], '')]", + "varExistingAvdVnetName": "[if(not(parameters('createVnet')), split(parameters('existingAvdSubnetResourceId'), '/')[8], '')]", + "varExistingAvdVnetResourceId": "[if(not(parameters('createVnet')), format('/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/virtualNetworks/{2}', variables('varExistingAvdVnetSubId'), variables('varExistingAvdVnetSubRgName'), variables('varExistingAvdVnetName')), '')]", + "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]", + "varWindowsActivationKMSPrefixesNsg": "[if(equals(variables('varAzureCloudName'), 'AzureCloud'), createArray('20.118.99.224', '40.83.235.53', '23.102.135.246'), if(equals(variables('varAzureCloudName'), 'AzureUSGovernment'), createArray('23.97.0.13', '52.126.105.2'), if(equals(variables('varAzureCloudName'), 'AzureChinaCloud'), createArray('159.27.28.100', '163.228.64.161', '42.159.7.249'), createArray())))]", + "varDefaultStaticRoutes": "[if(equals(variables('varAzureCloudName'), 'AzureCloud'), createArray(createObject('name', 'AVDServiceTraffic', 'properties', createObject('addressPrefix', 'WindowsVirtualDesktop', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'AVDStunInfraTurnRelayTraffic', 'properties', createObject('addressPrefix', '20.202.0.0/16', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'AVDTurnRelayTraffic', 'properties', createObject('addressPrefix', '51.5.0.0/16', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS', 'properties', createObject('addressPrefix', '20.118.99.224/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS01', 'properties', createObject('addressPrefix', '40.83.235.53/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS02', 'properties', createObject('addressPrefix', '23.102.135.246/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet'))), if(equals(variables('varAzureCloudName'), 'AzureUSGovernment'), createArray(createObject('name', 'AVDServiceTraffic', 'properties', createObject('addressPrefix', 'WindowsVirtualDesktop', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'AVDStunTurnTraffic', 'properties', createObject('addressPrefix', '20.202.0.0/16', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS', 'properties', createObject('addressPrefix', '23.97.0.13/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS01', 'properties', createObject('addressPrefix', '52.126.105.2/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet'))), if(equals(variables('varAzureCloudName'), 'AzureChinaCloud'), createArray(createObject('name', 'AVDServiceTraffic', 'properties', createObject('addressPrefix', 'WindowsVirtualDesktop', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'AVDStunTurnTraffic', 'properties', createObject('addressPrefix', '20.202.0.0/16', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS', 'properties', createObject('addressPrefix', '159.27.28.100/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS01', 'properties', createObject('addressPrefix', '163.228.64.161/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS02', 'properties', createObject('addressPrefix', '42.159.7.249/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet'))), createArray())))]", + "varStaticRoutes": "[union(variables('varDefaultStaticRoutes'), parameters('customStaticRoutes'))]", + "privateDnsZoneNames": { + "AutomationAgentService": "[format('privatelink.agentsvc.azure-automation.{0}', variables('privateDnsZoneSuffixes_AzureAutomation')[environment().name])]", + "Automation": "[format('privatelink.azure-automation.{0}', variables('privateDnsZoneSuffixes_AzureAutomation')[environment().name])]", + "AVDFeedConnections": "[format('privatelink.wvd.{0}', variables('privateDnsZoneSuffixes_AzureVirtualDesktop')[environment().name])]", + "AVDDiscovery": "[format('privatelink-global.wvd.{0}', variables('privateDnsZoneSuffixes_AzureVirtualDesktop')[environment().name])]", + "StorageFiles": "[format('privatelink.file.{0}', environment().suffixes.storage)]", + "StorageQueue": "[format('privatelink.queue.{0}', environment().suffixes.storage)]", + "StorageTable": "[format('privatelink.table.{0}', environment().suffixes.storage)]", + "StorageBlob": "[format('privatelink.blob.{0}', environment().suffixes.storage)]", + "KeyVault": "[replace(format('privatelink{0}', environment().suffixes.keyvaultDns), 'vault', 'vaultcore')]", + "Monitor": "[format('privatelink.monitor.{0}', variables('privateDnsZoneSuffixes_Monitor')[environment().name])]", + "MonitorODS": "[format('privatelink.ods.opinsights.{0}', variables('privateDnsZoneSuffixes_Monitor')[environment().name])]", + "MonitorOMS": "[format('privatelink.oms.opinsights.{0}', variables('privateDnsZoneSuffixes_Monitor')[environment().name])]" + }, + "privateDnsZoneSuffixes_AzureAutomation": { + "AzureCloud": "net", + "AzureUSGovernment": "us" + }, + "privateDnsZoneSuffixes_AzureVirtualDesktop": { + "AzureCloud": "microsoft.com", + "AzureUSGovernment": "azure.us" + }, + "privateDnsZoneSuffixes_Monitor": { + "AzureCloud": "azure.com", + "AzureUSGovernment": "azure.us" + } + }, + "resources": [ + { + "condition": "[parameters('createVnet')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('NSG-AVD-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('avdNetworksecurityGroupName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" + }, + "securityRules": { + "value": [ + { + "name": "AVDServiceTraffic", + "properties": { + "priority": 100, + "access": "Allow", + "description": "Session host traffic to AVD control plane", + "destinationAddressPrefix": "WindowsVirtualDesktop", + "direction": "Outbound", + "sourcePortRange": "*", + "destinationPortRange": "443", + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "AzureCloud", + "properties": { + "priority": 110, + "access": "Allow", + "description": "Session host traffic to Azure cloud services", + "destinationAddressPrefix": "AzureCloud", + "direction": "Outbound", + "sourcePortRange": "*", + "destinationPortRange": "8443", + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "AzureMonitor", + "properties": { + "priority": 120, + "access": "Allow", + "description": "Session host traffic to Azure Monitor", + "destinationAddressPrefix": "AzureMonitor", + "direction": "Outbound", + "sourcePortRange": "*", + "destinationPortRange": "443", + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "AzureMarketPlace", + "properties": { + "priority": 130, + "access": "Allow", + "description": "Session host traffic to Azure Monitor", + "destinationAddressPrefix": "AzureFrontDoor.Frontend", + "direction": "Outbound", + "sourcePortRange": "*", + "destinationPortRange": "443", + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "WindowsActivationKMS", + "properties": { + "priority": 140, + "access": "Allow", + "description": "Session host traffic to Windows license activation services", + "destinationAddressPrefixes": "[variables('varWindowsActivationKMSPrefixesNsg')]", + "direction": "Outbound", + "sourcePortRange": "*", + "destinationPortRange": "1688", + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "AzureInstanceMetadata", + "properties": { + "priority": 150, + "access": "Allow", + "description": "Session host traffic to Azure instance metadata", + "destinationAddressPrefix": "169.254.169.254", + "direction": "Outbound", + "sourcePortRange": "*", + "destinationPortRange": "80", + "protocol": "Tcp", + "sourceAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "RDPShortpath", + "properties": { + "priority": 150, + "access": "Allow", + "description": "Session host traffic to Azure instance metadata", + "destinationAddressPrefix": "VirtualNetwork", + "direction": "Inbound", + "sourcePortRange": "*", + "destinationPortRange": "3390", + "protocol": "Udp", + "sourceAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "RDPShortpathTurnStun", + "properties": { + "priority": 160, + "access": "Allow", + "description": "Session host traffic to RDP shortpath STUN/TURN", + "destinationAddressPrefix": "20.202.0.0/16", + "direction": "Outbound", + "sourcePortRange": "*", + "destinationPortRange": "3478", + "protocol": "Udp", + "sourceAddressPrefix": "VirtualNetwork" + } + }, + { + "name": "RDPShortpathTurnRelay", + "properties": { + "priority": 170, + "access": "Allow", + "description": "Session host traffic to RDP shortpath STUN/TURN", + "destinationAddressPrefix": "51.5.0.0/16", + "direction": "Outbound", + "sourcePortRange": "*", + "destinationPortRange": "3478", + "protocol": "Udp", + "sourceAddressPrefix": "VirtualNetwork" + } + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "9898059387129093740" + }, + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Network Security Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "securityRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." + } + }, + "flushConnection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the NSG resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "securityRules", + "count": "[length(parameters('securityRules'))]", + "input": { + "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", + "properties": { + "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", + "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", + "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", + "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", + "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" + } + } + } + ], + "flushConnection": "[parameters('flushConnection')]" + } + }, + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_securityRules": { + "copy": { + "name": "networkSecurityGroup_securityRules", + "count": "[length(parameters('securityRules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('securityRules')[copyIndex()].name]" + }, + "networkSecurityGroupName": { + "value": "[parameters('name')]" + }, + "protocol": { + "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" + }, + "access": { + "value": "[parameters('securityRules')[copyIndex()].properties.access]" + }, + "priority": { + "value": "[parameters('securityRules')[copyIndex()].properties.priority]" + }, + "direction": { + "value": "[parameters('securityRules')[copyIndex()].properties.direction]" + }, + "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "714966927696814087" + }, + "name": "Network Security Group (NSG) Security Rules", + "description": "This module deploys a Network Security Group (NSG) Security Rule.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security rule." + } + }, + "networkSecurityGroupName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." + } + }, + "access": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. Whether network traffic is allowed or denied." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 140, + "metadata": { + "description": "Optional. A description for this rule." + } + }, + "destinationAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + } + }, + "destinationApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as destination." + } + }, + "destinationPortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "metadata": { + "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The source port ranges." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", + "properties": { + "access": "[parameters('access')]", + "description": "[parameters('description')]", + "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", + "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", + "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", + "destinationPortRange": "[parameters('destinationPortRange')]", + "destinationPortRanges": "[parameters('destinationPortRanges')]", + "direction": "[parameters('direction')]", + "priority": "[parameters('priority')]", + "protocol": "[parameters('protocol')]", + "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", + "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", + "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", + "sourcePortRange": "[parameters('sourcePortRange')]", + "sourcePortRanges": "[parameters('sourcePortRanges')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the security rule was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the security rule." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the security rule." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "networkSecurityGroup" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network security group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the network security group." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the network security group." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('NSG-Private-Endpoint-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('privateEndpointNetworksecurityGroupName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" + }, + "securityRules": { + "value": [] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "9898059387129093740" + }, + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Network Security Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "securityRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." + } + }, + "flushConnection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the NSG resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "securityRules", + "count": "[length(parameters('securityRules'))]", + "input": { + "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", + "properties": { + "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", + "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", + "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", + "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", + "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" + } + } + } + ], + "flushConnection": "[parameters('flushConnection')]" + } + }, + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_securityRules": { + "copy": { + "name": "networkSecurityGroup_securityRules", + "count": "[length(parameters('securityRules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('securityRules')[copyIndex()].name]" + }, + "networkSecurityGroupName": { + "value": "[parameters('name')]" + }, + "protocol": { + "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" + }, + "access": { + "value": "[parameters('securityRules')[copyIndex()].properties.access]" + }, + "priority": { + "value": "[parameters('securityRules')[copyIndex()].properties.priority]" + }, + "direction": { + "value": "[parameters('securityRules')[copyIndex()].properties.direction]" + }, + "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "714966927696814087" + }, + "name": "Network Security Group (NSG) Security Rules", + "description": "This module deploys a Network Security Group (NSG) Security Rule.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security rule." + } + }, + "networkSecurityGroupName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." + } + }, + "access": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. Whether network traffic is allowed or denied." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 140, + "metadata": { + "description": "Optional. A description for this rule." + } + }, + "destinationAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + } + }, + "destinationApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as destination." + } + }, + "destinationPortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "metadata": { + "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The source port ranges." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", + "properties": { + "access": "[parameters('access')]", + "description": "[parameters('description')]", + "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", + "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", + "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", + "destinationPortRange": "[parameters('destinationPortRange')]", + "destinationPortRanges": "[parameters('destinationPortRanges')]", + "direction": "[parameters('direction')]", + "priority": "[parameters('priority')]", + "protocol": "[parameters('protocol')]", + "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", + "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", + "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", + "sourcePortRange": "[parameters('sourcePortRange')]", + "sourcePortRanges": "[parameters('sourcePortRanges')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the security rule was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the security rule." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the security rule." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "networkSecurityGroup" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network security group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the network security group." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the network security group." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[and(parameters('createVnet'), parameters('deployAnfSubnet'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('NSG-ANF-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('anfNetworksecurityGroupName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" + }, + "securityRules": { + "value": [] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "9898059387129093740" + }, + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Network Security Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "securityRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." + } + }, + "flushConnection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the NSG resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "securityRules", + "count": "[length(parameters('securityRules'))]", + "input": { + "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", + "properties": { + "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", + "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", + "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", + "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", + "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" + } + } + } + ], + "flushConnection": "[parameters('flushConnection')]" + } + }, + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_securityRules": { + "copy": { + "name": "networkSecurityGroup_securityRules", + "count": "[length(parameters('securityRules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('securityRules')[copyIndex()].name]" + }, + "networkSecurityGroupName": { + "value": "[parameters('name')]" + }, + "protocol": { + "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" + }, + "access": { + "value": "[parameters('securityRules')[copyIndex()].properties.access]" + }, + "priority": { + "value": "[parameters('securityRules')[copyIndex()].properties.priority]" + }, + "direction": { + "value": "[parameters('securityRules')[copyIndex()].properties.direction]" + }, + "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "714966927696814087" + }, + "name": "Network Security Group (NSG) Security Rules", + "description": "This module deploys a Network Security Group (NSG) Security Rule.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security rule." + } + }, + "networkSecurityGroupName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." + } + }, + "access": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. Whether network traffic is allowed or denied." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 140, + "metadata": { + "description": "Optional. A description for this rule." + } + }, + "destinationAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + } + }, + "destinationApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as destination." + } + }, + "destinationPortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "metadata": { + "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The source port ranges." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", + "properties": { + "access": "[parameters('access')]", + "description": "[parameters('description')]", + "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", + "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", + "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", + "destinationPortRange": "[parameters('destinationPortRange')]", + "destinationPortRanges": "[parameters('destinationPortRanges')]", + "direction": "[parameters('direction')]", + "priority": "[parameters('priority')]", + "protocol": "[parameters('protocol')]", + "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", + "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", + "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", + "sourcePortRange": "[parameters('sourcePortRange')]", + "sourcePortRanges": "[parameters('sourcePortRanges')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the security rule was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the security rule." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the security rule." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "networkSecurityGroup" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network security group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the network security group." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the network security group." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[parameters('deployAsg')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('ASG-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('applicationSecurityGroupName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "6399800135303615704" + }, + "name": "Application Security Groups (ASG)", + "description": "This module deploys an Application Security Group (ASG).", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application Security Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-applicationsecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "applicationSecurityGroup": { + "type": "Microsoft.Network/applicationSecurityGroups", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application security group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application security group." + }, + "value": "[resourceId('Microsoft.Network/applicationSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the application security group." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('applicationSecurityGroup', '2023-04-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[parameters('createVnet')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Route-Table-AVD-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('avdRouteTableName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "routes": "[if(variables('varCreateAvdStaticRoute'), createObject('value', variables('varStaticRoutes')), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "17894283484101609343" + }, + "name": "Route Tables", + "description": "This module deploys a User Defined Route Table (UDR).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "routeType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the route." + } + }, + "properties": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "None", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The type of Azure hop the packet should be sent to." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination CIDR to which the route applies." + } + }, + "hasBgpOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." + } + }, + "nextHopIpAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "description": "Required. Properties of the route." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name given for the hub route table." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "routes": { + "$ref": "#/definitions/routeType", + "metadata": { + "description": "Optional. An array of routes to be established within the hub route table." + } + }, + "disableBgpRoutePropagation": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Switch to disable BGP route propagation." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "routeTable": { + "type": "Microsoft.Network/routeTables", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "routes": "[parameters('routes')]", + "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the route table was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the route table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the route table." + }, + "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('routeTable', '2023-04-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Route-Table-PE-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('privateEndpointRouteTableName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "routes": { + "value": [] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "17894283484101609343" + }, + "name": "Route Tables", + "description": "This module deploys a User Defined Route Table (UDR).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "routeType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the route." + } + }, + "properties": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "None", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The type of Azure hop the packet should be sent to." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination CIDR to which the route applies." + } + }, + "hasBgpOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." + } + }, + "nextHopIpAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "description": "Required. Properties of the route." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name given for the hub route table." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "routes": { + "$ref": "#/definitions/routeType", + "metadata": { + "description": "Optional. An array of routes to be established within the hub route table." + } + }, + "disableBgpRoutePropagation": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Switch to disable BGP route propagation." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "routeTable": { + "type": "Microsoft.Network/routeTables", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "routes": "[parameters('routes')]", + "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the route table was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the route table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the route table." + }, + "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('routeTable', '2023-04-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[parameters('deployDDoSNetworkProtection')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('DDoS-Protection-Plan-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('ddosProtectionPlanName')]" + }, + "location": { + "value": "[parameters('location')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "6678083091788427255" + }, + "name": "DDoS Protection Plans", + "description": "This module deploys a DDoS Protection Plan.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the DDoS protection plan to assign the VNET to." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-ddosprotectionplan.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "ddosProtectionPlan": { + "type": "Microsoft.Network/ddosProtectionPlans", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the DDOS protection plan was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the DDOS protection plan." + }, + "value": "[resourceId('Microsoft.Network/ddosProtectionPlans', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the DDOS protection plan." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('ddosProtectionPlan', '2023-11-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[parameters('createVnet')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('vNet-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('vnetName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "addressPrefixes": { + "value": "[array(parameters('vnetAddressPrefixes'))]" + }, + "dnsServers": { + "value": "[parameters('dnsServers')]" + }, + "peerings": "[if(parameters('createVnetPeering'), createObject('value', createArray(createObject('remoteVirtualNetworkId', parameters('existingHubVnetResourceId'), 'name', parameters('vnetPeeringName'), 'allowForwardedTraffic', true(), 'allowGatewayTransit', false(), 'allowVirtualNetworkAccess', true(), 'doNotVerifyRemoteGateways', true(), 'useRemoteGateways', if(parameters('vNetworkGatewayOnHub'), true(), false()), 'remotePeeringEnabled', true(), 'remotePeeringName', parameters('remoteVnetPeeringName'), 'remotePeeringAllowForwardedTraffic', true(), 'remotePeeringAllowGatewayTransit', if(parameters('vNetworkGatewayOnHub'), true(), false()), 'remotePeeringAllowVirtualNetworkAccess', true(), 'remotePeeringDoNotVerifyRemoteGateways', true(), 'remotePeeringUseRemoteGateways', false()))), createObject('value', createArray()))]", + "subnets": { + "value": "[union(if(parameters('deployPrivateEndpointSubnet'), createArray(createObject('name', parameters('vnetAvdSubnetName'), 'addressPrefix', parameters('vnetAvdSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''))), createArray(createObject('name', parameters('vnetAvdSubnetName'), 'addressPrefix', parameters('vnetAvdSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage', 'locations', createArray(format('{0}', parameters('location')))), createObject('service', 'Microsoft.KeyVault', 'locations', createArray(format('{0}', parameters('location')))))))), if(parameters('deployAnfSubnet'), createArray(createObject('name', parameters('vnetAnfSubnetName'), 'addressPrefix', parameters('vnetAnfSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(and(parameters('createVnet'), parameters('deployAnfSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-ANF-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'delegations', createArray(createObject('name', 'delegation', 'properties', createObject('serviceName', 'Microsoft.NetApp/volumes'))))), createArray()), if(parameters('deployPrivateEndpointSubnet'), createArray(createObject('name', parameters('vnetPrivateEndpointSubnetName'), 'addressPrefix', parameters('vnetPrivateEndpointSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-Private-Endpoint-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-PE-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''))), createArray()))]" + }, + "ddosProtectionPlanResourceId": "[if(parameters('deployDDoSNetworkProtection'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('DDoS-Protection-Plan-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', ''))]", + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "18267772730058349233" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Virtual Network (vNet)." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Required. An Array of 1 or more IP Address Prefixes for the Virtual Network." + } + }, + "subnets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An Array of subnets to deploy to the Virtual Network." + } + }, + "dnsServers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. DNS Servers associated to the Virtual Network." + } + }, + "ddosProtectionPlanResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + } + }, + "peerings": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Virtual Network Peerings configurations." + } + }, + "vnetEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." + } + }, + "vnetEncryptionEnforcement": { + "type": "string", + "defaultValue": "AllowUnencrypted", + "allowedValues": [ + "AllowUnencrypted", + "DropUnencrypted" + ], + "metadata": { + "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." + } + }, + "flowTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "maxValue": 30, + "metadata": { + "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "virtualNetwork": { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "subnets", + "count": "[length(parameters('subnets'))]", + "input": { + "name": "[parameters('subnets')[copyIndex('subnets')].name]", + "properties": { + "addressPrefix": "[parameters('subnets')[copyIndex('subnets')].addressPrefix]", + "addressPrefixes": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'addressPrefixes'), parameters('subnets')[copyIndex('subnets')].addressPrefixes, createArray())]", + "applicationGatewayIPConfigurations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'applicationGatewayIPConfigurations'), parameters('subnets')[copyIndex('subnets')].applicationGatewayIPConfigurations, createArray())]", + "delegations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'delegations'), parameters('subnets')[copyIndex('subnets')].delegations, createArray())]", + "ipAllocations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'ipAllocations'), parameters('subnets')[copyIndex('subnets')].ipAllocations, createArray())]", + "natGateway": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'natGatewayResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].natGatewayResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].natGatewayResourceId), null())]", + "networkSecurityGroup": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'networkSecurityGroupResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].networkSecurityGroupResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].networkSecurityGroupResourceId), null())]", + "privateEndpointNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'privateEndpointNetworkPolicies'), parameters('subnets')[copyIndex('subnets')].privateEndpointNetworkPolicies, null())]", + "privateLinkServiceNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'privateLinkServiceNetworkPolicies'), parameters('subnets')[copyIndex('subnets')].privateLinkServiceNetworkPolicies, null())]", + "routeTable": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'routeTableResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].routeTableResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].routeTableResourceId), null())]", + "serviceEndpoints": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'serviceEndpoints'), parameters('subnets')[copyIndex('subnets')].serviceEndpoints, createArray())]", + "serviceEndpointPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'serviceEndpointPolicies'), parameters('subnets')[copyIndex('subnets')].serviceEndpointPolicies, createArray())]" + } + } + } + ], + "addressSpace": { + "addressPrefixes": "[parameters('addressPrefixes')]" + }, + "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", + "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", + "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", + "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]" + } + }, + "virtualNetwork_diagnosticSettings": { + "copy": { + "name": "virtualNetwork_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_subnets": { + "copy": { + "name": "virtualNetwork_subnets", + "count": "[length(parameters('subnets'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-subnet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualNetworkName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('subnets')[copyIndex()].name]" + }, + "addressPrefix": { + "value": "[parameters('subnets')[copyIndex()].addressPrefix]" + }, + "addressPrefixes": "[if(contains(parameters('subnets')[copyIndex()], 'addressPrefixes'), createObject('value', parameters('subnets')[copyIndex()].addressPrefixes), createObject('value', createArray()))]", + "applicationGatewayIPConfigurations": "[if(contains(parameters('subnets')[copyIndex()], 'applicationGatewayIPConfigurations'), createObject('value', parameters('subnets')[copyIndex()].applicationGatewayIPConfigurations), createObject('value', createArray()))]", + "delegations": "[if(contains(parameters('subnets')[copyIndex()], 'delegations'), createObject('value', parameters('subnets')[copyIndex()].delegations), createObject('value', createArray()))]", + "ipAllocations": "[if(contains(parameters('subnets')[copyIndex()], 'ipAllocations'), createObject('value', parameters('subnets')[copyIndex()].ipAllocations), createObject('value', createArray()))]", + "natGatewayResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'natGatewayResourceId'), createObject('value', parameters('subnets')[copyIndex()].natGatewayResourceId), createObject('value', ''))]", + "networkSecurityGroupResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('subnets')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", + "privateEndpointNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'privateEndpointNetworkPolicies'), createObject('value', parameters('subnets')[copyIndex()].privateEndpointNetworkPolicies), createObject('value', ''))]", + "privateLinkServiceNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'privateLinkServiceNetworkPolicies'), createObject('value', parameters('subnets')[copyIndex()].privateLinkServiceNetworkPolicies), createObject('value', ''))]", + "roleAssignments": "[if(contains(parameters('subnets')[copyIndex()], 'roleAssignments'), createObject('value', parameters('subnets')[copyIndex()].roleAssignments), createObject('value', createArray()))]", + "routeTableResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'routeTableResourceId'), createObject('value', parameters('subnets')[copyIndex()].routeTableResourceId), createObject('value', ''))]", + "serviceEndpointPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'serviceEndpointPolicies'), createObject('value', parameters('subnets')[copyIndex()].serviceEndpointPolicies), createObject('value', createArray()))]", + "serviceEndpoints": "[if(contains(parameters('subnets')[copyIndex()], 'serviceEndpoints'), createObject('value', parameters('subnets')[copyIndex()].serviceEndpoints), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "16351454463417912386" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Optional. The Name of the subnet resource." + } + }, + "virtualNetworkName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. The address prefix for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "delegations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The delegations to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of address prefixes for the subnet." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "ipAllocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of IpAllocation which reference this subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2023-04-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "properties": { + "addressPrefix": "[parameters('addressPrefix')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "serviceEndpoints": "[parameters('serviceEndpoints')]", + "delegations": "[parameters('delegations')]", + "privateEndpointNetworkPolicies": "[if(not(empty(parameters('privateEndpointNetworkPolicies'))), parameters('privateEndpointNetworkPolicies'), null())]", + "privateLinkServiceNetworkPolicies": "[if(not(empty(parameters('privateLinkServiceNetworkPolicies'))), parameters('privateLinkServiceNetworkPolicies'), null())]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "ipAllocations": "[parameters('ipAllocations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]" + } + }, + "subnet_roleAssignments": { + "copy": { + "name": "subnet_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}/subnets/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "subnet" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "subnetAddressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[reference('subnet').addressPrefix]" + }, + "subnetAddressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[if(not(empty(parameters('addressPrefixes'))), reference('subnet').addressPrefixes, createArray())]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_local": { + "copy": { + "name": "virtualNetwork_peering_local", + "count": "[length(parameters('peerings'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[parameters('name')]" + }, + "remoteVirtualNetworkId": { + "value": "[parameters('peerings')[copyIndex()].remoteVirtualNetworkId]" + }, + "name": "[if(contains(parameters('peerings')[copyIndex()], 'name'), createObject('value', parameters('peerings')[copyIndex()].name), createObject('value', format('{0}-{1}', parameters('name'), last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')))))]", + "allowForwardedTraffic": "[if(contains(parameters('peerings')[copyIndex()], 'allowForwardedTraffic'), createObject('value', parameters('peerings')[copyIndex()].allowForwardedTraffic), createObject('value', true()))]", + "allowGatewayTransit": "[if(contains(parameters('peerings')[copyIndex()], 'allowGatewayTransit'), createObject('value', parameters('peerings')[copyIndex()].allowGatewayTransit), createObject('value', false()))]", + "allowVirtualNetworkAccess": "[if(contains(parameters('peerings')[copyIndex()], 'allowVirtualNetworkAccess'), createObject('value', parameters('peerings')[copyIndex()].allowVirtualNetworkAccess), createObject('value', true()))]", + "doNotVerifyRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'doNotVerifyRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].doNotVerifyRemoteGateways), createObject('value', true()))]", + "useRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'useRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].useRemoteGateways), createObject('value', false()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "15212353974601574751" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "metadata": { + "description": "Optional. The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_remote": { + "copy": { + "name": "virtualNetwork_peering_remote", + "count": "[length(parameters('peerings'))]" + }, + "condition": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringEnabled'), equals(parameters('peerings')[copyIndex()].remotePeeringEnabled, true()), false())]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[2]]", + "resourceGroup": "[split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/'))]" + }, + "remoteVirtualNetworkId": { + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringName'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringName), createObject('value', format('{0}-{1}', last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')), parameters('name'))))]", + "allowForwardedTraffic": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowForwardedTraffic'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowForwardedTraffic), createObject('value', true()))]", + "allowGatewayTransit": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowGatewayTransit'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowGatewayTransit), createObject('value', false()))]", + "allowVirtualNetworkAccess": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowVirtualNetworkAccess), createObject('value', true()))]", + "doNotVerifyRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringDoNotVerifyRemoteGateways), createObject('value', true()))]", + "useRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringUseRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringUseRemoteGateways), createObject('value', false()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "15212353974601574751" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "metadata": { + "description": "Optional. The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network." + }, + "value": "[parameters('name')]" + }, + "subnetNames": { + "type": "array", + "metadata": { + "description": "The names of the deployed subnets." + }, + "copy": { + "count": "[length(parameters('subnets'))]", + "input": "[parameters('subnets')[copyIndex()].name]" + } + }, + "subnetResourceIds": { + "type": "array", + "metadata": { + "description": "The resource IDs of the deployed subnets." + }, + "copy": { + "count": "[length(parameters('subnets'))]", + "input": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('name'), parameters('subnets')[copyIndex()].name)]" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetwork', '2023-04-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('DDoS-Protection-Plan-{0}', parameters('time')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-ANF-{0}', parameters('time')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-Private-Endpoint-{0}', parameters('time')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-PE-{0}', parameters('time')))]" + ] + }, + { + "condition": "[parameters('createPrivateDnsZones')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Private-DNS-Files-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('privateDnsZoneNames').StorageFiles]" + }, + "virtualNetworkLinks": "[if(parameters('createVnet'), createObject('value', createArray(createObject('virtualNetworkResourceId', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value))), createObject('value', createArray(createObject('virtualNetworkResourceId', variables('varExistingAvdVnetResourceId')))))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "9826379828964980786" + }, + "name": "Private DNS Zones", + "description": "This module deploys a Private DNS zone.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Private DNS zone name." + } + }, + "virtualNetworkLinks": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2024-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "privateDnsZone_virtualNetworkLinks": { + "copy": { + "name": "privateDnsZone_virtualNetworkLinks", + "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-VirtualNetworkLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" + }, + "virtualNetworkResourceId": { + "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" + }, + "registrationEnabled": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4846633428140292997" + }, + "name": "Private DNS Zone Virtual Network Link", + "description": "This module deploys a Private DNS Zone Virtual Network Link.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "registrationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2024-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "registrationEnabled": "[parameters('registrationEnabled')]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private DNS zone." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private DNS zone." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateDnsZone', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time')))]" + ] + }, + { + "condition": "[parameters('createPrivateDnsZones')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Private-DNS-Kv-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('privateDnsZoneNames').KeyVault]" + }, + "virtualNetworkLinks": "[if(parameters('createVnet'), createObject('value', createArray(createObject('virtualNetworkResourceId', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value))), createObject('value', createArray(createObject('virtualNetworkResourceId', variables('varExistingAvdVnetResourceId')))))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "9826379828964980786" + }, + "name": "Private DNS Zones", + "description": "This module deploys a Private DNS zone.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Private DNS zone name." + } + }, + "virtualNetworkLinks": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2024-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "privateDnsZone_virtualNetworkLinks": { + "copy": { + "name": "privateDnsZone_virtualNetworkLinks", + "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-VirtualNetworkLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" + }, + "virtualNetworkResourceId": { + "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" + }, + "registrationEnabled": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4846633428140292997" + }, + "name": "Private DNS Zone Virtual Network Link", + "description": "This module deploys a Private DNS Zone Virtual Network Link.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "registrationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2024-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "registrationEnabled": "[parameters('registrationEnabled')]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private DNS zone." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private DNS zone." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateDnsZone', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time')))]" + ] + }, + { + "condition": "[and(parameters('createPrivateDnsZones'), parameters('deployAvdPrivateLinkService'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Private-DNS-AVD-Connection-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('privateDnsZoneNames').AVDFeedConnections]" + }, + "virtualNetworkLinks": "[if(parameters('createVnet'), createObject('value', createArray(createObject('virtualNetworkResourceId', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value))), createObject('value', createArray(createObject('virtualNetworkResourceId', variables('varExistingAvdVnetResourceId')))))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "9826379828964980786" + }, + "name": "Private DNS Zones", + "description": "This module deploys a Private DNS zone.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Private DNS zone name." + } + }, + "virtualNetworkLinks": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2024-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "privateDnsZone_virtualNetworkLinks": { + "copy": { + "name": "privateDnsZone_virtualNetworkLinks", + "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-VirtualNetworkLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" + }, + "virtualNetworkResourceId": { + "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" + }, + "registrationEnabled": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4846633428140292997" + }, + "name": "Private DNS Zone Virtual Network Link", + "description": "This module deploys a Private DNS Zone Virtual Network Link.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "registrationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2024-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "registrationEnabled": "[parameters('registrationEnabled')]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private DNS zone." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private DNS zone." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateDnsZone', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time')))]" + ] + }, + { + "condition": "[and(parameters('createPrivateDnsZones'), parameters('deployAvdPrivateLinkService'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Private-DNS-AVD-Discovery-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('privateDnsZoneNames').AVDDiscovery]" + }, + "virtualNetworkLinks": "[if(parameters('createVnet'), createObject('value', createArray(createObject('virtualNetworkResourceId', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value))), createObject('value', createArray(createObject('virtualNetworkResourceId', variables('varExistingAvdVnetResourceId')))))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "9826379828964980786" + }, + "name": "Private DNS Zones", + "description": "This module deploys a Private DNS zone.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Private DNS zone name." + } + }, + "virtualNetworkLinks": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateDnsZone": { + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2024-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "privateDnsZone_virtualNetworkLinks": { + "copy": { + "name": "privateDnsZone_virtualNetworkLinks", + "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateDnsZone-VirtualNetworkLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDnsZoneName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" + }, + "virtualNetworkResourceId": { + "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" + }, + "registrationEnabled": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4846633428140292997" + }, + "name": "Private DNS Zone Virtual Network Link", + "description": "This module deploys a Private DNS Zone Virtual Network Link.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateDnsZoneName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the virtual network link." + } + }, + "location": { + "type": "string", + "defaultValue": "global", + "metadata": { + "description": "Optional. The location of the PrivateDNSZone. Should be global." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "registrationEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Link to another virtual network resource ID." + } + } + }, + "resources": { + "privateDnsZone": { + "existing": true, + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2024-06-01", + "name": "[parameters('privateDnsZoneName')]" + }, + "virtualNetworkLink": { + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2024-06-01", + "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "registrationEnabled": "[parameters('registrationEnabled')]", + "virtualNetwork": { + "id": "[parameters('virtualNetworkResourceId')]" + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed virtual network link." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed virtual network link." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed virtual network link." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "privateDnsZone" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private DNS zone was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private DNS zone." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private DNS zone." + }, + "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateDnsZone', '2024-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time')))]" + ] + } + ], + "outputs": { + "applicationSecurityGroupResourceId": { + "type": "string", + "value": "[if(parameters('deployAsg'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('computeObjectsRgName'))), 'Microsoft.Resources/deployments', format('ASG-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" + }, + "virtualNetworkResourceId": { + "type": "string", + "value": "[if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" + }, + "azureFilesDnsZoneResourceId": { + "type": "string", + "value": "[if(parameters('createPrivateDnsZones'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Private-DNS-Files-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" + }, + "keyVaultDnsZoneResourceId": { + "type": "string", + "value": "[if(parameters('createPrivateDnsZones'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Private-DNS-Kv-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" + }, + "avdDnsConnectionZoneResourceId": { + "type": "string", + "value": "[if(and(parameters('createPrivateDnsZones'), parameters('deployAvdPrivateLinkService')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Private-DNS-AVD-Connection-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" + }, + "avdDnsDiscoveryZoneResourceId": { + "type": "string", + "value": "[if(and(parameters('createPrivateDnsZones'), parameters('deployAvdPrivateLinkService')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Private-DNS-AVD-Discovery-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Deploy-Network-RG-{0}', parameters('time')))]", + "baselineResourceGroups", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('AVD-MGMT-Plane-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "applicationGroupName": { + "value": "[variables('varApplicationGroupName')]" + }, + "applicationGroupFriendlyNameDesktop": { + "value": "[variables('varApplicationGroupFriendlyName')]" + }, + "workSpaceName": { + "value": "[variables('varWorkSpaceName')]" + }, + "mpImageSku": "[if(parameters('useSharedImage'), createObject('value', ''), createObject('value', parameters('mpImageSku')))]", + "keyVaultResourceId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" + }, + "workSpaceFriendlyName": { + "value": "[variables('varWorkSpaceFriendlyName')]" + }, + "computeTimeZone": { + "value": "[variables('varTimeZoneSessionHosts')]" + }, + "hostPoolName": { + "value": "[variables('varHostPoolName')]" + }, + "hostPoolFriendlyName": { + "value": "[variables('varHostFriendlyName')]" + }, + "hostPoolRdpProperties": { + "value": "[parameters('avdHostPoolRdpProperties')]" + }, + "hostPoolLoadBalancerType": { + "value": "[parameters('avdHostPoolLoadBalancerType')]" + }, + "hostPoolType": { + "value": "[parameters('avdHostPoolType')]" + }, + "preferredAppGroupType": "[if(equals(parameters('hostPoolPreferredAppGroupType'), 'RemoteApp'), createObject('value', 'RailApplications'), createObject('value', 'Desktop'))]", + "deployScalingPlan": "[if(not(empty(parameters('avdServicePrincipalObjectId'))), createObject('value', variables('varDeployScalingPlan')), createObject('value', false()))]", + "scalingPlanExclusionTag": { + "value": "[variables('varScalingPlanExclusionTag')]" + }, + "scalingPlanSchedules": "[if(equals(parameters('avdHostPoolType'), 'Pooled'), createObject('value', variables('varPooledScalingPlanSchedules')), createObject('value', variables('varPersonalScalingPlanSchedules')))]", + "scalingPlanName": { + "value": "[variables('varScalingPlanName')]" + }, + "hostPoolMaxSessions": { + "value": "[parameters('hostPoolMaxSessions')]" + }, + "personalAssignType": { + "value": "[parameters('avdPersonalAssignType')]" + }, + "managementPlaneLocation": { + "value": "[parameters('avdManagementPlaneLocation')]" + }, + "serviceObjectsRgName": { + "value": "[variables('varServiceObjectsRgName')]" + }, + "startVmOnConnect": { + "value": "[parameters('avdStartVmOnConnect')]" + }, + "subscriptionId": { + "value": "[parameters('avdWorkloadSubsId')]" + }, + "identityServiceProvider": { + "value": "[parameters('avdIdentityServiceProvider')]" + }, + "securityPrincipalId": { + "value": "[variables('varSecurityPrincipalId')]" + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]", + "alaWorkspaceResourceId": "[if(parameters('avdDeployMonitoring'), if(parameters('deployAlaWorkspace'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.avdAlaWorkspaceResourceId.value), createObject('value', parameters('alaExistingWorkspaceResourceId'))), createObject('value', ''))]", + "hostPoolAgentUpdateSchedule": { + "value": "[variables('varHostPoolAgentUpdateSchedule')]" + }, + "deployAvdPrivateLinkService": { + "value": "[parameters('deployAvdPrivateLinkService')]" + }, + "hostPoolPublicNetworkAccess": { + "value": "[parameters('hostPoolPublicNetworkAccess')]" + }, + "workspacePublicNetworkAccess": { + "value": "[parameters('workspacePublicNetworkAccess')]" + }, + "privateEndpointSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName'))), createObject('value', parameters('existingVnetPrivateEndpointSubnetResourceId')))]", + "avdVnetPrivateDnsZoneDiscoveryResourceId": "[if(parameters('deployAvdPrivateLinkService'), if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.avdDnsDiscoveryZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneDiscoveryResourceId'))), createObject('value', ''))]", + "avdVnetPrivateDnsZoneConnectionResourceId": "[if(parameters('deployAvdPrivateLinkService'), if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.avdDnsConnectionZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneConnectionResourceId'))), createObject('value', ''))]", + "privateEndpointConnectionName": { + "value": "[variables('varPrivateEndPointConnectionName')]" + }, + "privateEndpointDiscoveryName": { + "value": "[variables('varPrivateEndPointDiscoveryName')]" + }, + "privateEndpointWorkspaceName": { + "value": "[variables('varPrivateEndPointWorkspaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4866343470162672721" + }, + "name": "AVD LZA management plane", + "description": "This module deploys AVD workspace, host pool, application group scaling plan", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "managementPlaneLocation": { + "type": "string", + "metadata": { + "description": "Location where to deploy AVD management plane." + } + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "computeTimeZone": { + "type": "string", + "metadata": { + "description": "Virtual machine time zone." + } + }, + "identityServiceProvider": { + "type": "string", + "metadata": { + "description": "The service providing domain services for Azure Virtual Desktop." + } + }, + "securityPrincipalId": { + "type": "string", + "metadata": { + "description": "Identity ID to grant RBAC role to access AVD application group." + } + }, + "mpImageSku": { + "type": "string", + "metadata": { + "description": "Marketplace AVD OS image sku." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Resource ID of keyvault that will contain host pool registration token." + } + }, + "serviceObjectsRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for the service objects." + } + }, + "applicationGroupName": { + "type": "string", + "metadata": { + "description": "AVD Application group for the session hosts. Desktop type." + } + }, + "applicationGroupFriendlyNameDesktop": { + "type": "string", + "metadata": { + "description": "AVD Application group for the session hosts. Desktop type (friendly name)." + } + }, + "deployScalingPlan": { + "type": "bool", + "metadata": { + "description": "AVD deploy scaling plan." + } + }, + "hostPoolName": { + "type": "string", + "metadata": { + "description": "AVD Host Pool Name" + } + }, + "hostPoolFriendlyName": { + "type": "string", + "metadata": { + "description": "AVD Host Pool friendly Name" + } + }, + "scalingPlanName": { + "type": "string", + "metadata": { + "description": "AVD scaling plan name" + } + }, + "scalingPlanSchedules": { + "type": "array", + "metadata": { + "description": "AVD scaling plan schedules" + } + }, + "workSpaceName": { + "type": "string", + "metadata": { + "description": "AVD workspace name." + } + }, + "workSpaceFriendlyName": { + "type": "string", + "metadata": { + "description": "AVD workspace friendly name." + } + }, + "hostPoolRdpProperties": { + "type": "string", + "metadata": { + "description": "AVD host pool Custom RDP properties." + } + }, + "hostPoolType": { + "type": "string", + "allowedValues": [ + "Personal", + "Pooled" + ], + "metadata": { + "description": "Optional. AVD host pool type." + } + }, + "preferredAppGroupType": { + "type": "string", + "defaultValue": "Desktop", + "allowedValues": [ + "Desktop", + "None", + "RailApplications" + ], + "metadata": { + "description": "Optional. The type of preferred application group type, default to Desktop Application Group." + } + }, + "deployAvdPrivateLinkService": { + "type": "bool", + "metadata": { + "description": "Deploys the AVD Private Link Service." + } + }, + "privateEndpointConnectionName": { + "type": "string", + "metadata": { + "description": "Name of the Private Endpoint for the Connection" + } + }, + "privateEndpointDiscoveryName": { + "type": "string", + "metadata": { + "description": "Name of the Private Endpoint for the Discovery" + } + }, + "privateEndpointWorkspaceName": { + "type": "string", + "metadata": { + "description": "Name of the Private Endpoint for the Workspace" + } + }, + "privateEndpointSubnetResourceId": { + "type": "string", + "metadata": { + "description": "The subnet resource ID that the private endpoint should be deployed in." + } + }, + "avdVnetPrivateDnsZoneConnectionResourceId": { + "type": "string", + "metadata": { + "description": "The ResourceID of the AVD Private DNS Zone for Connection. (privatelink.wvd.azure.com)" + } + }, + "avdVnetPrivateDnsZoneDiscoveryResourceId": { + "type": "string", + "metadata": { + "description": "The ResourceID of the AVD Private DNS Zone for Discovery. (privatelink-global.wvd.azure.com)" + } + }, + "hostPoolPublicNetworkAccess": { + "type": "string", + "defaultValue": "EnabledForClientsOnly", + "allowedValues": [ + "Disabled", + "Enabled", + "EnabledForClientsOnly", + "EnabledForSessionHostsOnly" + ], + "metadata": { + "description": "Enables or Disables public network access on the host pool. (Default: EnabledForClientsOnly.)" + } + }, + "workspacePublicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Default to Enabled. Enables or Disables public network access on the workspace." + } + }, + "personalAssignType": { + "type": "string", + "allowedValues": [ + "Automatic", + "Direct" + ], + "metadata": { + "description": "Optional. AVD host pool type." + } + }, + "hostPoolLoadBalancerType": { + "type": "string", + "allowedValues": [ + "BreadthFirst", + "DepthFirst" + ], + "metadata": { + "description": "AVD host pool load balacing type." + } + }, + "hostPoolMaxSessions": { + "type": "int", + "metadata": { + "description": "Optional. AVD host pool maximum number of user sessions per session host." + } + }, + "startVmOnConnect": { + "type": "bool", + "metadata": { + "description": "Optional. AVD host pool start VM on Connect." + } + }, + "hostPoolAgentUpdateSchedule": { + "type": "array", + "metadata": { + "description": "Optional. AVD host pool start VM on Connect." + } + }, + "tags": { + "type": "object", + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "scalingPlanExclusionTag": { + "type": "string", + "metadata": { + "description": "Tag to exclude resources from scaling plan." + } + }, + "alaWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Log analytics workspace for diagnostic logs." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + } + }, + "variables": { + "varApplicationGroups": [ + { + "name": "[parameters('applicationGroupName')]", + "friendlyName": "[parameters('applicationGroupFriendlyNameDesktop')]", + "location": "[parameters('managementPlaneLocation')]", + "applicationGroupType": "[if(equals(parameters('preferredAppGroupType'), 'Desktop'), 'Desktop', 'RemoteApp')]" + } + ], + "varHostPoolRdpPropertiesDomainServiceCheck": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), format('{0};targetisaadjoined:i:1;enablerdsaadauth:i:1', parameters('hostPoolRdpProperties')), parameters('hostPoolRdpProperties'))]", + "varRAppApplicationGroupsStandardApps": "[if(equals(parameters('preferredAppGroupType'), 'RailApplications'), createArray(createObject('name', 'Task Manager', 'description', 'Task Manager', 'friendlyName', 'Task Manager', 'showInPortal', true(), 'filePath', 'C:\\Windows\\system32\\taskmgr.exe'), createObject('name', 'WordPad', 'description', 'WordPad', 'friendlyName', 'WordPad', 'showInPortal', true(), 'filePath', 'C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe'), createObject('name', 'Microsoft Edge', 'description', 'Microsoft Edge', 'friendlyName', 'Edge', 'showInPortal', true(), 'filePath', 'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe'), createObject('name', 'Remote Desktop Connection', 'description', 'Remote Desktop Connection', 'friendlyName', 'Remote Desktop', 'showInPortal', true(), 'filePath', 'C:\\WINDOWS\\system32\\mtsc.exe')), createArray())]", + "varRAppApplicationGroupsOfficeApps": "[if(equals(parameters('preferredAppGroupType'), 'RailApplications'), createArray(createObject('name', 'Microsoft Excel', 'description', 'Microsoft Excel', 'friendlyName', 'Excel', 'showInPortal', true(), 'filePath', 'C:\\Program Files\\Microsoft Office\\root\\Office16\\EXCEL.EXE'), createObject('name', 'Microsoft PowerPoint', 'description', 'Microsoft PowerPoint', 'friendlyName', 'PowerPoint', 'showInPortal', true(), 'filePath', 'C:\\Program Files\\Microsoft Office\\root\\Office16\\POWERPNT.EXE'), createObject('name', 'Microsoft Word', 'description', 'Microsoft Word', 'friendlyName', 'Word', 'showInPortal', true(), 'filePath', 'C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE'), createObject('name', 'Microsoft Outlook', 'description', 'Microsoft Word', 'friendlyName', 'Outlook', 'showInPortal', true(), 'filePath', 'C:\\Program Files\\Microsoft Office\\root\\Office16\\OUTLOOK.EXE')), createArray())]", + "varRAppApplicationGroupsApps": "[if(equals(parameters('preferredAppGroupType'), 'RailApplications'), if(contains(parameters('mpImageSku'), 'office'), union(variables('varRAppApplicationGroupsStandardApps'), variables('varRAppApplicationGroupsOfficeApps')), variables('varRAppApplicationGroupsStandardApps')), createArray())]", + "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'))), createArray())]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('HostPool-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('hostPoolName')]" + }, + "friendlyName": { + "value": "[parameters('hostPoolFriendlyName')]" + }, + "location": { + "value": "[parameters('managementPlaneLocation')]" + }, + "hostPoolType": { + "value": "[parameters('hostPoolType')]" + }, + "startVMOnConnect": { + "value": "[parameters('startVmOnConnect')]" + }, + "customRdpProperty": { + "value": "[variables('varHostPoolRdpPropertiesDomainServiceCheck')]" + }, + "loadBalancerType": { + "value": "[parameters('hostPoolLoadBalancerType')]" + }, + "maxSessionLimit": { + "value": "[parameters('hostPoolMaxSessions')]" + }, + "preferredAppGroupType": { + "value": "[parameters('preferredAppGroupType')]" + }, + "personalDesktopAssignmentType": { + "value": "[parameters('personalAssignType')]" + }, + "keyVaultResourceId": { + "value": "[parameters('keyVaultResourceId')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "publicNetworkAccess": "[if(parameters('deployAvdPrivateLinkService'), createObject('value', parameters('hostPoolPublicNetworkAccess')), createObject('value', null()))]", + "privateEndpoints": "[if(parameters('deployAvdPrivateLinkService'), createObject('value', createArray(createObject('name', parameters('privateEndpointConnectionName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'privateDnsZoneResourceIds', createArray(parameters('avdVnetPrivateDnsZoneConnectionResourceId'))))), createObject('value', createArray()))]", + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" + }, + "agentUpdate": "[if(not(empty(parameters('hostPoolAgentUpdateSchedule'))), createObject('value', createObject('maintenanceWindows', parameters('hostPoolAgentUpdateSchedule'), 'maintenanceWindowTimeZone', parameters('computeTimeZone'), 'type', 'Scheduled', 'useSessionHostLocalTime', true())), createObject('value', createObject()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "17896773356115754728" + }, + "name": "Azure Virtual Desktop Host Pool", + "description": "This module deploys an Azure Virtual Desktop Host Pool", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the host pool." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the keyvault." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the scaling plan. Defaults to resource group location." + } + }, + "friendlyName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Friendly name of the scaling plan." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Description of the scaling plan." + } + }, + "hostPoolType": { + "type": "string", + "defaultValue": "Pooled", + "allowedValues": [ + "Personal", + "Pooled" + ], + "metadata": { + "description": "Optional. Set this parameter to Personal if you would like to enable Persistent Desktop experience. Defaults to Pooled." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled", + "EnabledForClientsOnly", + "EnabledForSessionHostsOnly" + ], + "metadata": { + "description": "Optional. Set public network access." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints." + } + }, + "personalDesktopAssignmentType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Automatic", + "Direct", + "" + ], + "metadata": { + "description": "Optional. Set the type of assignment for a Personal Host Pool type." + } + }, + "loadBalancerType": { + "type": "string", + "defaultValue": "BreadthFirst", + "allowedValues": [ + "BreadthFirst", + "DepthFirst", + "Persistent" + ], + "metadata": { + "description": "Optional. Type of load balancer algorithm." + } + }, + "maxSessionLimit": { + "type": "int", + "defaultValue": 99999, + "metadata": { + "description": "Optional. Maximum number of sessions." + } + }, + "customRdpProperty": { + "type": "string", + "defaultValue": "audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2;", + "metadata": { + "description": "Optional. Host Pool RDP properties." + } + }, + "validationEnvironment": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Validation host pools allows you to test service changes before they are deployed to production. When set to true, the Host Pool will be deployed in a validation 'ring' (environment) that receives all the new features (might be less stable). Defaults to false that stands for the stable, production-ready environment." + } + }, + "vmTemplate": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The necessary information for adding more VMs to this Host Pool." + } + }, + "tokenValidityLength": { + "type": "string", + "defaultValue": "PT8H", + "metadata": { + "description": "Optional. Host Pool token validity length. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the token will be valid for 8 hours." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to generate a registration token." + } + }, + "preferredAppGroupType": { + "type": "string", + "defaultValue": "Desktop", + "allowedValues": [ + "Desktop", + "None", + "RailApplications" + ], + "metadata": { + "description": "Optional. The type of preferred application group type, default to Desktop Application Group." + } + }, + "startVMOnConnect": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable Start VM on connect to allow users to start the virtual machine from a deallocated state. Important: Custom RBAC role required to power manage VMs." + } + }, + "agentUpdate": { + "type": "object", + "defaultValue": { + "useSessionHostLocalTime": true + }, + "metadata": { + "description": "Optional. The session host configuration for updating agent, monitoring agent, and stack component." + } + }, + "ring": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. The ring number of HostPool." + } + }, + "ssoadfsAuthority": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. URL to customer ADFS server for signing WVD SSO certificates." + } + }, + "ssoClientId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ClientId for the registered Relying Party used to issue WVD SSO certificates." + } + }, + "ssoClientSecretKeyVaultPath": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Path to Azure KeyVault storing the secret used for communication to ADFS." + } + }, + "ssoSecretType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Certificate", + "CertificateInKeyVault", + "SharedKey", + "SharedKeyInKeyVault" + ], + "metadata": { + "description": "Optional. The type of single sign on Secret Type." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[take(format('46d3xbcp.res.desktopvirtualization-hostpool.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "hostPool": { + "type": "Microsoft.DesktopVirtualization/hostPools", + "apiVersion": "2023-09-05", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "friendlyName": "[parameters('friendlyName')]", + "description": "[parameters('description')]", + "hostPoolType": "[parameters('hostPoolType')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "customRdpProperty": "[parameters('customRdpProperty')]", + "personalDesktopAssignmentType": "[parameters('personalDesktopAssignmentType')]", + "preferredAppGroupType": "[parameters('preferredAppGroupType')]", + "maxSessionLimit": "[parameters('maxSessionLimit')]", + "loadBalancerType": "[parameters('loadBalancerType')]", + "startVMOnConnect": "[parameters('startVMOnConnect')]", + "validationEnvironment": "[parameters('validationEnvironment')]", + "registrationInfo": { + "expirationTime": "[dateTimeAdd(parameters('baseTime'), parameters('tokenValidityLength'))]", + "token": null, + "registrationTokenOperation": "Update" + }, + "vmTemplate": "[if(not(empty(parameters('vmTemplate'))), null(), string(parameters('vmTemplate')))]", + "agentUpdate": "[parameters('agentUpdate')]", + "ring": "[if(not(equals(parameters('ring'), -1)), parameters('ring'), null())]", + "ssoadfsAuthority": "[parameters('ssoadfsAuthority')]", + "ssoClientId": "[parameters('ssoClientId')]", + "ssoClientSecretKeyVaultPath": "[parameters('ssoClientSecretKeyVaultPath')]", + "ssoSecretType": "[parameters('ssoSecretType')]" + } + }, + "hostPool_diagnosticSettings": { + "copy": { + "name": "hostPool_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DesktopVirtualization/hostPools/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "hostPool" + ] + }, + "keyVaultHostPoolSecret": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-HP-Token-Secret', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[format('{0}', variables('varKeyVaultSubId'))]", + "resourceGroup": "[format('{0}', variables('varKeyVaultRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[variables('varKeyVaultName')]" + }, + "name": { + "value": "hostPoolRegistrationToken" + }, + "value": { + "value": "[reference('hostPool').registrationInfo.token]" + }, + "contentType": { + "value": "Host pool registration token for session hosts" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12190317675030946449" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "contentType": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secret": { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "contentType": "[parameters('contentType')]", + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "value": "[parameters('value')]" + } + }, + "secret_roleAssignments": { + "copy": { + "name": "secret_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "secret" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the secret." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the secret." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the secret was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "hostPool" + ] + }, + "hostPool_privateEndpoints": { + "copy": { + "name": "hostPool_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-hostPool-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "hostPool" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the host pool." + }, + "value": "[resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the host pool was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the host pool." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location of the host pool." + }, + "value": "[reference('hostPool', '2023-09-05', 'full').location]" + }, + "keyVaultTokenSecretResourceId": { + "type": "string", + "metadata": { + "description": "Host pool registration token secret resource ID." + }, + "value": "[reference('keyVaultHostPoolSecret').outputs.resourceId.value]" + } + } + } + } + }, + { + "copy": { + "name": "applicationGroups", + "count": "[length(variables('varApplicationGroups'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}', variables('varApplicationGroups')[copyIndex()].name, parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('varApplicationGroups')[copyIndex()].name]" + }, + "friendlyName": { + "value": "[variables('varApplicationGroups')[copyIndex()].friendlyName]" + }, + "location": { + "value": "[variables('varApplicationGroups')[copyIndex()].location]" + }, + "applicationGroupType": { + "value": "[variables('varApplicationGroups')[copyIndex()].applicationGroupType]" + }, + "hostpoolName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('HostPool-{0}', parameters('time'))), '2022-09-01').outputs.name.value]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "applications": "[if(equals(variables('varApplicationGroups')[copyIndex()].applicationGroupType, 'RemoteApp'), createObject('value', variables('varRAppApplicationGroupsApps')), createObject('value', createArray()))]", + "roleAssignments": "[if(not(empty(parameters('securityPrincipalId'))), createObject('value', createArray(createObject('roleDefinitionIdOrName', 'Desktop Virtualization User', 'principalId', parameters('securityPrincipalId')))), createObject('value', createArray()))]", + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4794696781017607017" + }, + "name": "Azure Virtual Desktop Application Group", + "description": "This module deploys an Azure Virtual Desktop Application Group.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 3, + "metadata": { + "description": "Required. Name of the Application Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "applicationGroupType": { + "type": "string", + "allowedValues": [ + "RemoteApp", + "Desktop" + ], + "metadata": { + "description": "Required. The type of the Application Group to be created. Allowed values: RemoteApp or Desktop." + } + }, + "hostpoolName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Host Pool to be linked to this Application Group." + } + }, + "friendlyName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. The friendly name of the Application Group to be created." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Description of the application group." + } + }, + "applications": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of applications to be created in the Application Group." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "builtInRoleNames": { + "Owner": "/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635", + "Contributor": "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c", + "Reader": "/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7", + "Role Based Access Control Administrator (Preview)": "/providers/Microsoft.Authorization/roleDefinitions/f58310d9-a9f6-439a-9e8d-f62e7b41a168", + "User Access Administrator": "/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9", + "Application Group Contributor": "/providers/Microsoft.Authorization/roleDefinitions/ca6382a4-1721-4bcf-a114-ff0c70227b6b", + "Desktop Virtualization Application Group Contributor": "/providers/Microsoft.Authorization/roleDefinitions/86240b0e-9422-4c43-887b-b61143f32ba8", + "Desktop Virtualization Application Group Reader": "/providers/Microsoft.Authorization/roleDefinitions/aebf23d0-b568-4e86-b8f9-fe83a2c6ab55", + "Desktop Virtualization Contributor": "/providers/Microsoft.Authorization/roleDefinitions/082f0a83-3be5-4ba1-904c-961cca79b387", + "Desktop Virtualization Host Pool Contributor": "/providers/Microsoft.Authorization/roleDefinitions/e307426c-f9b6-4e81-87de-d99efb3c32bc", + "Desktop Virtualization Host Pool Reader": "/providers/Microsoft.Authorization/roleDefinitions/ceadfde2-b300-400a-ab7b-6143895aa822", + "Desktop Virtualization Power On Off Contributor": "/providers/Microsoft.Authorization/roleDefinitions/40c5ff49-9181-41f8-ae61-143b0e78555e", + "Desktop Virtualization Reader": "/providers/Microsoft.Authorization/roleDefinitions/49a72310-ab8d-41df-bbb0-79b649203868", + "Desktop Virtualization Session Host Operator": "/providers/Microsoft.Authorization/roleDefinitions/2ad6aaab-ead9-4eaa-8ac5-da422f562408", + "Desktop Virtualization User": "/providers/Microsoft.Authorization/roleDefinitions/1d18fff3-a72a-46b5-b4a9-0b38a3cd7e63", + "Desktop Virtualization User Session Operator": "/providers/Microsoft.Authorization/roleDefinitions/ea4bfff8-7fb4-485a-aadd-d4129a0ffaa6", + "Desktop Virtualization Virtual Machine Contributor": "/providers/Microsoft.Authorization/roleDefinitions/a959dbd1-f747-45e3-8ba6-dd80f235f97c", + "Desktop Virtualization Workspace Contributor": "/providers/Microsoft.Authorization/roleDefinitions/21efdde3-836f-432b-bf3d-3e8e734d4b2b", + "Desktop Virtualization Workspace Reader": "/providers/Microsoft.Authorization/roleDefinitions/0fa44ee9-7a7d-466b-9bb2-2bf446b1204d", + "Managed Application Contributor Role": "/providers/Microsoft.Authorization/roleDefinitions/641177b8-a67a-45b9-a033-47bc880bb21e", + "Managed Application Operator Role": "/providers/Microsoft.Authorization/roleDefinitions/c7393b34-138c-406f-901b-d8cf2b17e6ae", + "Managed Applications Reader": "/providers/Microsoft.Authorization/roleDefinitions/b9331d33-8a36-4f8c-b097-4f54124fdb44" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.desktopvirtualization-appgroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "appGroup_hostpool": { + "existing": true, + "type": "Microsoft.DesktopVirtualization/hostPools", + "apiVersion": "2023-09-05", + "name": "[parameters('hostpoolName')]" + }, + "appGroup": { + "type": "Microsoft.DesktopVirtualization/applicationGroups", + "apiVersion": "2023-09-05", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "hostPoolArmPath": "[resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('hostpoolName'))]", + "friendlyName": "[parameters('friendlyName')]", + "description": "[parameters('description')]", + "applicationGroupType": "[parameters('applicationGroupType')]" + } + }, + "appGroup_roleAssignments": { + "copy": { + "name": "appGroup_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.DesktopVirtualization/applicationGroups/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.DesktopVirtualization/applicationGroups', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "appGroup" + ] + }, + "appGroup_diagnosticSettings": { + "copy": { + "name": "appGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DesktopVirtualization/applicationGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "appGroup" + ] + }, + "appGroup_applications": { + "copy": { + "name": "appGroup_applications", + "count": "[length(parameters('applications'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-AppGroup-App-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('applications')[copyIndex()].name]" + }, + "applicationGroupName": { + "value": "[parameters('name')]" + }, + "description": { + "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'description'), '')]" + }, + "friendlyName": { + "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'friendlyName'), parameters('name'))]" + }, + "filePath": { + "value": "[parameters('applications')[copyIndex()].filePath]" + }, + "commandLineSetting": { + "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'commandLineSetting'), 'DoNotAllow')]" + }, + "commandLineArguments": { + "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'commandLineArguments'), '')]" + }, + "showInPortal": { + "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'showInPortal'), false())]" + }, + "iconPath": { + "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'iconPath'), parameters('applications')[copyIndex()].filePath)]" + }, + "iconIndex": { + "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'iconIndex'), 0)]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "11724144502531514491" + }, + "name": "Azure Virtual Desktop Application Group Application", + "description": "This module deploys an Azure Virtual Desktop Application Group Application.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "applicationGroupName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Group to create the application(s) in. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application to be created in the Application Group." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Description of the Application." + } + }, + "friendlyName": { + "type": "string", + "metadata": { + "description": "Required. Friendly name of the Application." + } + }, + "filePath": { + "type": "string", + "metadata": { + "description": "Required. Specifies a path for the executable file for the Application." + } + }, + "commandLineSetting": { + "type": "string", + "defaultValue": "DoNotAllow", + "allowedValues": [ + "Allow", + "DoNotAllow", + "Require" + ], + "metadata": { + "description": "Optional. Specifies whether this published Application can be launched with command-line arguments provided by the client, command-line arguments specified at publish time, or no command-line arguments at all." + } + }, + "commandLineArguments": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Command-Line Arguments for the Application." + } + }, + "showInPortal": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether to show the RemoteApp program in the RD Web Access server." + } + }, + "iconPath": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Path to icon." + } + }, + "iconIndex": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Index of the icon." + } + } + }, + "resources": [ + { + "type": "Microsoft.DesktopVirtualization/applicationGroups/applications", + "apiVersion": "2023-09-05", + "name": "[format('{0}/{1}', parameters('applicationGroupName'), parameters('name'))]", + "properties": { + "description": "[parameters('description')]", + "friendlyName": "[parameters('friendlyName')]", + "filePath": "[parameters('filePath')]", + "commandLineSetting": "[parameters('commandLineSetting')]", + "commandLineArguments": "[parameters('commandLineArguments')]", + "showInPortal": "[parameters('showInPortal')]", + "iconPath": "[parameters('iconPath')]", + "iconIndex": "[parameters('iconIndex')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Application." + }, + "value": "[resourceId('Microsoft.DesktopVirtualization/applicationGroups/applications', parameters('applicationGroupName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Application was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Application." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "appGroup" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the scaling plan." + }, + "value": "[resourceId('Microsoft.DesktopVirtualization/applicationGroups', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the scaling plan was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the scaling plan." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location of the scaling plan." + }, + "value": "[reference('appGroup', '2023-09-05', 'full').location]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('HostPool-{0}', parameters('time')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Workspace-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('workSpaceName')]" + }, + "friendlyName": { + "value": "[parameters('workSpaceFriendlyName')]" + }, + "location": { + "value": "[parameters('managementPlaneLocation')]" + }, + "applicationGroupReferences": { + "value": [ + "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('{0}-{1}', variables('varApplicationGroups')[0].name, parameters('time'))), '2022-09-01').outputs.resourceId.value]" + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "publicNetworkAccess": "[if(parameters('deployAvdPrivateLinkService'), createObject('value', parameters('workspacePublicNetworkAccess')), createObject('value', null()))]", + "privateEndpoints": "[if(parameters('deployAvdPrivateLinkService'), createObject('value', createArray(createObject('name', parameters('privateEndpointWorkspaceName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'service', 'feed', 'privateDnsZoneResourceIds', createArray(parameters('avdVnetPrivateDnsZoneConnectionResourceId'))), createObject('name', parameters('privateEndpointDiscoveryName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'service', 'global', 'privateDnsZoneResourceIds', createArray(parameters('avdVnetPrivateDnsZoneDiscoveryResourceId'))))), createObject('value', createArray()))]", + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "16965361488789112059" + }, + "name": "Workspace", + "description": "This module deploys an Azure Virtual Desktop Workspace.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"feed\" or \"global\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "applicationGroupReferences": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of application group references." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Description of the workspace." + } + }, + "friendlyName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Friendly name of the workspace." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Optional. Public network access for the workspace. Enabled by default." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[take(format('46d3xbcp.res.desktopvirtualization-workspace.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "workspace": { + "type": "Microsoft.DesktopVirtualization/workspaces", + "apiVersion": "2023-09-05", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "applicationGroupReferences": "[parameters('applicationGroupReferences')]", + "description": "[parameters('description')]", + "friendlyName": "[parameters('friendlyName')]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]" + } + }, + "workspace_diagnosticSettings": { + "copy": { + "name": "workspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DesktopVirtualization/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true())))]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "workspace" + ] + }, + "workspace_privateEndpoints": { + "copy": { + "name": "workspace_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-workspace-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "workspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the workspace." + }, + "value": "[resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the workspace was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the workspace." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location of the workspace." + }, + "value": "[reference('workspace', '2023-09-05', 'full').location]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('{0}-{1}', variables('varApplicationGroups')[0].name, parameters('time')))]" + ] + }, + { + "condition": "[parameters('deployScalingPlan')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Scaling-Plan-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('scalingPlanName')]" + }, + "location": { + "value": "[parameters('managementPlaneLocation')]" + }, + "hostPoolType": { + "value": "[parameters('hostPoolType')]" + }, + "exclusionTag": { + "value": "[parameters('scalingPlanExclusionTag')]" + }, + "timeZone": { + "value": "[parameters('computeTimeZone')]" + }, + "schedules": { + "value": "[parameters('scalingPlanSchedules')]" + }, + "hostPoolReferences": { + "value": [ + { + "hostPoolArmPath": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('HostPool-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]", + "scalingPlanEnabled": true + } + ] + }, + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13077254828568021707" + }, + "name": "Azure Virtual Desktop Scaling Plan", + "description": "This module deploys an Azure Virtual Desktop Scaling Plan.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Scaling Plan." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the Scaling Plan. Defaults to resource group location." + } + }, + "friendlyName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Friendly name of the Scaling Plan." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "UTC", + "metadata": { + "description": "Optional. Time zone of the Scaling Plan. Defaults to UTC." + } + }, + "hostPoolType": { + "type": "string", + "defaultValue": "Pooled", + "allowedValues": [ + "Personal", + "Pooled" + ], + "metadata": { + "description": "Optional. Host pool type of the Scaling Plan." + } + }, + "exclusionTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Exclusion tag to be used for exclusion of VMs from Scaling Plan." + } + }, + "schedules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Schedules of the Scaling Plan." + } + }, + "hostPoolReferences": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Host pool references of the Scaling Plan." + } + }, + "description": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Description of the Scaling Plan." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.desktopvirtualization-scalingplan.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "scalingPlan": { + "type": "Microsoft.DesktopVirtualization/scalingPlans", + "apiVersion": "2023-09-05", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "friendlyName": "[parameters('friendlyName')]", + "timeZone": "[parameters('timeZone')]", + "hostPoolType": "[parameters('hostPoolType')]", + "exclusionTag": "[parameters('exclusionTag')]", + "schedules": [], + "hostPoolReferences": "[parameters('hostPoolReferences')]", + "description": "[parameters('description')]" + } + }, + "scalingPlanSchedulePersonal": { + "copy": { + "name": "scalingPlanSchedulePersonal", + "count": "[length(parameters('schedules'))]" + }, + "condition": "[equals(parameters('hostPoolType'), 'Personal')]", + "type": "Microsoft.DesktopVirtualization/scalingPlans/personalSchedules", + "apiVersion": "2023-09-05", + "name": "[format('{0}/{1}', parameters('name'), format('{0}', parameters('schedules')[copyIndex()].name))]", + "properties": "[parameters('schedules')[copyIndex()]]", + "dependsOn": [ + "scalingPlan" + ] + }, + "scalingPlanSchedulePooled": { + "copy": { + "name": "scalingPlanSchedulePooled", + "count": "[length(parameters('schedules'))]" + }, + "condition": "[equals(parameters('hostPoolType'), 'Pooled')]", + "type": "Microsoft.DesktopVirtualization/scalingPlans/pooledSchedules", + "apiVersion": "2023-09-05", + "name": "[format('{0}/{1}', parameters('name'), format('{0}', parameters('schedules')[copyIndex()].name))]", + "properties": "[parameters('schedules')[copyIndex()]]", + "dependsOn": [ + "scalingPlan" + ] + }, + "scalingPlan_diagnosticSettings": { + "copy": { + "name": "scalingPlan_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DesktopVirtualization/scalingPlans/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "scalingPlan" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Scaling Plan." + }, + "value": "[resourceId('Microsoft.DesktopVirtualization/scalingPlans', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Scaling Plan was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Scaling Plan." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location of the Scaling Plan." + }, + "value": "[reference('scalingPlan', '2023-09-05', 'full').location]" + } + } + } + }, + "dependsOn": [ + "applicationGroups", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('HostPool-{0}', parameters('time')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workspace-{0}', parameters('time')))]" + ] + } + ], + "outputs": { + "hostPoolResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('HostPool-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" + } + } + } + }, + "dependsOn": [ + "baselineResourceGroups", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Identities-And-RoleAssign-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('avdSessionHostLocation')]" + }, + "subscriptionId": { + "value": "[parameters('avdWorkloadSubsId')]" + }, + "computeObjectsRgName": { + "value": "[variables('varComputeObjectsRgName')]" + }, + "createAppAttachRoleAssignments": { + "value": "[and(parameters('createAppAttachDeployment'), equals(parameters('avdIdentityServiceProvider'), 'EntraID'))]" + }, + "serviceObjectsRgName": { + "value": "[variables('varServiceObjectsRgName')]" + }, + "storageObjectsRgName": { + "value": "[variables('varStorageObjectsRgName')]" + }, + "avdServicePrincipalObjectId": { + "value": "[parameters('avdServicePrincipalObjectId')]" + }, + "avdArmServicePrincipalObjectId": { + "value": "[parameters('avdArmServicePrincipalObjectId')]" + }, + "deployScalingPlan": "[if(not(empty(parameters('avdServicePrincipalObjectId'))), createObject('value', variables('varDeployScalingPlan')), createObject('value', false()))]", + "storageManagedIdentityName": { + "value": "[variables('varStorageManagedIdentityName')]" + }, + "enableStartVmOnConnect": { + "value": "[parameters('avdStartVmOnConnect')]" + }, + "identityServiceProvider": { + "value": "[parameters('avdIdentityServiceProvider')]" + }, + "createStorageDeployment": { + "value": "[variables('varCreateStorageDeployment')]" + }, + "securityPrincipalId": { + "value": "[variables('varSecurityPrincipalId')]" + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "16449043338553652850" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy AVD session hosts." + } + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "serviceObjectsRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for the service objects." + } + }, + "computeObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group name for the session hosts." + } + }, + "storageObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name for Azure Files." + } + }, + "avdServicePrincipalObjectId": { + "type": "string", + "metadata": { + "description": "Azure Virtual Desktop service principal object ID." + } + }, + "avdArmServicePrincipalObjectId": { + "type": "string", + "metadata": { + "description": "Azure Virtual Desktop ARM provider service principal object ID." + } + }, + "createAppAttachRoleAssignments": { + "type": "bool", + "metadata": { + "description": "Configure App Attach Role Assignments." + } + }, + "enableStartVmOnConnect": { + "type": "bool", + "metadata": { + "description": "Configure start VM on connect." + } + }, + "identityServiceProvider": { + "type": "string", + "metadata": { + "description": "Required, The service providing domain services for Azure Virtual Desktop." + } + }, + "securityPrincipalId": { + "type": "string", + "metadata": { + "description": "Required, Identity ID to grant RBAC role to access AVD application group." + } + }, + "deployScalingPlan": { + "type": "bool", + "metadata": { + "description": "Deploy scaling plan." + } + }, + "storageManagedIdentityName": { + "type": "string", + "metadata": { + "description": "Storage managed identity name." + } + }, + "createStorageDeployment": { + "type": "bool", + "metadata": { + "description": "Deploy Storage setup." + } + }, + "tags": { + "type": "object", + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + } + }, + "variables": { + "varVirtualMachineUserLoginRole": { + "id": "fb879df8-f326-4884-b1cf-06f3ad86be52", + "name": "Virtual Machine User Login" + }, + "varStorageSmbShareContributorRole": { + "id": "0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb", + "name": "Storage File Data SMB Share Contributor" + }, + "varDesktopVirtualizationPowerOnContributorRole": { + "id": "489581de-a3bd-480d-9518-53dea7416b33", + "name": "Desktop Virtualization Power On Contributor" + }, + "varDesktopVirtualizationPowerOnOffContributorRole": { + "id": "40c5ff49-9181-41f8-ae61-143b0e78555e", + "name": "Desktop Virtualization Power On Off Contributor" + }, + "computeAndServiceObjectsRgs": [ + { + "name": "ServiceObjects", + "rgName": "[parameters('computeObjectsRgName')]" + }, + { + "name": "Compute", + "rgName": "[parameters('serviceObjectsRgName')]" + } + ], + "storageRoleAssignments": [ + { + "name": "Storage Account Contributor", + "acronym": "StoraContri", + "id": "17d1049b-9a84-46fb-8f53-869881c3d3ab" + }, + { + "name": "Reader", + "acronym": "Reader", + "id": "acdd72a7-3385-48ef-bd42-f606fba81ae7" + } + ], + "appAttachEntraIDPrincpals": [ + { + "name": "AVD", + "id": "[parameters('avdServicePrincipalObjectId')]" + }, + { + "name": "AVDARM", + "id": "[parameters('avdArmServicePrincipalObjectId')]" + } + ] + }, + "resources": [ + { + "condition": "[and(parameters('createStorageDeployment'), not(equals(parameters('identityServiceProvider'), 'EntraID')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('MI-Storage-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('storageManagedIdentityName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "11657260805865946801" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2023-01-31', 'full').location]" + } + } + } + } + }, + { + "copy": { + "name": "startVMonConnectRoleAssignCompute", + "count": "[length(variables('computeAndServiceObjectsRgs'))]" + }, + "condition": "[and(and(parameters('enableStartVmOnConnect'), not(parameters('deployScalingPlan'))), not(empty(parameters('avdServicePrincipalObjectId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('StartOnCon-RolAssign-{0}-{1}', variables('computeAndServiceObjectsRgs')[copyIndex()].name, parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', variables('computeAndServiceObjectsRgs')[copyIndex()].rgName)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "roleDefinitionIdOrName": { + "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/{1}', parameters('subscriptionId'), variables('varDesktopVirtualizationPowerOnContributorRole').id)]" + }, + "principalId": { + "value": "[parameters('avdServicePrincipalObjectId')]" + }, + "resourceGroupName": { + "value": "[variables('computeAndServiceObjectsRgs')[copyIndex()].rgName]" + }, + "principalType": { + "value": "ServicePrincipal" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "298383569508499170" + }, + "name": "Role Assignments (Resource Group scope)", + "description": "This module deploys a Role Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + }, + "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", + "properties": { + "roleDefinitionId": "[variables('roleDefinitionIdVar')]", + "principalId": "[parameters('principalId')]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[resourceGroup().id]" + } + } + } + } + }, + { + "copy": { + "name": "scalingPlanRoleAssignCompute", + "count": "[length(variables('computeAndServiceObjectsRgs'))]" + }, + "condition": "[and(parameters('deployScalingPlan'), not(empty(parameters('avdServicePrincipalObjectId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('ScalingPlan-RolAssign-{0}-{1}', variables('computeAndServiceObjectsRgs')[copyIndex()].name, parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', variables('computeAndServiceObjectsRgs')[copyIndex()].rgName)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "roleDefinitionIdOrName": { + "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/{1}', parameters('subscriptionId'), variables('varDesktopVirtualizationPowerOnOffContributorRole').id)]" + }, + "principalId": { + "value": "[parameters('avdServicePrincipalObjectId')]" + }, + "resourceGroupName": { + "value": "[variables('computeAndServiceObjectsRgs')[copyIndex()].rgName]" + }, + "subscriptionId": { + "value": "[parameters('subscriptionId')]" + }, + "principalType": { + "value": "ServicePrincipal" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "298383569508499170" + }, + "name": "Role Assignments (Resource Group scope)", + "description": "This module deploys a Role Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + }, + "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", + "properties": { + "roleDefinitionId": "[variables('roleDefinitionIdVar')]", + "principalId": "[parameters('principalId')]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[resourceGroup().id]" + } + } + } + } + }, + { + "copy": { + "name": "storageContributorRoleAssign", + "count": "[length(variables('storageRoleAssignments'))]" + }, + "condition": "[and(parameters('createStorageDeployment'), not(equals(parameters('identityServiceProvider'), 'EntraID')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Stora-RolAssign-{0}-{1}', variables('storageRoleAssignments')[copyIndex()].acronym, parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "roleDefinitionIdOrName": { + "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/{1}', parameters('subscriptionId'), variables('storageRoleAssignments')[copyIndex()].id)]" + }, + "principalId": "[if(parameters('createStorageDeployment'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('MI-Storage-{0}', parameters('time'))), '2022-09-01').outputs.principalId.value), createObject('value', ''))]", + "resourceGroupName": { + "value": "[parameters('storageObjectsRgName')]" + }, + "subscriptionId": { + "value": "[parameters('subscriptionId')]" + }, + "principalType": { + "value": "ServicePrincipal" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "298383569508499170" + }, + "name": "Role Assignments (Resource Group scope)", + "description": "This module deploys a Role Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + }, + "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", + "properties": { + "roleDefinitionId": "[variables('roleDefinitionIdVar')]", + "principalId": "[parameters('principalId')]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[resourceGroup().id]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('MI-Storage-{0}', parameters('time')))]" + ] + }, + { + "condition": "[and(and(parameters('createStorageDeployment'), not(empty(parameters('securityPrincipalId')))), not(equals(parameters('identityServiceProvider'), 'EntraID')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Stora-SmbContri-RolAssign{0}-{1}', take(format('{0}', parameters('securityPrincipalId')), 6), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "roleDefinitionIdOrName": { + "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/{1}', parameters('subscriptionId'), variables('varStorageSmbShareContributorRole').id)]" + }, + "principalId": "[if(not(empty(parameters('securityPrincipalId'))), createObject('value', parameters('securityPrincipalId')), createObject('value', ''))]", + "resourceGroupName": { + "value": "[parameters('storageObjectsRgName')]" + }, + "subscriptionId": { + "value": "[parameters('subscriptionId')]" + }, + "principalType": { + "value": "Group" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "298383569508499170" + }, + "name": "Role Assignments (Resource Group scope)", + "description": "This module deploys a Role Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + }, + "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", + "properties": { + "roleDefinitionId": "[variables('roleDefinitionIdVar')]", + "principalId": "[parameters('principalId')]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[resourceGroup().id]" + } + } + } + } + }, + { + "copy": { + "name": "storageReaderandDataAccessRoleAssign", + "count": "[length(variables('appAttachEntraIDPrincpals'))]" + }, + "condition": "[parameters('createAppAttachRoleAssignments')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Stora-ReaderData-RolAssign-{0}-{1}', variables('appAttachEntraIDPrincpals')[copyIndex()].name, parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[variables('appAttachEntraIDPrincpals')[copyIndex()].id]" + }, + "roleDefinitionIdOrName": { + "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/c12c1c16-33a1-487b-954d-41c89c60f349', parameters('subscriptionId'))]" + }, + "resourceGroupName": { + "value": "[parameters('storageObjectsRgName')]" + }, + "subscriptionId": { + "value": "[parameters('subscriptionId')]" + }, + "principalType": { + "value": "ServicePrincipal" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "298383569508499170" + }, + "name": "Role Assignments (Resource Group scope)", + "description": "This module deploys a Role Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + }, + "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", + "properties": { + "roleDefinitionId": "[variables('roleDefinitionIdVar')]", + "principalId": "[parameters('principalId')]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[resourceGroup().id]" + } + } + } + } + }, + { + "condition": "[and(contains(parameters('identityServiceProvider'), 'EntraID'), not(empty(parameters('securityPrincipalId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('VM-Login-Comp-{0}-{1}', take(format('{0}', parameters('securityPrincipalId')), 6), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "roleDefinitionIdOrName": { + "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/{1}', parameters('subscriptionId'), variables('varVirtualMachineUserLoginRole').id)]" + }, + "principalId": "[if(not(empty(parameters('securityPrincipalId'))), createObject('value', parameters('securityPrincipalId')), createObject('value', ''))]", + "resourceGroupName": { + "value": "[parameters('computeObjectsRgName')]" + }, + "subscriptionId": { + "value": "[parameters('subscriptionId')]" + }, + "principalType": { + "value": "Group" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "298383569508499170" + }, + "name": "Role Assignments (Resource Group scope)", + "description": "This module deploys a Role Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + }, + "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", + "properties": { + "roleDefinitionId": "[variables('roleDefinitionIdVar')]", + "principalId": "[parameters('principalId')]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[resourceGroup().id]" + } + } + } + } + }, + { + "condition": "[and(contains(parameters('identityServiceProvider'), 'EntraID'), not(empty(parameters('securityPrincipalId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('VM-Login-Serv-{0}-{1}', take(format('{0}', parameters('securityPrincipalId')), 6), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "roleDefinitionIdOrName": { + "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/{1}', parameters('subscriptionId'), variables('varVirtualMachineUserLoginRole').id)]" + }, + "principalId": "[if(not(empty(parameters('securityPrincipalId'))), createObject('value', parameters('securityPrincipalId')), createObject('value', ''))]", + "resourceGroupName": { + "value": "[parameters('serviceObjectsRgName')]" + }, + "subscriptionId": { + "value": "[parameters('subscriptionId')]" + }, + "principalType": { + "value": "Group" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "298383569508499170" + }, + "name": "Role Assignments (Resource Group scope)", + "description": "This module deploys a Role Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + }, + "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", + "properties": { + "roleDefinitionId": "[variables('roleDefinitionIdVar')]", + "principalId": "[parameters('principalId')]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[resourceGroup().id]" + } + } + } + } + } + ], + "outputs": { + "managedIdentityStorageResourceId": { + "type": "string", + "value": "[if(and(parameters('createStorageDeployment'), not(equals(parameters('identityServiceProvider'), 'EntraID'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('MI-Storage-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" + }, + "managedIdentityStorageClientId": { + "type": "string", + "value": "[if(and(parameters('createStorageDeployment'), not(equals(parameters('identityServiceProvider'), 'EntraID'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('MI-Storage-{0}', parameters('time'))), '2022-09-01').outputs.clientId.value, '')]" + } + } + } + }, + "dependsOn": [ + "baselineResourceGroups", + "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]" + ] + }, + { + "condition": "[and(parameters('diskZeroTrust'), parameters('avdDeploySessionHosts'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Zero-Trust-{0}', parameters('time'))]", + "subscriptionId": "[parameters('avdWorkloadSubsId')]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('avdSessionHostLocation')]" + }, + "subscriptionId": { + "value": "[parameters('avdWorkloadSubsId')]" + }, + "diskZeroTrust": { + "value": "[parameters('diskZeroTrust')]" + }, + "serviceObjectsRgName": { + "value": "[variables('varServiceObjectsRgName')]" + }, + "computeObjectsRgName": { + "value": "[variables('varComputeObjectsRgName')]" + }, + "vaultSku": { + "value": "[variables('varWrklKeyVaultSku')]" + }, + "diskEncryptionKeyExpirationInDays": { + "value": "[parameters('diskEncryptionKeyExpirationInDays')]" + }, + "diskEncryptionSetName": { + "value": "[variables('varDiskEncryptionSetName')]" + }, + "ztKvName": { + "value": "[variables('varZtKvName')]" + }, + "ztKvPrivateEndpointName": { + "value": "[variables('varZtKvPrivateEndpointName')]" + }, + "privateEndpointsubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName'))), createObject('value', parameters('existingVnetPrivateEndpointSubnetResourceId')))]", + "deployPrivateEndpointKeyvaultStorage": { + "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" + }, + "keyVaultprivateDNSResourceId": "[if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.keyVaultDnsZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneKeyvaultId')))]", + "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]", + "enableKvPurgeProtection": { + "value": "[parameters('enableKvPurgeProtection')]" + }, + "kvTags": { + "value": "[variables('varZtKeyvaultTag')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "7927730494789166511" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy compute services." + } + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "diskZeroTrust": { + "type": "bool", + "metadata": { + "description": "Enables a zero trust configuration on the session host disks." + } + }, + "serviceObjectsRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for the service objects." + } + }, + "computeObjectsRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for the service objects." + } + }, + "diskEncryptionKeyExpirationInDays": { + "type": "int", + "metadata": { + "description": "This value is used to set the expiration date on the disk encryption key." + } + }, + "deployPrivateEndpointKeyvaultStorage": { + "type": "bool", + "metadata": { + "description": "Deploy private endpoints for key vault and storage." + } + }, + "ztKvPrivateEndpointName": { + "type": "string", + "metadata": { + "description": "Key vault private endpoint name." + } + }, + "privateEndpointsubnetResourceId": { + "type": "string", + "metadata": { + "description": "Private endpoint subnet resource ID" + } + }, + "tags": { + "type": "object", + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "kvTags": { + "type": "object", + "metadata": { + "description": "Tags to be added to key vault" + } + }, + "diskEncryptionSetName": { + "type": "string", + "metadata": { + "description": "Encryption set name" + } + }, + "ztKvName": { + "type": "string", + "metadata": { + "description": "Key vault name" + } + }, + "keyVaultprivateDNSResourceId": { + "type": "string", + "metadata": { + "description": "Private DNS zone for key vault private endpoint" + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + }, + "enableKvPurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable purge protection on the key vault" + } + }, + "vaultSku": { + "type": "string", + "metadata": { + "description": "Specifies the SKU for the vault." + } + } + }, + "variables": { + "$fxv#0": "{\r\n \"name\": \"AVD-ACC-Zero-Trust-Disable-Managed-Disk-Network-Access\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Zero Trust - Disable Managed Disk Network Access\",\r\n \"description\": \"This policy definition sets the network access policy property to \\\"DenyAll\\\" and the public network access property to \\\"Disabled\\\" on all the managed disks within the assigned scope.\",\r\n \"metadata\": {\r\n \"version\": \"1.1.0\",\r\n \"category\": \"Security\"\r\n },\r\n \"parameters\": {\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Compute/disks\"\r\n },\r\n \"then\": {\r\n \"effect\": \"modify\",\r\n \"details\": {\r\n \"roleDefinitionIds\": [\r\n \"/providers/Microsoft.Authorization/roleDefinitions/60fc6e62-5479-42d4-8bf4-67625fcc2840\"\r\n ],\r\n \"operations\": [\r\n {\r\n \"operation\": \"addOrReplace\",\r\n \"field\": \"Microsoft.Compute/disks/networkAccessPolicy\",\r\n \"value\": \"DenyAll\"\r\n },\r\n {\r\n \"operation\": \"addOrReplace\",\r\n \"field\": \"Microsoft.Compute/disks/publicNetworkAccess\",\r\n \"value\": \"Disabled\"\r\n }\r\n ]\r\n }\r\n }\r\n }\r\n }\r\n}", + "varCustomPolicyDefinitions": [ + { + "deploymentName": "ZT-Disk", + "libDefinition": "[json(variables('$fxv#0'))]" + } + ] + }, + "resources": [ + { + "copy": { + "name": "ztPolicyDefinitions", + "count": "[length(variables('varCustomPolicyDefinitions'))]" + }, + "condition": "[parameters('diskZeroTrust')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "description": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.description]" + }, + "displayName": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.displayName]" + }, + "name": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.name]" + }, + "metadata": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.metadata]" + }, + "mode": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.mode]" + }, + "parameters": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.parameters]" + }, + "policyRule": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.policyRule]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "15296566503434303805" + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. Specifies the name of the policy definition. Maximum length is 64 characters." + } + }, + "displayName": { + "type": "string", + "defaultValue": "", + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy definition. Maximum length is 128 characters." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The policy definition description." + } + }, + "mode": { + "type": "string", + "defaultValue": "All", + "allowedValues": [ + "All", + "Indexed", + "Microsoft.KeyVault.Data", + "Microsoft.ContainerService.Data", + "Microsoft.Kubernetes.Data", + "Microsoft.Network.Data" + ], + "metadata": { + "description": "Optional. The policy definition mode. Default is All, Some examples are All, Indexed, Microsoft.KeyVault.Data." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy Definition metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy definition parameters that can be used in policy definition references." + } + }, + "policyRule": { + "type": "object", + "metadata": { + "description": "Required. The Policy Rule details for the Policy Definition." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyDefinitions", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "properties": { + "policyType": "Custom", + "mode": "[parameters('mode')]", + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "parameters": "[if(not(empty(parameters('parameters'))), parameters('parameters'), null())]", + "policyRule": "[parameters('policyRule')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy Definition Name." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Definition resource ID." + }, + "value": "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name'))]" + }, + "roleDefinitionIds": { + "type": "array", + "metadata": { + "description": "Policy Definition Role Definition IDs." + }, + "value": "[if(contains(reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then, 'details'), if(contains(reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then.details, 'roleDefinitionIds'), reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then.details.roleDefinitionIds, createArray()), createArray())]" + } + } + } + } + }, + { + "copy": { + "name": "ztPolicyAssignmentServiceObjects", + "count": "[length(variables('varCustomPolicyDefinitions'))]" + }, + "condition": "[parameters('diskZeroTrust')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Pol-Assign-ServObj{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.name]" + }, + "displayName": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.displayName]" + }, + "description": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.description]" + }, + "identity": { + "value": "SystemAssigned" + }, + "location": { + "value": "[parameters('location')]" + }, + "policyDefinitionId": "[if(parameters('diskZeroTrust'), createObject('value', reference(subscriptionResourceId(format('{0}', parameters('subscriptionId')), 'Microsoft.Resources/deployments', format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', ''))]", + "resourceSelectors": { + "value": [ + { + "name": "VirtualMachineDisks", + "selectors": [ + { + "in": [ + "Microsoft.Compute/disks" + ], + "kind": "resourceType" + } + ] + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "10386382608825992636" + }, + "name": "Policy Assignments (Resource Group scope)", + "description": "This module deploys a Policy Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 64 characters for resource group scope." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. This message will be part of response in case of policy violation." + } + }, + "displayName": { + "type": "string", + "defaultValue": "", + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy assignment. Maximum length is 128 characters." + } + }, + "policyDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the ID of the policy definition or policy set definition being assigned." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Parameters for the policy assignment if needed." + } + }, + "identity": { + "type": "string", + "defaultValue": "SystemAssigned", + "allowedValues": [ + "SystemAssigned", + "UserAssigned", + "None" + ], + "metadata": { + "description": "Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions." + } + }, + "userAssignedIdentityId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource ID for the user assigned identity to assign to the policy assignment." + } + }, + "roleDefinitionIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "nonComplianceMessages": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The messages that describe why a resource is non-compliant with the policy." + } + }, + "enforcementMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "DoNotEnforce" + ], + "metadata": { + "description": "Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce." + } + }, + "notScopes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy excluded scopes." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "overrides": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition." + } + }, + "resourceSelectors": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The name of the resource group for the policy assignment. If not provided, will use the current scope for deployment." + } + } + }, + "variables": { + "identityVar": "[if(equals(parameters('identity'), 'SystemAssigned'), createObject('type', parameters('identity')), if(equals(parameters('identity'), 'UserAssigned'), createObject('type', parameters('identity'), 'userAssignedIdentities', createObject(format('{0}', parameters('userAssignedIdentityId')), createObject())), null()))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2022-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "policyDefinitionId": "[parameters('policyDefinitionId')]", + "parameters": "[parameters('parameters')]", + "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), parameters('nonComplianceMessages'), createArray())]", + "enforcementMode": "[parameters('enforcementMode')]", + "notScopes": "[if(not(empty(parameters('notScopes'))), parameters('notScopes'), createArray())]", + "overrides": "[if(not(empty(parameters('overrides'))), parameters('overrides'), createArray())]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), createArray())]" + }, + "identity": "[variables('identityVar')]" + }, + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('roleDefinitionIds'))]" + }, + "condition": "[and(not(empty(parameters('roleDefinitionIds'))), equals(parameters('identity'), 'SystemAssigned'))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), parameters('roleDefinitionIds')[copyIndex()], parameters('location'), parameters('name'))]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionIds')[copyIndex()]]", + "principalId": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy Assignment Name." + }, + "value": "[parameters('name')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Policy Assignment principal ID." + }, + "value": "[coalesce(tryGet(tryGet(reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Assignment resource ID." + }, + "value": "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the policy was assigned to." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "ztPolicyDefinitions" + ] + }, + { + "copy": { + "name": "ztPolicyServBojRemediationTask", + "count": "[length(variables('varCustomPolicyDefinitions'))]" + }, + "condition": "[parameters('diskZeroTrust')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Remm-ServObj-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, copyIndex())]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, copyIndex())]" + }, + "policyAssignmentId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Pol-Assign-ServObj{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.resourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "8141314117626850328" + }, + "name": "Policy Insights Remediations (Resource Group scope)", + "description": "This module deploys a Policy Insights Remediation on a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specifies the name of the policy remediation." + } + }, + "failureThresholdPercentage": { + "type": "string", + "defaultValue": "1", + "metadata": { + "description": "Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail." + } + }, + "filtersLocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The filters that will be applied to determine which resources to remediate." + } + }, + "parallelDeployments": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "maxValue": 30, + "metadata": { + "description": "Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used." + } + }, + "resourceCount": { + "type": "int", + "defaultValue": 500, + "minValue": 1, + "maxValue": 50000, + "metadata": { + "description": "Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used." + } + }, + "resourceDiscoveryMode": { + "type": "string", + "defaultValue": "ExistingNonCompliant", + "allowedValues": [ + "ExistingNonCompliant", + "ReEvaluateCompliance" + ], + "metadata": { + "description": "Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified." + } + }, + "policyAssignmentId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the policy assignment that should be remediated." + } + }, + "policyDefinitionReferenceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location deployment metadata." + } + } + }, + "resources": [ + { + "type": "Microsoft.PolicyInsights/remediations", + "apiVersion": "2021-10-01", + "name": "[parameters('name')]", + "properties": { + "failureThreshold": { + "percentage": "[json(parameters('failureThresholdPercentage'))]" + }, + "filters": { + "locations": "[parameters('filtersLocations')]" + }, + "parallelDeployments": "[parameters('parallelDeployments')]", + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceId": "[parameters('policyDefinitionReferenceId')]", + "resourceCount": "[parameters('resourceCount')]", + "resourceDiscoveryMode": "[parameters('resourceDiscoveryMode')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the remediation." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the remediation." + }, + "value": "[resourceId('Microsoft.PolicyInsights/remediations', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed remediation." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[parameters('location')]" + } + } + } + }, + "dependsOn": [ + "ztPolicyAssignmentServiceObjects" + ] + }, + { + "copy": { + "name": "ztPolicyAssignmentCompute", + "count": "[length(variables('varCustomPolicyDefinitions'))]" + }, + "condition": "[parameters('diskZeroTrust')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Pol-Assign-Comp-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.name]" + }, + "displayName": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.displayName]" + }, + "description": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.description]" + }, + "identity": { + "value": "SystemAssigned" + }, + "location": { + "value": "[parameters('location')]" + }, + "policyDefinitionId": "[if(parameters('diskZeroTrust'), createObject('value', reference(subscriptionResourceId(format('{0}', parameters('subscriptionId')), 'Microsoft.Resources/deployments', format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', ''))]", + "resourceSelectors": { + "value": [ + { + "name": "VirtualMachineDisks", + "selectors": [ + { + "in": [ + "Microsoft.Compute/disks" + ], + "kind": "resourceType" + } + ] + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "10386382608825992636" + }, + "name": "Policy Assignments (Resource Group scope)", + "description": "This module deploys a Policy Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 64 characters for resource group scope." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. This message will be part of response in case of policy violation." + } + }, + "displayName": { + "type": "string", + "defaultValue": "", + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy assignment. Maximum length is 128 characters." + } + }, + "policyDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the ID of the policy definition or policy set definition being assigned." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Parameters for the policy assignment if needed." + } + }, + "identity": { + "type": "string", + "defaultValue": "SystemAssigned", + "allowedValues": [ + "SystemAssigned", + "UserAssigned", + "None" + ], + "metadata": { + "description": "Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions." + } + }, + "userAssignedIdentityId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource ID for the user assigned identity to assign to the policy assignment." + } + }, + "roleDefinitionIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "nonComplianceMessages": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The messages that describe why a resource is non-compliant with the policy." + } + }, + "enforcementMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "DoNotEnforce" + ], + "metadata": { + "description": "Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce." + } + }, + "notScopes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy excluded scopes." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "overrides": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition." + } + }, + "resourceSelectors": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The name of the resource group for the policy assignment. If not provided, will use the current scope for deployment." + } + } + }, + "variables": { + "identityVar": "[if(equals(parameters('identity'), 'SystemAssigned'), createObject('type', parameters('identity')), if(equals(parameters('identity'), 'UserAssigned'), createObject('type', parameters('identity'), 'userAssignedIdentities', createObject(format('{0}', parameters('userAssignedIdentityId')), createObject())), null()))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2022-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "policyDefinitionId": "[parameters('policyDefinitionId')]", + "parameters": "[parameters('parameters')]", + "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), parameters('nonComplianceMessages'), createArray())]", + "enforcementMode": "[parameters('enforcementMode')]", + "notScopes": "[if(not(empty(parameters('notScopes'))), parameters('notScopes'), createArray())]", + "overrides": "[if(not(empty(parameters('overrides'))), parameters('overrides'), createArray())]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), createArray())]" + }, + "identity": "[variables('identityVar')]" + }, + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('roleDefinitionIds'))]" + }, + "condition": "[and(not(empty(parameters('roleDefinitionIds'))), equals(parameters('identity'), 'SystemAssigned'))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), parameters('roleDefinitionIds')[copyIndex()], parameters('location'), parameters('name'))]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionIds')[copyIndex()]]", + "principalId": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy Assignment Name." + }, + "value": "[parameters('name')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Policy Assignment principal ID." + }, + "value": "[coalesce(tryGet(tryGet(reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Assignment resource ID." + }, + "value": "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the policy was assigned to." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "ztPolicyDefinitions", + "ztPolicyServBojRemediationTask" + ] + }, + { + "copy": { + "name": "ztPolicyComputeRemediationTask", + "count": "[length(variables('varCustomPolicyDefinitions'))]" + }, + "condition": "[parameters('diskZeroTrust')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Remm-Comp-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, copyIndex())]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, copyIndex())]" + }, + "policyAssignmentId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('computeObjectsRgName'))), 'Microsoft.Resources/deployments', format('Pol-Assign-Comp-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.resourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "8141314117626850328" + }, + "name": "Policy Insights Remediations (Resource Group scope)", + "description": "This module deploys a Policy Insights Remediation on a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specifies the name of the policy remediation." + } + }, + "failureThresholdPercentage": { + "type": "string", + "defaultValue": "1", + "metadata": { + "description": "Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail." + } + }, + "filtersLocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The filters that will be applied to determine which resources to remediate." + } + }, + "parallelDeployments": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "maxValue": 30, + "metadata": { + "description": "Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used." + } + }, + "resourceCount": { + "type": "int", + "defaultValue": 500, + "minValue": 1, + "maxValue": 50000, + "metadata": { + "description": "Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used." + } + }, + "resourceDiscoveryMode": { + "type": "string", + "defaultValue": "ExistingNonCompliant", + "allowedValues": [ + "ExistingNonCompliant", + "ReEvaluateCompliance" + ], + "metadata": { + "description": "Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified." + } + }, + "policyAssignmentId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the policy assignment that should be remediated." + } + }, + "policyDefinitionReferenceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location deployment metadata." + } + } + }, + "resources": [ + { + "type": "Microsoft.PolicyInsights/remediations", + "apiVersion": "2021-10-01", + "name": "[parameters('name')]", + "properties": { + "failureThreshold": { + "percentage": "[json(parameters('failureThresholdPercentage'))]" + }, + "filters": { + "locations": "[parameters('filtersLocations')]" + }, + "parallelDeployments": "[parameters('parallelDeployments')]", + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceId": "[parameters('policyDefinitionReferenceId')]", + "resourceCount": "[parameters('resourceCount')]", + "resourceDiscoveryMode": "[parameters('resourceDiscoveryMode')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the remediation." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the remediation." + }, + "value": "[resourceId('Microsoft.PolicyInsights/remediations', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed remediation." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[parameters('location')]" + } + } + } + }, + "dependsOn": [ + "ztPolicyAssignmentCompute" + ] + }, + { + "copy": { + "name": "ztRoleAssignmentCompute", + "count": "[length(variables('varCustomPolicyDefinitions'))]" + }, + "condition": "[parameters('diskZeroTrust')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('ZT-RA-Comp-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": "[if(parameters('diskZeroTrust'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('computeObjectsRgName'))), 'Microsoft.Resources/deployments', format('Pol-Assign-Comp-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.principalId.value), createObject('value', ''))]", + "roleDefinitionIdOrName": { + "value": "/providers/Microsoft.Authorization/roleDefinitions/60fc6e62-5479-42d4-8bf4-67625fcc2840" + }, + "principalType": { + "value": "ServicePrincipal" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "298383569508499170" + }, + "name": "Role Assignments (Resource Group scope)", + "description": "This module deploys a Role Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + }, + "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", + "properties": { + "roleDefinitionId": "[variables('roleDefinitionIdVar')]", + "principalId": "[parameters('principalId')]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[resourceGroup().id]" + } + } + } + }, + "dependsOn": [ + "ztPolicyAssignmentCompute", + "ztPolicyComputeRemediationTask" + ] + }, + { + "copy": { + "name": "ztRoleAssignmentServObj", + "count": "[length(variables('varCustomPolicyDefinitions'))]" + }, + "condition": "[parameters('diskZeroTrust')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('ZT-RA-ServObj-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": "[if(parameters('diskZeroTrust'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Pol-Assign-ServObj{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.principalId.value), createObject('value', ''))]", + "roleDefinitionIdOrName": { + "value": "/providers/Microsoft.Authorization/roleDefinitions/60fc6e62-5479-42d4-8bf4-67625fcc2840" + }, + "principalType": { + "value": "ServicePrincipal" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "298383569508499170" + }, + "name": "Role Assignments (Resource Group scope)", + "description": "This module deploys a Role Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + }, + "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", + "properties": { + "roleDefinitionId": "[variables('roleDefinitionIdVar')]", + "principalId": "[parameters('principalId')]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[resourceGroup().id]" + } + } + } + }, + "dependsOn": [ + "ztPolicyAssignmentServiceObjects", + "ztPolicyServBojRemediationTask" + ] + }, + { + "condition": "[parameters('diskZeroTrust')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('ZT-RA-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": "[if(parameters('diskZeroTrust'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('ZT-Key-Vault-{0}', parameters('time'))), '2022-09-01').outputs.ztDiskEncryptionSetPrincipalId.value), createObject('value', ''))]", + "roleDefinitionIdOrName": { + "value": "/providers/Microsoft.Authorization/roleDefinitions/e147488a-f6f5-4113-8e2d-b22465e65bf6" + }, + "principalType": { + "value": "" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "298383569508499170" + }, + "name": "Role Assignments (Resource Group scope)", + "description": "This module deploys a Role Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. ID of the delegated managed identity resource." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." + } + }, + "conditionVersion": { + "type": "string", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + }, + "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", + "properties": { + "roleDefinitionId": "[variables('roleDefinitionIdVar')]", + "principalId": "[parameters('principalId')]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", + "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + }, + "scope": { + "type": "string", + "metadata": { + "description": "The scope this Role Assignment applies to." + }, + "value": "[resourceGroup().id]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('ZT-Key-Vault-{0}', parameters('time')))]" + ] + }, + { + "condition": "[parameters('diskZeroTrust')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('ZT-Key-Vault-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "subscriptionId": { + "value": "[parameters('subscriptionId')]" + }, + "rgName": { + "value": "[parameters('serviceObjectsRgName')]" + }, + "kvName": { + "value": "[parameters('ztKvName')]" + }, + "vaultSku": { + "value": "[parameters('vaultSku')]" + }, + "deployPrivateEndpointKeyvaultStorage": { + "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" + }, + "ztKvPrivateEndpointName": { + "value": "[parameters('ztKvPrivateEndpointName')]" + }, + "privateEndpointsubnetResourceId": { + "value": "[parameters('privateEndpointsubnetResourceId')]" + }, + "keyVaultprivateDNSResourceId": { + "value": "[parameters('keyVaultprivateDNSResourceId')]" + }, + "diskEncryptionKeyExpirationInDays": { + "value": "[parameters('diskEncryptionKeyExpirationInDays')]" + }, + "diskEncryptionSetName": { + "value": "[parameters('diskEncryptionSetName')]" + }, + "tags": { + "value": "[union(parameters('tags'), parameters('kvTags'))]" + }, + "enableKvPurgeProtection": { + "value": "[parameters('enableKvPurgeProtection')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "7847524294349175140" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy compute services." + } + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "rgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for the service objects." + } + }, + "deployPrivateEndpointKeyvaultStorage": { + "type": "bool", + "metadata": { + "description": "Deploy private endpoints for key vault and storage." + } + }, + "kvName": { + "type": "string", + "metadata": { + "description": "Key vault name" + } + }, + "privateEndpointsubnetResourceId": { + "type": "string", + "metadata": { + "description": "Private endpoint subnet resource ID" + } + }, + "ztKvPrivateEndpointName": { + "type": "string", + "metadata": { + "description": "Key vault private endpoint name." + } + }, + "keyVaultprivateDNSResourceId": { + "type": "string", + "metadata": { + "description": "Private DNS zone for key vault private endpoint" + } + }, + "diskEncryptionKeyExpirationInDays": { + "type": "int", + "metadata": { + "description": "This value is used to set the expiration date on the disk encryption key." + } + }, + "diskEncryptionSetName": { + "type": "string", + "metadata": { + "description": "Encryption set name" + } + }, + "tags": { + "type": "object", + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + }, + "vaultSku": { + "type": "string", + "metadata": { + "description": "Specifies the SKU for the vault." + } + }, + "enableKvPurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enable purge protection on the key vault" + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('ZT-KeyVault-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('rgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('kvName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableRbacAuthorization": { + "value": true + }, + "enablePurgeProtection": { + "value": "[parameters('enableKvPurgeProtection')]" + }, + "softDeleteRetentionInDays": { + "value": 7 + }, + "sku": { + "value": "[parameters('vaultSku')]" + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "Deny", + "virtualNetworkRules": [], + "ipRules": [] + } + }, + "privateEndpoints": "[if(parameters('deployPrivateEndpointKeyvaultStorage'), createObject('value', createArray(createObject('name', parameters('ztKvPrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointsubnetResourceId'), 'customNetworkInterfaceName', format('nic-01-{0}', parameters('ztKvPrivateEndpointName')), 'service', 'vault', 'privateDnsZoneGroup', createObject('privateDNSResourceIds', createArray(parameters('keyVaultprivateDNSResourceId')))))), createObject('value', createArray()))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "14297043571004129093" + }, + "name": "Key Vaults", + "description": "This module deploys a Key Vault.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "accessPoliciesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + }, + "metadata": { + "description": "Required. Permissions the identity has for keys, secrets and certificates." + } + } + } + }, + "nullable": true + }, + "secretsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributes": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Defines whether the secret is enabled or disabled." + } + }, + "exp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Defines when the secret will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." + } + }, + "nbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. If set, defines the date from which onwards the secret becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Contains attributes of the secret." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + } + }, + "nullable": true + }, + "keysType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributes": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Defines whether the key is enabled or disabled." + } + }, + "exp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Defines when the key will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." + } + }, + "nbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. If set, defines the date from which onwards the key becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Contains attributes of the key." + } + }, + "curveName": { + "type": "string", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "nullable": true, + "metadata": { + "description": "Optional. The elliptic curve name. Only works if \"keySize\" equals \"EC\" or \"EC-HSM\". Default is \"P-256\"." + } + }, + "keyOps": { + "type": "array", + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "release", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. The allowed operations on this key." + } + }, + "keySize": { + "type": "int", + "allowedValues": [ + 2048, + 3072, + 4096 + ], + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. Only works if \"keySize\" equals \"RSA\" or \"RSA-HSM\". Default is \"4096\"." + } + }, + "kty": { + "type": "string", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the key. Default is \"EC\"." + } + }, + "releasePolicy": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Content type and version of key release policy." + } + }, + "data": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Blob encoding the policy rules under which the key can be released." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "rotationPolicy": { + "$ref": "#/definitions/rotationPoliciesType", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + } + }, + "nullable": true + }, + "rotationPoliciesType": { + "type": "object", + "properties": { + "attributes": { + "type": "object", + "properties": { + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiration time for the new key version. It should be in ISO8601 format. Eg: \"P90D\", \"P1Y\"." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The attributes of key rotation policy." + } + }, + "lifetimeActions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "action": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "Notify", + "Rotate" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of action." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The action of key rotation policy lifetimeAction." + } + }, + "trigger": { + "type": "object", + "properties": { + "timeAfterCreate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time duration after key creation to rotate the key. It only applies to rotate. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." + } + }, + "timeBeforeExpiry": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time duration before key expiring to rotate or notify. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The trigger of key rotation policy lifetimeAction." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The lifetimeActions for key rotation action." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Key Vault. Must be globally unique." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "accessPolicies": { + "$ref": "#/definitions/accessPoliciesType", + "metadata": { + "description": "Optional. All access policies to create." + } + }, + "secrets": { + "$ref": "#/definitions/secretsType", + "nullable": true, + "metadata": { + "description": "Optional. All secrets to create." + } + }, + "keys": { + "$ref": "#/definitions/keysType", + "nullable": true, + "metadata": { + "description": "Optional. All keys to create." + } + }, + "enableVaultForDeployment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for deployment by script or compute." + } + }, + "enableVaultForTemplateDeployment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for a template deployment." + } + }, + "enableVaultForDiskEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the azure platform has access to the vault for enabling disk encryption scenarios." + } + }, + "enableSoftDelete": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Switch to enable/disable Key Vault's soft delete feature." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 90, + "metadata": { + "description": "Optional. softDelete data retention days. It accepts >=7 and <=90." + } + }, + "enableRbacAuthorization": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC." + } + }, + "createMode": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The vault's create mode to indicate whether the vault need to be recovered or not. - recover or default." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Provide 'true' to enable Key Vault's purge protection feature." + } + }, + "sku": { + "type": "string", + "defaultValue": "premium", + "allowedValues": [ + "premium", + "standard" + ], + "metadata": { + "description": "Optional. Specifies the SKU for the vault." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Rules governing the accessibility of the resource from specific network locations." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedAccessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Certificates Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a4417e6f-fecd-4de8-b567-7b0420556985')]", + "Key Vault Certificate User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db79e9a7-68ee-4b58-9aeb-b90e7c24fcba')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.keyvault-vault.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "keyVault": { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "enabledForDeployment": "[parameters('enableVaultForDeployment')]", + "enabledForTemplateDeployment": "[parameters('enableVaultForTemplateDeployment')]", + "enabledForDiskEncryption": "[parameters('enableVaultForDiskEncryption')]", + "enableSoftDelete": "[parameters('enableSoftDelete')]", + "softDeleteRetentionInDays": "[parameters('softDeleteRetentionInDays')]", + "enableRbacAuthorization": "[parameters('enableRbacAuthorization')]", + "createMode": "[parameters('createMode')]", + "enablePurgeProtection": "[if(parameters('enablePurgeProtection'), parameters('enablePurgeProtection'), null())]", + "tenantId": "[subscription().tenantId]", + "accessPolicies": "[variables('formattedAccessPolicies')]", + "sku": { + "name": "[parameters('sku')]", + "family": "A" + }, + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(coalesce(parameters('privateEndpoints'), createArray()))), empty(coalesce(parameters('networkAcls'), createObject()))), 'Disabled', null()))]" + } + }, + "keyVault_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_diagnosticSettings": { + "copy": { + "name": "keyVault_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_roleAssignments": { + "copy": { + "name": "keyVault_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.KeyVault/vaults', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_accessPolicies": { + "condition": "[not(empty(parameters('accessPolicies')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-AccessPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('name')]" + }, + "accessPolicies": { + "value": "[parameters('accessPolicies')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "17696169708082133914" + }, + "name": "Key Vault Access Policies", + "description": "This module deploys a Key Vault Access Policy.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "accessPoliciesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + }, + "metadata": { + "description": "Required. Permissions the identity has for keys, secrets and certificates." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "accessPolicies": { + "$ref": "#/definitions/accessPoliciesType", + "metadata": { + "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedAccessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ] + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "policies": { + "type": "Microsoft.KeyVault/vaults/accessPolicies", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", + "properties": { + "accessPolicies": "[variables('formattedAccessPolicies')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the access policies assignment was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the access policies assignment." + }, + "value": "add" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the access policies assignment." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', parameters('keyVaultName'), 'add')]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_secrets": { + "copy": { + "name": "keyVault_secrets", + "count": "[length(coalesce(parameters('secrets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-Secret-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].value]" + }, + "keyVaultName": { + "value": "[parameters('name')]" + }, + "attributesEnabled": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributesEnabled')]" + }, + "attributesExp": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributesExp')]" + }, + "attributesNbf": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributesNbf')]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12190317675030946449" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "contentType": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secret": { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "contentType": "[parameters('contentType')]", + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "value": "[parameters('value')]" + } + }, + "secret_roleAssignments": { + "copy": { + "name": "secret_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "secret" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the secret." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the secret." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the secret was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_keys": { + "copy": { + "name": "keyVault_keys", + "count": "[length(coalesce(parameters('keys'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-Key-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('keys'), createArray())[copyIndex()].name]" + }, + "keyVaultName": { + "value": "[parameters('name')]" + }, + "attributesEnabled": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesEnabled')]" + }, + "attributesExp": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesExp')]" + }, + "attributesNbf": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesNbf')]" + }, + "curveName": "[if(and(not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA')), not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM'))), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'curveName'), 'P-256')), createObject('value', null()))]", + "keyOps": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keyOps')]" + }, + "keySize": "[if(or(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA'), equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM')), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keySize'), 4096)), createObject('value', null()))]", + "releasePolicy": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'releasePolicy'), createObject())]" + }, + "kty": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'EC')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "rotationPolicy": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'rotationPolicy')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "1370782359529624908" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "curveName": { + "type": "string", + "defaultValue": "P-256", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "metadata": { + "description": "Optional. The elliptic curve name." + } + }, + "keyOps": { + "type": "array", + "nullable": true, + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "metadata": { + "description": "Optional. Array of JsonWebKeyOperation." + } + }, + "keySize": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." + } + }, + "kty": { + "type": "string", + "defaultValue": "EC", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "metadata": { + "description": "Optional. The type of the key." + } + }, + "releasePolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "rotationPolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy properties object." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "key": { + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "curveName": "[parameters('curveName')]", + "keyOps": "[parameters('keyOps')]", + "keySize": "[parameters('keySize')]", + "kty": "[parameters('kty')]", + "rotationPolicy": "[coalesce(parameters('rotationPolicy'), createObject())]", + "release_policy": "[coalesce(parameters('releasePolicy'), createObject())]" + } + }, + "key_roleAssignments": { + "copy": { + "name": "key_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "key" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the key was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_privateEndpoints": { + "copy": { + "name": "keyVault_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyVault-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key vault." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the key vault was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the key vault." + }, + "value": "[parameters('name')]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The URI of the key vault." + }, + "value": "[reference('keyVault').vaultUri]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('keyVault', '2022-07-01', 'full').location]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('ZT-KeyVaultKey-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('rgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "attributesEnabled": { + "value": true + }, + "keySize": { + "value": 4096 + }, + "keyVaultName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-KeyVault-{0}', parameters('time'))), '2022-09-01').outputs.name.value]" + }, + "kty": { + "value": "RSA" + }, + "name": { + "value": "DiskEncryptionKey" + }, + "rotationPolicy": { + "value": { + "attributes": { + "expiryTime": "[format('P{0}D', string(parameters('diskEncryptionKeyExpirationInDays')))]" + }, + "lifetimeActions": [ + { + "action": { + "type": "notify" + }, + "trigger": { + "timeBeforeExpiry": "P10D" + } + }, + { + "action": { + "type": "rotate" + }, + "trigger": { + "timeAfterCreate": "[format('P{0}D', string(sub(parameters('diskEncryptionKeyExpirationInDays'), 7)))]" + } + } + ] + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "1370782359529624908" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "curveName": { + "type": "string", + "defaultValue": "P-256", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "metadata": { + "description": "Optional. The elliptic curve name." + } + }, + "keyOps": { + "type": "array", + "nullable": true, + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "metadata": { + "description": "Optional. Array of JsonWebKeyOperation." + } + }, + "keySize": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." + } + }, + "kty": { + "type": "string", + "defaultValue": "EC", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "metadata": { + "description": "Optional. The type of the key." + } + }, + "releasePolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "rotationPolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy properties object." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "key": { + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "curveName": "[parameters('curveName')]", + "keyOps": "[parameters('keyOps')]", + "keySize": "[parameters('keySize')]", + "kty": "[parameters('kty')]", + "rotationPolicy": "[coalesce(parameters('rotationPolicy'), createObject())]", + "release_policy": "[coalesce(parameters('releasePolicy'), createObject())]" + } + }, + "key_roleAssignments": { + "copy": { + "name": "key_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "key" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the key was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-KeyVault-{0}', parameters('time')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('ZT-DiskEncryptionSet-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('rgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-KeyVaultKey-{0}', parameters('time'))), '2022-09-01').outputs.name.value]" + }, + "keyVaultResourceId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-KeyVault-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" + }, + "location": { + "value": "[parameters('location')]" + }, + "name": { + "value": "[parameters('diskEncryptionSetName')]" + }, + "rotationToLatestKeyVersionEnabled": { + "value": true + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "15993472351338005036" + }, + "name": "Disk Encryption Sets", + "description": "This module deploys a Disk Encryption Set. The module will attempt to set permissions on the provided Key Vault for any used user-assigned identity.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the disk encryption set that is being created." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Resource location." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the KeyVault containing the key or secret." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. Key URL (with version) pointing to a key or secret in KeyVault." + } + }, + "keyVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the latest key version is used." + } + }, + "encryptionType": { + "type": "string", + "defaultValue": "EncryptionAtRestWithPlatformAndCustomerKeys", + "allowedValues": [ + "EncryptionAtRestWithCustomerKey", + "EncryptionAtRestWithPlatformAndCustomerKeys" + ], + "metadata": { + "description": "Optional. The type of key used to encrypt the data of the disk. For security reasons, it is recommended to set encryptionType to EncryptionAtRestWithPlatformAndCustomerKeys." + } + }, + "federatedClientId": { + "type": "string", + "defaultValue": "None", + "metadata": { + "description": "Optional. Multi-tenant application client ID to access key vault in a different tenant. Setting the value to \"None\" will clear the property." + } + }, + "rotationToLatestKeyVersionEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Set this flag to true to enable auto-updating of this disk encryption set to the latest key version." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "defaultValue": { + "systemAssigned": true + }, + "metadata": { + "description": "Optional. The managed identity definition for this resource. At least one identity type is required." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the disk encryption resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", + "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", + "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", + "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", + "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "keyVault::key": { + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2021-10-01", + "subscriptionId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(parameters('keyVaultResourceId'), '/')), parameters('keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.compute-diskencryptionset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-10-01", + "subscriptionId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "name": "[last(split(parameters('keyVaultResourceId'), '/'))]" + }, + "diskEncryptionSet": { + "type": "Microsoft.Compute/diskEncryptionSets", + "apiVersion": "2023-10-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "activeKey": { + "sourceVault": { + "id": "[parameters('keyVaultResourceId')]" + }, + "keyUrl": "[if(not(empty(parameters('keyVersion'))), format('{0}/{1}', reference('keyVault::key').keyUri, parameters('keyVersion')), reference('keyVault::key').keyUriWithVersion)]" + }, + "encryptionType": "[parameters('encryptionType')]", + "federatedClientId": "[parameters('federatedClientId')]", + "rotationToLatestKeyVersionEnabled": "[parameters('rotationToLatestKeyVersionEnabled')]" + }, + "dependsOn": [ + "keyVault::key", + "keyVaultPermissions" + ] + }, + "keyVaultPermissions": { + "copy": { + "name": "keyVaultPermissions", + "count": "[length(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-DiskEncrSet-KVPermissions-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyName": { + "value": "[parameters('keyName')]" + }, + "keyVaultResourceId": { + "value": "[parameters('keyVaultResourceId')]" + }, + "userAssignedIdentityResourceId": { + "value": "[coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray())[copyIndex()]]" + }, + "rbacAuthorizationEnabled": { + "value": "[reference('keyVault').enableRbacAuthorization]" + }, + "location": { + "value": "[parameters('location')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12732011659166716786" + } + }, + "parameters": { + "rbacAuthorizationEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Required. A boolean to specify whether or not the used Key Vault has RBAC authentication enabled or not." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resourceID of the User Assigned Identity to assign permissions to." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Resource location." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the KeyVault containing the key or secret." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. Name of the key to set the permissions for." + } + } + }, + "resources": [ + { + "condition": "[equals(parameters('rbacAuthorizationEnabled'), true())]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', last(split(parameters('keyVaultResourceId'), '/')), parameters('keyName'))]", + "name": "[guid(format('msi-{0}-{1}-{2}-Key-Reader-RoleAssignment', resourceId('Microsoft.KeyVault/vaults/keys', last(split(parameters('keyVaultResourceId'), '/')), parameters('keyName')), parameters('location'), parameters('userAssignedIdentityResourceId')))]", + "properties": { + "principalId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('userAssignedIdentityResourceId'), '/')[2], split(parameters('userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(parameters('userAssignedIdentityResourceId'), '/'))), '2023-01-31').principalId]", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "principalType": "ServicePrincipal" + } + }, + { + "condition": "[not(equals(parameters('rbacAuthorizationEnabled'), true()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-DiskEncrSet-KVAccessPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(parameters('keyVaultResourceId'), '/'))]" + }, + "accessPolicies": { + "value": [ + { + "tenantId": "[subscription().tenantId]", + "objectId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('userAssignedIdentityResourceId'), '/')[2], split(parameters('userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(parameters('userAssignedIdentityResourceId'), '/'))), '2023-01-31').principalId]", + "permissions": { + "keys": [ + "get", + "wrapKey", + "unwrapKey" + ] + } + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "8247309965052145251" + }, + "name": "Key Vault Access Policies", + "description": "This module deploys a Key Vault Access Policy.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "accessPoliciesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "accessPolicies": { + "$ref": "#/definitions/accessPoliciesType", + "metadata": { + "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedAccessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ] + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "policies": { + "type": "Microsoft.KeyVault/vaults/accessPolicies", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", + "properties": { + "accessPolicies": "[variables('formattedAccessPolicies')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the access policies assignment was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the access policies assignment." + }, + "value": "add" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the access policies assignment." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', parameters('keyVaultName'), 'add')]" + } + } + } + } + } + ] + } + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the disk encryption set." + }, + "value": "[resourceId('Microsoft.Compute/diskEncryptionSets', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the disk encryption set." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the disk encryption set was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('diskEncryptionSet', '2023-10-02', 'full'), 'identity'), 'principalId'), '')]" + }, + "identities": { + "type": "object", + "metadata": { + "description": "The idenities of the disk encryption set." + }, + "value": "[reference('diskEncryptionSet', '2023-10-02', 'full').identity]" + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "The name of the key vault with the disk encryption key." + }, + "value": "[last(split(parameters('keyVaultResourceId'), '/'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('diskEncryptionSet', '2023-10-02', 'full').location]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-KeyVault-{0}', parameters('time')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-KeyVaultKey-{0}', parameters('time')))]" + ] + } + ], + "outputs": { + "ztDiskEncryptionSetResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-DiskEncryptionSet-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" + }, + "ztDiskEncryptionSetPrincipalId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-DiskEncryptionSet-{0}', parameters('time'))), '2022-09-01').outputs.systemAssignedMIPrincipalId.value]" + } + } + } + } + } + ], + "outputs": { + "ztDiskEncryptionSetResourceId": { + "type": "string", + "value": "[if(parameters('diskZeroTrust'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('ZT-Key-Vault-{0}', parameters('time'))), '2022-09-01').outputs.ztDiskEncryptionSetResourceId.value, '')]" + } + } + } + }, + "dependsOn": [ + "baselineResourceGroups", + "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Workload-KeyVault-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('avdWorkloadSubsId'))]", + "resourceGroup": "[format('{0}', variables('varServiceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('varWrklKvName')]" + }, + "location": { + "value": "[parameters('avdSessionHostLocation')]" + }, + "enableRbacAuthorization": { + "value": true + }, + "enablePurgeProtection": { + "value": "[parameters('enableKvPurgeProtection')]" + }, + "sku": { + "value": "[variables('varWrklKeyVaultSku')]" + }, + "softDeleteRetentionInDays": { + "value": 7 + }, + "publicNetworkAccess": "[if(parameters('deployPrivateEndpointKeyvaultStorage'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "networkAcls": "[if(parameters('deployPrivateEndpointKeyvaultStorage'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId')), 'action', 'Allow')), 'ipRules', createArray())))]", + "privateEndpoints": "[if(parameters('deployPrivateEndpointKeyvaultStorage'), createObject('value', createArray(createObject('name', variables('varWrklKvPrivateEndpointName'), 'subnetResourceId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName')), parameters('existingVnetPrivateEndpointSubnetResourceId')), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklKvPrivateEndpointName')), 'service', 'vault', 'privateDnsZoneGroupName', if(parameters('createPrivateDnsZones'), split(reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.keyVaultDnsZoneResourceId.value, '/')[8], split(parameters('avdVnetPrivateDnsZoneKeyvaultId'), '/')[8]), 'privateDnsZoneResourceIds', createArray(if(parameters('createPrivateDnsZones'), reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.keyVaultDnsZoneResourceId.value, parameters('avdVnetPrivateDnsZoneKeyvaultId')))))), createObject('value', createArray()))]", + "secrets": "[if(not(contains(parameters('avdIdentityServiceProvider'), 'EntraID')), createObject('value', createArray(createObject('name', 'vmLocalUserPassword', 'value', parameters('avdVmLocalUserPassword'), 'contentType', 'Session host local user credentials'), createObject('name', 'vmLocalUserName', 'value', parameters('avdVmLocalUserName'), 'contentType', 'Session host local user credentials'), createObject('name', 'domainJoinUserName', 'value', parameters('avdDomainJoinUserName'), 'contentType', 'Domain join credentials'), createObject('name', 'domainJoinUserPassword', 'value', parameters('avdDomainJoinUserPassword'), 'contentType', 'Domain join credentials'))), createObject('value', createArray(createObject('name', 'vmLocalUserPassword', 'value', parameters('avdVmLocalUserPassword'), 'contentType', 'Session host local user credentials'), createObject('name', 'vmLocalUserName', 'value', parameters('avdVmLocalUserName'), 'contentType', 'Session host local user credentials'), createObject('name', 'domainJoinUserName', 'value', 'NoUsername', 'contentType', 'Domain join credentials'), createObject('name', 'domainJoinUserPassword', 'value', 'NoPassword', 'contentType', 'Domain join credentials'))))]", + "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'), variables('varWorkloadKeyvaultTag'))), createObject('value', union(variables('varAvdDefaultTags'), variables('varWorkloadKeyvaultTag'))))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "14297043571004129093" + }, + "name": "Key Vaults", + "description": "This module deploys a Key Vault.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "accessPoliciesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + }, + "metadata": { + "description": "Required. Permissions the identity has for keys, secrets and certificates." + } + } + } + }, + "nullable": true + }, + "secretsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributes": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Defines whether the secret is enabled or disabled." + } + }, + "exp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Defines when the secret will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." + } + }, + "nbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. If set, defines the date from which onwards the secret becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Contains attributes of the secret." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + } + }, + "nullable": true + }, + "keysType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributes": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Defines whether the key is enabled or disabled." + } + }, + "exp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Defines when the key will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." + } + }, + "nbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. If set, defines the date from which onwards the key becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Contains attributes of the key." + } + }, + "curveName": { + "type": "string", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "nullable": true, + "metadata": { + "description": "Optional. The elliptic curve name. Only works if \"keySize\" equals \"EC\" or \"EC-HSM\". Default is \"P-256\"." + } + }, + "keyOps": { + "type": "array", + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "release", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. The allowed operations on this key." + } + }, + "keySize": { + "type": "int", + "allowedValues": [ + 2048, + 3072, + 4096 + ], + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. Only works if \"keySize\" equals \"RSA\" or \"RSA-HSM\". Default is \"4096\"." + } + }, + "kty": { + "type": "string", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the key. Default is \"EC\"." + } + }, + "releasePolicy": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Content type and version of key release policy." + } + }, + "data": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Blob encoding the policy rules under which the key can be released." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "rotationPolicy": { + "$ref": "#/definitions/rotationPoliciesType", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + } + }, + "nullable": true + }, + "rotationPoliciesType": { + "type": "object", + "properties": { + "attributes": { + "type": "object", + "properties": { + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiration time for the new key version. It should be in ISO8601 format. Eg: \"P90D\", \"P1Y\"." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The attributes of key rotation policy." + } + }, + "lifetimeActions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "action": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "Notify", + "Rotate" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of action." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The action of key rotation policy lifetimeAction." + } + }, + "trigger": { + "type": "object", + "properties": { + "timeAfterCreate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time duration after key creation to rotate the key. It only applies to rotate. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." + } + }, + "timeBeforeExpiry": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time duration before key expiring to rotate or notify. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The trigger of key rotation policy lifetimeAction." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The lifetimeActions for key rotation action." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Key Vault. Must be globally unique." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "accessPolicies": { + "$ref": "#/definitions/accessPoliciesType", + "metadata": { + "description": "Optional. All access policies to create." + } + }, + "secrets": { + "$ref": "#/definitions/secretsType", + "nullable": true, + "metadata": { + "description": "Optional. All secrets to create." + } + }, + "keys": { + "$ref": "#/definitions/keysType", + "nullable": true, + "metadata": { + "description": "Optional. All keys to create." + } + }, + "enableVaultForDeployment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for deployment by script or compute." + } + }, + "enableVaultForTemplateDeployment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for a template deployment." + } + }, + "enableVaultForDiskEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the azure platform has access to the vault for enabling disk encryption scenarios." + } + }, + "enableSoftDelete": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Switch to enable/disable Key Vault's soft delete feature." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 90, + "metadata": { + "description": "Optional. softDelete data retention days. It accepts >=7 and <=90." + } + }, + "enableRbacAuthorization": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC." + } + }, + "createMode": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The vault's create mode to indicate whether the vault need to be recovered or not. - recover or default." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Provide 'true' to enable Key Vault's purge protection feature." + } + }, + "sku": { + "type": "string", + "defaultValue": "premium", + "allowedValues": [ + "premium", + "standard" + ], + "metadata": { + "description": "Optional. Specifies the SKU for the vault." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Rules governing the accessibility of the resource from specific network locations." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedAccessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Certificates Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a4417e6f-fecd-4de8-b567-7b0420556985')]", + "Key Vault Certificate User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db79e9a7-68ee-4b58-9aeb-b90e7c24fcba')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.keyvault-vault.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "keyVault": { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "enabledForDeployment": "[parameters('enableVaultForDeployment')]", + "enabledForTemplateDeployment": "[parameters('enableVaultForTemplateDeployment')]", + "enabledForDiskEncryption": "[parameters('enableVaultForDiskEncryption')]", + "enableSoftDelete": "[parameters('enableSoftDelete')]", + "softDeleteRetentionInDays": "[parameters('softDeleteRetentionInDays')]", + "enableRbacAuthorization": "[parameters('enableRbacAuthorization')]", + "createMode": "[parameters('createMode')]", + "enablePurgeProtection": "[if(parameters('enablePurgeProtection'), parameters('enablePurgeProtection'), null())]", + "tenantId": "[subscription().tenantId]", + "accessPolicies": "[variables('formattedAccessPolicies')]", + "sku": { + "name": "[parameters('sku')]", + "family": "A" + }, + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(coalesce(parameters('privateEndpoints'), createArray()))), empty(coalesce(parameters('networkAcls'), createObject()))), 'Disabled', null()))]" + } + }, + "keyVault_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_diagnosticSettings": { + "copy": { + "name": "keyVault_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_roleAssignments": { + "copy": { + "name": "keyVault_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.KeyVault/vaults', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_accessPolicies": { + "condition": "[not(empty(parameters('accessPolicies')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-AccessPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('name')]" + }, + "accessPolicies": { + "value": "[parameters('accessPolicies')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "17696169708082133914" + }, + "name": "Key Vault Access Policies", + "description": "This module deploys a Key Vault Access Policy.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "accessPoliciesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + }, + "metadata": { + "description": "Required. Permissions the identity has for keys, secrets and certificates." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "accessPolicies": { + "$ref": "#/definitions/accessPoliciesType", + "metadata": { + "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedAccessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ] + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "policies": { + "type": "Microsoft.KeyVault/vaults/accessPolicies", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", + "properties": { + "accessPolicies": "[variables('formattedAccessPolicies')]" + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the access policies assignment was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the access policies assignment." + }, + "value": "add" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the access policies assignment." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', parameters('keyVaultName'), 'add')]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_secrets": { + "copy": { + "name": "keyVault_secrets", + "count": "[length(coalesce(parameters('secrets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-Secret-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].value]" + }, + "keyVaultName": { + "value": "[parameters('name')]" + }, + "attributesEnabled": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributesEnabled')]" + }, + "attributesExp": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributesExp')]" + }, + "attributesNbf": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributesNbf')]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12190317675030946449" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "contentType": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secret": { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "contentType": "[parameters('contentType')]", + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "value": "[parameters('value')]" + } + }, + "secret_roleAssignments": { + "copy": { + "name": "secret_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "secret" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the secret." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the secret." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the secret was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_keys": { + "copy": { + "name": "keyVault_keys", + "count": "[length(coalesce(parameters('keys'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-Key-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('keys'), createArray())[copyIndex()].name]" + }, + "keyVaultName": { + "value": "[parameters('name')]" + }, + "attributesEnabled": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesEnabled')]" + }, + "attributesExp": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesExp')]" + }, + "attributesNbf": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesNbf')]" + }, + "curveName": "[if(and(not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA')), not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM'))), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'curveName'), 'P-256')), createObject('value', null()))]", + "keyOps": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keyOps')]" + }, + "keySize": "[if(or(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA'), equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM')), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keySize'), 4096)), createObject('value', null()))]", + "releasePolicy": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'releasePolicy'), createObject())]" + }, + "kty": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'EC')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "rotationPolicy": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'rotationPolicy')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "1370782359529624908" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "curveName": { + "type": "string", + "defaultValue": "P-256", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "metadata": { + "description": "Optional. The elliptic curve name." + } + }, + "keyOps": { + "type": "array", + "nullable": true, + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "metadata": { + "description": "Optional. Array of JsonWebKeyOperation." + } + }, + "keySize": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." + } + }, + "kty": { + "type": "string", + "defaultValue": "EC", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "metadata": { + "description": "Optional. The type of the key." + } + }, + "releasePolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "rotationPolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy properties object." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "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')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "key": { + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "curveName": "[parameters('curveName')]", + "keyOps": "[parameters('keyOps')]", + "keySize": "[parameters('keySize')]", + "kty": "[parameters('kty')]", + "rotationPolicy": "[coalesce(parameters('rotationPolicy'), createObject())]", + "release_policy": "[coalesce(parameters('releasePolicy'), createObject())]" + } + }, + "key_roleAssignments": { + "copy": { + "name": "key_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "key" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the key was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_privateEndpoints": { + "copy": { + "name": "keyVault_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyVault-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key vault." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the key vault was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the key vault." + }, + "value": "[parameters('name')]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The URI of the key vault." + }, + "value": "[reference('keyVault').vaultUri]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('keyVault', '2022-07-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "baselineResourceGroups", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]" + ] + }, + { + "condition": "[variables('varCreateStorageDeployment')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('SMB-Storage-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('avdWorkloadSubsId'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "deploymentPrefix": { + "value": "[variables('varDeploymentPrefixLowercase')]" + }, + "deploymentEnvironment": { + "value": "[variables('varDeploymentEnvironmentLowercase')]" + }, + "storageService": { + "value": "[parameters('storageService')]" + }, + "useCustomNaming": { + "value": "[parameters('avdUseCustomNaming')]" + }, + "storageAvailabilityZones": { + "value": "[parameters('zoneRedundantStorage')]" + }, + "domainJoinUserName": { + "value": "[parameters('avdDomainJoinUserName')]" + }, + "vmLocalUserName": { + "value": "[parameters('avdVmLocalUserName')]" + }, + "identityServiceProvider": { + "value": "[parameters('avdIdentityServiceProvider')]" + }, + "avdSessionHostsOuPath": { + "value": "[parameters('avdOuPath')]" + }, + "storageOuPath": { + "value": "[parameters('storageOuPath')]" + }, + "managementVmSize": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostsSize')), createObject('value', 'Standard_D2ads_v5'))]", + "createResourceTags": { + "value": "[parameters('createResourceTags')]" + }, + "deployPrivateEndpointKeyvaultStorage": { + "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" + }, + "dnsServers": { + "value": "[parameters('customDnsIps')]" + }, + "identityDomainName": { + "value": "[parameters('identityDomainName')]" + }, + "storageObjectsRgName": { + "value": "[variables('varStorageObjectsRgName')]" + }, + "baseScriptUri": { + "value": "[variables('varBaseScriptUri')]" + }, + "securityPrincipalName": { + "value": "[variables('varSecurityPrincipalName')]" + }, + "diskEncryptionSetResourceId": "[if(parameters('diskZeroTrust'), createObject('value', reference(subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time'))), '2022-09-01').outputs.ztDiskEncryptionSetResourceId.value), createObject('value', ''))]", + "sessionHostTimeZone": { + "value": "[variables('varTimeZoneSessionHosts')]" + }, + "createFslogixDeployment": { + "value": "[parameters('createFslogixDeployment')]" + }, + "securityType": "[if(equals(parameters('securityType'), 'Standard'), createObject('value', ''), createObject('value', parameters('securityType')))]", + "secureBootEnabled": { + "value": "[parameters('secureBootEnabled')]" + }, + "vTpmEnabled": { + "value": "[parameters('vTpmEnabled')]" + }, + "encryptionAtHost": { + "value": "[parameters('diskZeroTrust')]" + }, + "storageManagedIdentityResourceId": "[if(and(variables('varCreateStorageDeployment'), not(equals(parameters('avdIdentityServiceProvider'), 'EntraID'))), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time'))), '2022-09-01').outputs.managedIdentityStorageResourceId.value), createObject('value', ''))]", + "applicationSecurityGroupResourceId": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', format('{0}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.applicationSecurityGroupResourceId.value)), createObject('value', ''))]", + "createAppAttachDeployment": { + "value": "[parameters('createAppAttachDeployment')]" + }, + "fslogixFileShareCustomName": { + "value": "[parameters('fslogixFileShareCustomName')]" + }, + "appAttachFileShareCustomName": { + "value": "[parameters('appAttachFileShareCustomName')]" + }, + "storageAccountPrefixCustomName": { + "value": "[parameters('storageAccountPrefixCustomName')]" + }, + "anfAccountCustomName": { + "value": "[parameters('anfAccountCustomName')]" + }, + "managedIdentityClientId": "[if(and(variables('varCreateStorageDeployment'), not(equals(parameters('avdIdentityServiceProvider'), 'EntraID'))), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time'))), '2022-09-01').outputs.managedIdentityStorageClientId.value), createObject('value', ''))]", + "privateDnsZoneFilesResourceId": "[if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.azureFilesDnsZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneFilesId')))]", + "serviceObjectsRgName": { + "value": "[variables('varServiceObjectsRgName')]" + }, + "alaWorkspaceResourceId": "[if(parameters('avdDeployMonitoring'), if(parameters('deployAlaWorkspace'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.avdAlaWorkspaceResourceId.value), createObject('value', parameters('alaExistingWorkspaceResourceId'))), createObject('value', ''))]", + "deploymentEnvironmentOneCharacter": { + "value": "[variables('varDeploymentEnvironmentOneCharacter')]" + }, + "computeStorageResourcesNamingStandard": { + "value": "[variables('varComputeStorageResourcesNamingStandard')]" + }, + "fslogixFileShareQuotaSize": { + "value": "[parameters('fslogixFileShareQuotaSize')]" + }, + "appAttachFileShareQuotaSize": { + "value": "[parameters('appAttachFileShareQuotaSize')]" + }, + "fslogixStoragePerformance": { + "value": "[parameters('fslogixStoragePerformance')]" + }, + "appAttachStoragePerformance": { + "value": "[parameters('appAttachStoragePerformance')]" + }, + "anfSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAnfSubnetName'))), createObject('value', parameters('existingVnetAnfSubnetResourceId')))]", + "vmsSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", + "privateEndpointSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", + "location": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostLocation')), createObject('value', parameters('avdManagementPlaneLocation')))]", + "locationAcronym": "[if(parameters('avdDeploySessionHosts'), createObject('value', variables('varSessionHostLocationAcronym')), createObject('value', parameters('avdManagementPlaneLocation')))]", + "managementVmOsImage": { + "value": "[parameters('managementVmOsImage')]" + }, + "keyVaultResourceId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" + }, + "customResourceTags": { + "value": "[variables('varCustomResourceTags')]" + }, + "defaultTags": { + "value": "[variables('varAvdDefaultTags')]" + }, + "identityDomainGuid": { + "value": "[parameters('identityDomainGuid')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "17332805804383803852" + } + }, + "parameters": { + "subId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "The subscription ID for the AVD workload." + } + }, + "deploymentPrefix": { + "type": "string", + "metadata": { + "description": "The deployment prefix in lowercase." + } + }, + "deploymentEnvironment": { + "type": "string", + "metadata": { + "description": "The deployment environment in lowercase." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The session host location acronym derived from the resource group location." + } + }, + "locationAcronym": { + "type": "string", + "metadata": { + "description": "The session host or AVD management plane location acronym For example, \"eus\" for East US." + } + }, + "storageService": { + "type": "string", + "metadata": { + "description": "The storage service to use (AzureFiles or ANF)." + } + }, + "useCustomNaming": { + "type": "bool", + "metadata": { + "description": "Indicates whether to use custom naming for AVD." + } + }, + "computeStorageResourcesNamingStandard": { + "type": "string", + "metadata": { + "description": "The naming standard for compute storage resources coming from the main template." + } + }, + "fslogixFileShareCustomName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The custom name for the FSLogix file share." + } + }, + "appAttachFileShareCustomName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The custom name for the App Attach file share." + } + }, + "managementVmOsImage": { + "type": "string", + "metadata": { + "description": "The OS image for the management VM." + } + }, + "storageAccountPrefixCustomName": { + "type": "string", + "defaultValue": "st", + "metadata": { + "description": "AVD FSLogix and App Attach storage account prefix custom name." + } + }, + "anfAccountCustomName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The custom name for the ANF account." + } + }, + "deploymentEnvironmentOneCharacter": { + "type": "string", + "metadata": { + "description": "Deployment prefix one character." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Key Vault." + } + }, + "alaWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "The Azure Log Analytics workspace resource ID." + } + }, + "privateDnsZoneFilesResourceId": { + "type": "string", + "metadata": { + "description": "The private DNS zone files resource ID." + } + }, + "managedIdentityClientId": { + "type": "string", + "metadata": { + "description": "The client ID of the managed identity." + } + }, + "fslogixFileShareQuotaSize": { + "type": "int", + "metadata": { + "description": "The FSLogix file share quota size in GiBs." + } + }, + "appAttachFileShareQuotaSize": { + "type": "int", + "metadata": { + "description": "The App Attach file share quota size in GiBs." + } + }, + "fslogixStoragePerformance": { + "type": "string", + "metadata": { + "description": "The storage performance level for FSLogix." + } + }, + "appAttachStoragePerformance": { + "type": "string", + "metadata": { + "description": "The storage performance level for App Attach." + } + }, + "anfSubnetResourceId": { + "type": "string", + "metadata": { + "description": "Subnet resource ID for ANF volumes." + } + }, + "vmsSubnetResourceId": { + "type": "string", + "metadata": { + "description": "Subnet resource ID for VMs." + } + }, + "securityType": { + "type": "string", + "metadata": { + "description": "The security type for the VM (e.g., TrustedLaunch, Standard)." + } + }, + "privateEndpointSubnetResourceId": { + "type": "string", + "metadata": { + "description": "Subnet resource ID for private endpoints." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the disk encryption set." + } + }, + "encryptionAtHost": { + "type": "bool", + "metadata": { + "description": "Indicates whether encryption at host is enabled for the VM." + } + }, + "storageManagedIdentityResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the managed identity for storage." + } + }, + "secureBootEnabled": { + "type": "bool", + "metadata": { + "description": "Indicates whether secure boot is enabled for the VM." + } + }, + "vTpmEnabled": { + "type": "bool", + "metadata": { + "description": "Indicates whether vTPM is enabled for the VM." + } + }, + "sessionHostTimeZone": { + "type": "string", + "metadata": { + "description": "The time zone for the session host." + } + }, + "applicationSecurityGroupResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application security group." + } + }, + "storageAvailabilityZones": { + "type": "bool", + "metadata": { + "description": "USe or not zone redundant storage." + } + }, + "dnsServers": { + "type": "string", + "metadata": { + "description": "The custom DNS IPs." + } + }, + "identityServiceProvider": { + "type": "string", + "metadata": { + "description": "The identity service provider (e.g., EntraDS)." + } + }, + "domainJoinUserName": { + "type": "string", + "metadata": { + "description": "The domain join username." + } + }, + "vmLocalUserName": { + "type": "string", + "metadata": { + "description": "The VM local username." + } + }, + "serviceObjectsRgName": { + "type": "string", + "metadata": { + "description": "The service objects resource group name." + } + }, + "storageObjectsRgName": { + "type": "string", + "metadata": { + "description": "The storage objects resource group name." + } + }, + "managementVmSize": { + "type": "string", + "metadata": { + "description": "The VM size for the management VM." + } + }, + "avdSessionHostsOuPath": { + "type": "string", + "metadata": { + "description": "The OU path for AVD session hosts." + } + }, + "storageOuPath": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The storage OU path." + } + }, + "customResourceTags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "The custom resource tags." + } + }, + "defaultTags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "The AVD default tags." + } + }, + "createResourceTags": { + "type": "bool", + "metadata": { + "description": "Indicates whether to create resource tags." + } + }, + "baseScriptUri": { + "type": "string", + "metadata": { + "description": "The base script URI." + } + }, + "securityPrincipalName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The security principal name." + } + }, + "identityDomainName": { + "type": "string", + "metadata": { + "description": "The identity domain name." + } + }, + "identityDomainGuid": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The identity domain GUID." + } + }, + "deployPrivateEndpointKeyvaultStorage": { + "type": "bool", + "metadata": { + "description": "Indicates whether to deploy private endpoints for Key Vault and storage." + } + }, + "createFslogixDeployment": { + "type": "bool", + "metadata": { + "description": "Indicates whether to create FSLogix deployment." + } + }, + "createAppAttachDeployment": { + "type": "bool", + "metadata": { + "description": "Indicates whether to create App Attach deployment." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "The deployment timestamp." + } + } + }, + "variables": { + "$fxv#0": { + "win10_22h2_g2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "windows-10", + "sku": "win10-22h2-avd-g2", + "version": "latest" + }, + "win10_22h2_office_g2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "office-365", + "sku": "win10-22h2-avd-m365-g2", + "version": "latest" + }, + "win11_22h2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "Windows-11", + "sku": "win11-22h2-avd", + "version": "latest" + }, + "win11_22h2_office": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "office-365", + "sku": "win11-22h2-avd-m365", + "version": "latest" + }, + "win11_23h2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "Windows-11", + "sku": "win11-23h2-avd", + "version": "latest" + }, + "win11_23h2_office": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "office-365", + "sku": "win11-23h2-avd-m365", + "version": "latest" + }, + "win11_24h2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "Windows-11", + "sku": "win11-24h2-avd", + "version": "latest" + }, + "win11_24h2_office": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "office-365", + "sku": "win11-24h2-avd-m365", + "version": "latest" + }, + "winServer_2022_Datacenter": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2022-datacenter-g2", + "version": "latest" + }, + "winServer_2022_Datacenter_smalldisk_g2": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2022-datacenter-smalldisk-g2", + "version": "latest" + }, + "winServer_2022_datacenter_core": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2022-datacenter-core-g2", + "version": "latest" + }, + "winServer_2022_Datacenter_core_smalldisk_g2": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2022-datacenter-core-smalldisk-g2", + "version": "latest" + } + }, + "varNamingUniqueStringThreeChar": "[take(format('{0}', uniqueString(parameters('subId'), parameters('deploymentPrefix'), parameters('time'))), 3)]", + "varAnfCapacityPoolSize": "[if(greater(add(if(parameters('createFslogixDeployment'), parameters('fslogixFileShareQuotaSize'), 0), if(parameters('createAppAttachDeployment'), parameters('appAttachFileShareQuotaSize'), 0)), 4096), add(if(parameters('createFslogixDeployment'), parameters('fslogixFileShareQuotaSize'), 0), if(parameters('createAppAttachDeployment'), parameters('appAttachFileShareQuotaSize'), 0)), 4096)]", + "varFslogixFileShareName": "[if(equals(parameters('storageService'), 'AzureFiles'), if(parameters('useCustomNaming'), parameters('fslogixFileShareCustomName'), format('fslogix-pc-{0}-{1}-{2}-001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('locationAcronym'))), if(equals(parameters('storageService'), 'ANF'), format('fsl{0}{1}{2}001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('locationAcronym')), ''))]", + "varAnfSmbServerNamePrefix": "[format('anf{0}{1}', parameters('deploymentPrefix'), parameters('deploymentEnvironment'))]", + "varAppAttachFileShareName": "[if(equals(parameters('storageService'), 'AzureFiles'), if(parameters('useCustomNaming'), parameters('appAttachFileShareCustomName'), format('appa-{0}-{1}-{2}-001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('locationAcronym'))), if(equals(parameters('storageService'), 'ANF'), format('appa{0}01', parameters('deploymentPrefix')), ''))]", + "varFslogixAnfVolume": "[if(parameters('createFslogixDeployment'), createArray(createObject('name', variables('varFslogixFileShareName'), 'coolAccess', false(), 'encryptionKeySource', 'Microsoft.NetApp', 'zones', createArray(), 'serviceLevel', parameters('fslogixStoragePerformance'), 'networkFeatures', 'Standard', 'usageThreshold', mul(parameters('fslogixFileShareQuotaSize'), 1073741824), 'protocolTypes', createArray('CIFS'), 'subnetResourceId', parameters('anfSubnetResourceId'), 'creationToken', variables('varFslogixFileShareName'), 'smbContinuouslyAvailable', true(), 'securityStyle', 'ntfs')), createArray())]", + "varAppAttchAnfVolume": "[if(parameters('createAppAttachDeployment'), createArray(createObject('name', variables('varAppAttachFileShareName'), 'coolAccess', false(), 'encryptionKeySource', 'Microsoft.NetApp', 'zones', createArray(), 'serviceLevel', parameters('appAttachStoragePerformance'), 'networkFeatures', 'Standard', 'usageThreshold', mul(parameters('appAttachFileShareQuotaSize'), 1073741824), 'protocolTypes', createArray('CIFS'), 'subnetResourceId', parameters('anfSubnetResourceId'), 'creationToken', variables('varAppAttachFileShareName'), 'smbContinuouslyAvailable', true(), 'securityStyle', 'ntfs')), createArray())]", + "varAnfVolumes": "[union(variables('varFslogixAnfVolume'), variables('varAppAttchAnfVolume'))]", + "varFslogixStorageName": "[if(parameters('useCustomNaming'), format('{0}fsl{1}{2}{3}', parameters('storageAccountPrefixCustomName'), parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')), format('stfsl{0}{1}{2}', parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')))]", + "varAnfAccountName": "[if(parameters('useCustomNaming'), parameters('anfAccountCustomName'), format('anf-acc-{0}-001', parameters('computeStorageResourcesNamingStandard')))]", + "varAnfCapacityPoolName": "[format('anf-cpool-{0}-001', parameters('computeStorageResourcesNamingStandard'))]", + "varFslogixStorageFqdn": "[if(parameters('createFslogixDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('{0}.file.{1}', variables('varFslogixStorageName'), environment().suffixes.storage), if(equals(parameters('storageService'), 'ANF'), format('{0}...{1}.netapp.azure.com', variables('varFslogixFileShareName'), parameters('location')), '')), '')]", + "varAppAttachStorageFqdn": "[if(parameters('createAppAttachDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('{0}.file.{1}', variables('varAppAttachStorageName'), environment().suffixes.storage), if(equals(parameters('storageService'), 'ANF'), format('{0}...{1}.netapp.azure.com', variables('varAppAttachFileShareName'), parameters('location')), '')), '')]", + "varAppAttachStorageName": "[if(parameters('useCustomNaming'), format('{0}appa{1}{2}{3}', parameters('storageAccountPrefixCustomName'), parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')), format('stappa{0}{1}{2}', parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')))]", + "varManagementVmName": "[format('vmmgmt{0}{1}{2}', parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), parameters('locationAcronym'))]", + "varFslogixStoragePerformance": "[if(equals(parameters('fslogixStoragePerformance'), 'Ultra'), 'Premium', parameters('fslogixStoragePerformance'))]", + "varAppAttachStoragePerformance": "[if(equals(parameters('appAttachStoragePerformance'), 'Ultra'), 'Premium', parameters('appAttachStoragePerformance'))]", + "varFslogixStorageSku": "[if(and(parameters('storageAvailabilityZones'), equals(parameters('storageService'), 'AzureFiles')), format('{0}_ZRS', variables('varFslogixStoragePerformance')), format('{0}_LRS', variables('varFslogixStoragePerformance')))]", + "varAppAttachStorageSku": "[if(parameters('storageAvailabilityZones'), format('{0}_ZRS', variables('varAppAttachStoragePerformance')), format('{0}_LRS', variables('varAppAttachStoragePerformance')))]", + "varStorageAzureFilesDscAgentPackageLocation": "https://github.com/Azure/avdaccelerator/raw/main/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip", + "varStorageToDomainScriptUri": "[format('{0}scripts/Manual-DSC-Storage-Scripts.ps1', parameters('baseScriptUri'))]", + "varStorageToDomainScript": "./Manual-DSC-Storage-Scripts.ps1", + "varOuStgPath": "[if(not(empty(parameters('storageOuPath'))), format('\"{0}\"', parameters('storageOuPath')), format('\"{0}\"', variables('varDefaultStorageOuPath')))]", + "varDefaultStorageOuPath": "[if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDC Computers', 'Computers')]", + "varStorageCustomOuPath": "[if(not(empty(parameters('storageOuPath'))), 'true', 'false')]", + "varMarketPlaceGalleryWindows": "[variables('$fxv#0')]" + }, + "resources": [ + { + "condition": "[and(not(equals(parameters('identityServiceProvider'), 'EntraID')), or(parameters('createFslogixDeployment'), parameters('createAppAttachDeployment')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-MGMT-VM-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "diskEncryptionSetResourceId": { + "value": "[parameters('diskEncryptionSetResourceId')]" + }, + "identityServiceProvider": { + "value": "[parameters('identityServiceProvider')]" + }, + "vmName": { + "value": "[variables('varManagementVmName')]" + }, + "computeTimeZone": { + "value": "[parameters('sessionHostTimeZone')]" + }, + "applicationSecurityGroupResourceId": { + "value": "[parameters('applicationSecurityGroupResourceId')]" + }, + "domainJoinUserName": { + "value": "[parameters('domainJoinUserName')]" + }, + "keyVaultResourceId": { + "value": "[parameters('keyVaultResourceId')]" + }, + "serviceObjectsRgName": { + "value": "[parameters('serviceObjectsRgName')]" + }, + "identityDomainName": { + "value": "[parameters('identityDomainName')]" + }, + "ouPath": { + "value": "[parameters('avdSessionHostsOuPath')]" + }, + "osDiskType": { + "value": "Standard_LRS" + }, + "location": { + "value": "[parameters('location')]" + }, + "vmSize": { + "value": "[parameters('managementVmSize')]" + }, + "subnetResourceId": { + "value": "[parameters('vmsSubnetResourceId')]" + }, + "enableAcceleratedNetworking": { + "value": true + }, + "securityType": { + "value": "[parameters('securityType')]" + }, + "secureBootEnabled": { + "value": "[parameters('secureBootEnabled')]" + }, + "vTpmEnabled": { + "value": "[parameters('vTpmEnabled')]" + }, + "vmLocalUserName": { + "value": "[parameters('vmLocalUserName')]" + }, + "subId": { + "value": "[parameters('subId')]" + }, + "encryptionAtHost": { + "value": "[parameters('encryptionAtHost')]" + }, + "storageManagedIdentityResourceId": { + "value": "[parameters('storageManagedIdentityResourceId')]" + }, + "osImage": { + "value": "[variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')]]" + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "8670712661433034722" + }, + "name": "AVD LZA storage management VM", + "description": "This module deploys a management VM to join Azure Files to domain and for tools.", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "diskEncryptionSetResourceId": { + "type": "string", + "metadata": { + "description": "AVD disk encryption set resource ID to enable server side encyption." + } + }, + "subId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "computeTimeZone": { + "type": "string", + "metadata": { + "description": "Virtual machine time zone." + } + }, + "identityServiceProvider": { + "type": "string", + "metadata": { + "description": "Required, The service providing domain services for Azure Virtual Desktop." + } + }, + "serviceObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name for Azure Files." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Subnet resource ID." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "metadata": { + "description": "Enable accelerated networking on the session host VMs." + } + }, + "securityType": { + "type": "string", + "metadata": { + "description": "Specifies the securityType of the virtual machine. Must be TrustedLaunch or ConfidentialVM enable UefiSettings." + } + }, + "secureBootEnabled": { + "type": "bool", + "metadata": { + "description": "Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "vTpmEnabled": { + "type": "bool", + "metadata": { + "description": "Specifies whether virtual TPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy compute services." + } + }, + "encryptionAtHost": { + "type": "bool", + "metadata": { + "description": "This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "Session host VM size." + } + }, + "osDiskType": { + "type": "string", + "metadata": { + "description": "OS disk type for session host." + } + }, + "osImage": { + "type": "object", + "metadata": { + "description": "Market Place OS image" + } + }, + "storageManagedIdentityResourceId": { + "type": "string", + "metadata": { + "description": "Storage Managed Identity Resource ID." + } + }, + "vmLocalUserName": { + "type": "string", + "metadata": { + "description": "Local administrator username." + } + }, + "identityDomainName": { + "type": "string", + "metadata": { + "description": "Identity domain name." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Keyvault resource ID to get credentials from." + } + }, + "domainJoinUserName": { + "type": "string", + "metadata": { + "description": "AVD session host domain join credentials." + } + }, + "ouPath": { + "type": "string", + "metadata": { + "description": "OU path to join AVd VMs." + } + }, + "applicationSecurityGroupResourceId": { + "type": "string", + "metadata": { + "description": "Application Security Group (ASG) for the session hosts." + } + }, + "tags": { + "type": "object", + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "vmName": { + "type": "string", + "metadata": { + "description": "Name for management virtual machine. for tools and to join Azure Files to domain." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + } + }, + "variables": { + "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]", + "varManagedDisk": "[if(empty(parameters('diskEncryptionSetResourceId')), createObject('storageAccountType', parameters('osDiskType')), createObject('diskEncryptionSet', createObject('id', parameters('diskEncryptionSetResourceId')), 'storageAccountType', parameters('osDiskType')))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('MGMT-VM-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('vmName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "timeZone": { + "value": "[parameters('computeTimeZone')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": false, + "userAssignedResourceIds": [ + "[parameters('storageManagedIdentityResourceId')]" + ] + } + }, + "encryptionAtHost": { + "value": "[parameters('encryptionAtHost')]" + }, + "zone": { + "value": 0 + }, + "osType": { + "value": "Windows" + }, + "vmSize": { + "value": "[parameters('vmSize')]" + }, + "securityType": { + "value": "[parameters('securityType')]" + }, + "secureBootEnabled": { + "value": "[parameters('secureBootEnabled')]" + }, + "vTpmEnabled": { + "value": "[parameters('vTpmEnabled')]" + }, + "imageReference": { + "value": "[parameters('osImage')]" + }, + "osDisk": { + "value": { + "createOption": "FromImage", + "deleteOption": "Delete", + "caching": "ReadWrite", + "managedDisk": "[variables('varManagedDisk')]" + } + }, + "adminUsername": { + "value": "[parameters('vmLocalUserName')]" + }, + "adminPassword": { + "reference": { + "keyVault": { + "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))]" + }, + "secretName": "vmLocalUserPassword" + } + }, + "nicConfigurations": { + "value": [ + { + "name": "[format('nic-01-{0}', parameters('vmName'))]", + "deleteOption": "Delete", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "ipConfigurations": "[if(not(empty(parameters('applicationSecurityGroupResourceId'))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetResourceId'), 'applicationSecurityGroups', createArray(createObject('id', parameters('applicationSecurityGroupResourceId'))))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetResourceId'))))]" + } + ] + }, + "allowExtensionOperations": { + "value": true + }, + "extensionDomainJoinPassword": { + "reference": { + "keyVault": { + "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))]" + }, + "secretName": "domainJoinUserPassword" + } + }, + "extensionDomainJoinConfig": { + "value": { + "enabled": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), false(), true())]", + "settings": { + "name": "[parameters('identityDomainName')]", + "ouPath": "[if(not(empty(parameters('ouPath'))), parameters('ouPath'), null())]", + "user": "[parameters('domainJoinUserName')]", + "restart": "true", + "options": "3" + } + } + }, + "extensionAadJoinConfig": { + "value": { + "enabled": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), true(), false())]" + } + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13031055217657209142" + }, + "name": "Virtual Machines", + "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "osDiskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "metadata": { + "description": "Required. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + } + } + }, + "dataDisksType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } + }, + "lun": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the logical unit number of the data disk." + } + }, + "diskSizeGB": { + "type": "int", + "maxValue": 1023, + "metadata": { + "description": "Required. Specifies the size of an empty data disk in gigabytes." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "metadata": { + "description": "Required. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." + } + }, + "computerName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." + } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "Required. Specifies the size for the VMs." + } + }, + "encryptionAtHost": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "securityType": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the SecurityType of the virtual machine. It is set as TrustedLaunch to enable UefiSettings." + } + }, + "secureBootEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "vTpmEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "imageReference": { + "type": "object", + "metadata": { + "description": "Required. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image." + } + }, + "plan": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." + } + }, + "osDisk": { + "$ref": "#/definitions/osDiskType", + "metadata": { + "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "dataDisks": { + "$ref": "#/definitions/dataDisksType", + "metadata": { + "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "ultraSSDEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." + } + }, + "adminUsername": { + "type": "securestring", + "metadata": { + "description": "Required. Administrator username." + } + }, + "adminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. When specifying a Windows Virtual Machine, this value should be passed." + } + }, + "customData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." + } + }, + "certificatesToBeInstalled": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." + } + }, + "priority": { + "type": "string", + "defaultValue": "Regular", + "allowedValues": [ + "Regular", + "Low", + "Spot" + ], + "metadata": { + "description": "Optional. Specifies the priority for the virtual machine." + } + }, + "enableEvictionPolicy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy." + } + }, + "maxPriceForLowPriorityVm": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." + } + }, + "dedicatedHostId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." + } + }, + "licenseType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "RHEL_BYOS", + "SLES_BYOS", + "Windows_Client", + "Windows_Server", + "" + ], + "metadata": { + "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." + } + }, + "bootDiagnostics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." + } + }, + "bootDiagnosticStorageAccountName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." + } + }, + "bootDiagnosticStorageAccountUri": { + "type": "string", + "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", + "metadata": { + "description": "Optional. Storage account boot diagnostic base URI." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a proximity placement group." + } + }, + "virtualMachineScaleSetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." + } + }, + "availabilitySetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." + } + }, + "zone": { + "type": "int", + "allowedValues": [ + 0, + 1, + 2, + 3 + ], + "metadata": { + "description": "Required. If set to 1, 2 or 3, the availability zone for all VMs is hardcoded to that value. If zero, then availability zones is not used. Cannot be used in combination with availability set nor scale set." + } + }, + "nicConfigurations": { + "type": "array", + "metadata": { + "description": "Required. Configures NICs and PIPs." + } + }, + "allowExtensionOperations": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." + } + }, + "extensionDomainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if name is specified. Password of the user specified in user parameter." + } + }, + "extensionDomainJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAadJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." + } + }, + "extensionAzureDiskEncryptionConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." + } + }, + "extensionDSCConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "fileData": [] + }, + "metadata": { + "description": "Optional. The configuration for the [Custom Script] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionNvidiaGpuDriverWindows": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptProtectedSetting": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. An object that contains the extension specific protected settings." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to generate a registration token." + } + }, + "sasTokenValidityLength": { + "type": "string", + "defaultValue": "PT8H", + "metadata": { + "description": "Optional. SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. The chosen OS type." + } + }, + "provisionVMAgent": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." + } + }, + "enableAutomaticUpdates": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." + } + }, + "patchMode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "AutomaticByPlatform", + "AutomaticByOS", + "Manual", + "ImageDefault", + "" + ], + "metadata": { + "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." + } + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables customer to schedule patching without accidental upgrades." + } + }, + "rebootSetting": { + "type": "string", + "defaultValue": "IfRequired", + "allowedValues": [ + "Always", + "IfRequired", + "Never", + "Unknown" + ], + "metadata": { + "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." + } + }, + "patchAssessmentMode": { + "type": "string", + "defaultValue": "ImageDefault", + "allowedValues": [ + "AutomaticByPlatform", + "ImageDefault" + ], + "metadata": { + "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." + } + }, + "additionalUnattendContent": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." + } + }, + "winRM": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object." + } + }, + "configurationProfile": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." + } + } + }, + "variables": { + "windowsConfiguration": { + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting'))), null())]", + "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", + "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), parameters('additionalUnattendContent'))]", + "winRM": "[if(not(empty(parameters('winRM'))), createObject('listeners', parameters('winRM')), null())]" + }, + "accountSasProperties": { + "signedServices": "b", + "signedPermission": "r", + "signedExpiry": "[dateTimeAdd(parameters('baseTime'), parameters('sasTokenValidityLength'))]", + "signedResourceTypes": "o", + "signedProtocol": "https" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "vm": { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "zones": "[if(not(equals(parameters('zone'), 0)), array(string(parameters('zone'))), null())]", + "plan": "[if(not(empty(parameters('plan'))), parameters('plan'), null())]", + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "securityProfile": { + "encryptionAtHost": "[if(parameters('encryptionAtHost'), parameters('encryptionAtHost'), null())]", + "securityType": "[parameters('securityType')]", + "uefiSettings": "[if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null())]" + }, + "storageProfile": { + "copy": [ + { + "name": "dataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", + "input": { + "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", + "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))]", + "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createoption'), 'Empty')]", + "deleteOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete')]", + "caching": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly')]", + "managedDisk": { + "storageAccountType": "[coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.storageAccountType]", + "diskEncryptionSet": "[coalesce(tryGet(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'managedDisk'), 'diskEncryptionSet'), null())]" + } + } + } + ], + "imageReference": "[parameters('imageReference')]", + "osDisk": { + "name": "[coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name')))]", + "createOption": "[coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage')]", + "deleteOption": "[coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete')]", + "caching": "[coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly')]", + "managedDisk": { + "storageAccountType": "[parameters('osDisk').managedDisk.storageAccountType]", + "diskEncryptionSet": { + "id": "[tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')]" + } + } + } + }, + "additionalCapabilities": { + "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]" + }, + "osProfile": { + "computerName": "[parameters('computerName')]", + "adminUsername": "[parameters('adminUsername')]", + "adminPassword": "[parameters('adminPassword')]", + "customData": "[if(not(empty(parameters('customData'))), base64(parameters('customData')), null())]", + "windowsConfiguration": "[if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null())]", + "secrets": "[parameters('certificatesToBeInstalled')]", + "allowExtensionOperations": "[parameters('allowExtensionOperations')]" + }, + "networkProfile": { + "copy": [ + { + "name": "networkInterfaces", + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "properties": { + "deleteOption": "[if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].deleteOption, 'Delete')]", + "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" + }, + "id": "[resourceId('Microsoft.Network/networkInterfaces', if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].name, format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].nicSuffix)))]" + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", + "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" + } + }, + "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", + "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", + "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", + "priority": "[parameters('priority')]", + "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", + "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", + "host": "[if(not(empty(parameters('dedicatedHostId'))), createObject('id', parameters('dedicatedHostId')), null())]", + "licenseType": "[if(not(empty(parameters('licenseType'))), parameters('licenseType'), null())]" + }, + "dependsOn": [ + "vm_nic" + ] + }, + "vm_configurationProfileAssignment": { + "condition": "[not(empty(parameters('configurationProfile')))]", + "type": "Microsoft.Automanage/configurationProfileAssignments", + "apiVersion": "2022-05-04", + "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", + "name": "default", + "properties": { + "configurationProfile": "[parameters('configurationProfile')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_nic": { + "copy": { + "name": "vm_nic", + "count": "[length(parameters('nicConfigurations'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkInterfaceName": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'name'), createObject('value', parameters('nicConfigurations')[copyIndex()].name), createObject('value', format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex()].nicSuffix)))]", + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableIPForwarding": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableIPForwarding), createObject('value', false()))]", + "enableAcceleratedNetworking": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableAcceleratedNetworking), createObject('value', true()))]", + "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(parameters('nicConfigurations')[copyIndex()].dnsServers)), createObject('value', parameters('nicConfigurations')[copyIndex()].dnsServers), createObject('value', createArray())), createObject('value', createArray()))]", + "networkSecurityGroupResourceId": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('nicConfigurations')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", + "ipConfigurations": { + "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4081873631846149092" + } + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "networkInterfaceName": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + }, + "ipConfigurations": { + "type": "array" + }, + "location": { + "type": "string", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false + }, + "dnsServers": { + "type": "array", + "defaultValue": [] + }, + "enableTelemetry": { + "type": "bool", + "metadata": { + "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the Network Interface." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "resources": { + "networkInterface_publicIPAddresses": { + "copy": { + "name": "networkInterface_publicIPAddresses", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[contains(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIpNameSuffix)]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'idleTimeoutInMinutes')]" + }, + "ddosSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'dnsSettings')]" + }, + "publicIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressVersion'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAddressVersion), createObject('value', 'IPv4'))]", + "publicIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAllocationMethod'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAllocationMethod), createObject('value', 'Static'))]", + "publicIpPrefixResourceId": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPPrefixResourceId'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPPrefixResourceId), createObject('value', ''))]", + "roleAssignments": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'roleAssignments'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.roleAssignments), createObject('value', createArray()))]", + "skuName": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuName'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuName), createObject('value', 'Standard'))]", + "skuTier": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuTier'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuTier), createObject('value', 'Regional'))]", + "tags": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "zones": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.zones), createObject('value', createArray(1, 2, 3)))]", + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.54.24096", + "templateHash": "4718335757080871925" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "", + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "metadata": { + "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "metadata": { + "description": "Required. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + } + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": null + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkInterface', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('networkInterfaceName')]" + }, + "ipConfigurations": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('ipConfigurations'))]", + "input": "[createObject('name', if(not(empty(parameters('ipConfigurations')[copyIndex('value')].name)), parameters('ipConfigurations')[copyIndex('value')].name, null()), 'primary', equals(copyIndex('value'), 0), 'privateIPAllocationMethod', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod, null()), null()), 'privateIPAddress', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('value')].privateIPAddress, null()), null()), 'publicIPAddressResourceId', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), resourceId('Microsoft.Network/publicIPAddresses', format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.publicIpNameSuffix)), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerBackendAddressPools, null()), 'applicationSecurityGroups', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('value')].applicationSecurityGroups, null()), 'applicationGatewayBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].applicationGatewayBackendAddressPools, null()), 'gatewayLoadBalancer', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('value')].gatewayLoadBalancer, null()), 'loadBalancerInboundNatRules', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerInboundNatRules, null()), 'privateIPAddressVersion', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('value')].privateIPAddressVersion, null()), 'virtualNetworkTaps', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('value')].virtualNetworkTaps, null()))]" + } + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "dnsServers": "[if(not(empty(parameters('dnsServers'))), createObject('value', parameters('dnsServers')), createObject('value', createArray()))]", + "enableAcceleratedNetworking": { + "value": "[parameters('enableAcceleratedNetworking')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enableIPForwarding": { + "value": "[parameters('enableIPForwarding')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", + "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "1612343535299711142" + }, + "name": "Network Interface", + "description": "This module deploys a Network Interface.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the network interface." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "dnsServers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "auxiliaryMode": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Floating", + "MaxConnections", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "auxiliarySku": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "A1", + "A2", + "A4", + "A8", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "disableTcpStateTracking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "description": "Required. A list of IPConfigurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.2.4', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "ipConfigurations", + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].name, format('ipconfig0{0}', add(copyIndex('ipConfigurations'), 1)))]", + "properties": { + "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", + "privateIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod, null()), null())]", + "privateIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress, null()), null())]", + "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId, null())), createObject('id', parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId), null()), null())]", + "subnet": { + "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" + }, + "loadBalancerBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerBackendAddressPools, null())]", + "applicationSecurityGroups": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationSecurityGroups, null())]", + "applicationGatewayBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationGatewayBackendAddressPools, null())]", + "gatewayLoadBalancer": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].gatewayLoadBalancer, null())]", + "loadBalancerInboundNatRules": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerInboundNatRules, null())]", + "privateIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddressVersion, null())]", + "virtualNetworkTaps": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].virtualNetworkTaps, null())]" + } + } + } + ], + "auxiliaryMode": "[parameters('auxiliaryMode')]", + "auxiliarySku": "[parameters('auxiliarySku')]", + "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", + "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "enableIPForwarding": "[parameters('enableIPForwarding')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" + } + }, + "networkInterface_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_diagnosticSettings": { + "copy": { + "name": "networkInterface_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_roleAssignments": { + "copy": { + "name": "networkInterface_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkInterface" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed resource." + }, + "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed resource." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkInterface', '2023-04-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "networkInterface_publicIPAddresses" + ] + } + } + } + } + }, + "vm_aadJoinExtension": { + "condition": "[parameters('extensionAadJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "AADLogin" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.ActiveDirectory" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", + "typeHandlerVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAadJoinConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.0'), createObject('value', '1.0')))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAadJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAadJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": "[if(contains(parameters('extensionAadJoinConfig'), 'settings'), createObject('value', parameters('extensionAadJoinConfig').settings), createObject('value', createObject()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] + }, + "vm_domainJoinExtension": { + "condition": "[parameters('extensionDomainJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DomainJoin" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "JsonADDomainExtension" + }, + "typeHandlerVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDomainJoinConfig').typeHandlerVersion), createObject('value', '1.3'))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDomainJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDomainJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": { + "value": "[parameters('extensionDomainJoinConfig').settings]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": { + "Password": "[parameters('extensionDomainJoinPassword')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_aadJoinExtension" + ] + }, + "vm_desiredStateConfigurationExtension": { + "condition": "[parameters('extensionDSCConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DesiredStateConfiguration" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Powershell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": "[if(contains(parameters('extensionDSCConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDSCConfig').typeHandlerVersion), createObject('value', '2.77'))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDSCConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDSCConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": "[if(contains(parameters('extensionDSCConfig'), 'settings'), createObject('value', parameters('extensionDSCConfig').settings), createObject('value', createObject()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": "[if(contains(parameters('extensionDSCConfig'), 'protectedSettings'), createObject('value', parameters('extensionDSCConfig').protectedSettings), createObject('value', createObject()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] + }, + "vm_customScriptExtension": { + "condition": "[parameters('extensionCustomScriptConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "CustomScriptExtension" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", + "typeHandlerVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionCustomScriptConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '1.10'), createObject('value', '2.1')))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionCustomScriptConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionCustomScriptConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": { + "value": { + "copy": [ + { + "name": "fileUris", + "count": "[length(parameters('extensionCustomScriptConfig').fileData)]", + "input": "[if(contains(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')], 'storageAccountId'), format('{0}?{1}', parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri, listAccountSas(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].storageAccountId, '2019-04-01', variables('accountSasProperties')).accountSasToken), parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri)]" + } + ] + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": "[parameters('extensionCustomScriptProtectedSetting')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_desiredStateConfigurationExtension" + ] + }, + "vm_azureDiskEncryptionExtension": { + "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "AzureDiskEncryption" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", + "typeHandlerVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.2'), createObject('value', '1.1')))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "forceUpdateTag": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').forceUpdateTag), createObject('value', '1.0'))]", + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] + }, + "vm_nvidiaGpuDriverWindowsExtension": { + "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "NvidiaGpuDriverWindows" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.HpcCompute" + }, + "type": { + "value": "NvidiaGpuDriverWindows" + }, + "typeHandlerVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').typeHandlerVersion), createObject('value', '1.4'))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').enableAutomaticUpgrade), createObject('value', false()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureDiskEncryptionExtension" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the VM." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the VM." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the VM was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('vm', '2023-09-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vm', '2023-09-01', 'full').location]" + } + } + } + } + } + ] + } + } + }, + { + "condition": "[and(equals(parameters('storageService'), 'ANF'), not(contains(parameters('identityServiceProvider'), 'EntraID')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-ANF-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "accountName": { + "value": "[variables('varAnfAccountName')]" + }, + "capacityPoolName": { + "value": "[variables('varAnfCapacityPoolName')]" + }, + "volumes": { + "value": "[variables('varAnfVolumes')]" + }, + "smbServerNamePrefix": { + "value": "[variables('varAnfSmbServerNamePrefix')]" + }, + "capacityPoolSize": { + "value": "[variables('varAnfCapacityPoolSize')]" + }, + "dnsServers": { + "value": "[parameters('dnsServers')]" + }, + "performance": { + "value": "[parameters('fslogixStoragePerformance')]" + }, + "createFslogixStorage": { + "value": "[parameters('createFslogixDeployment')]" + }, + "createAppAttachStorage": { + "value": "[parameters('createAppAttachDeployment')]" + }, + "storageOuPath": "[if(not(empty(parameters('storageOuPath'))), createObject('value', parameters('storageOuPath')), createObject('value', variables('varDefaultStorageOuPath')))]", + "domainJoinUserName": { + "value": "[parameters('domainJoinUserName')]" + }, + "keyVaultResourceId": { + "value": "[parameters('keyVaultResourceId')]" + }, + "identityDomainName": { + "value": "[parameters('identityDomainName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "storageObjectsRgName": { + "value": "[parameters('storageObjectsRgName')]" + }, + "subId": { + "value": "[parameters('subId')]" + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "6273873211710387488" + }, + "name": "AVD LZA storage", + "description": "This module deploys ANF account, capacity pool and volumes", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "subId": { + "type": "string", + "metadata": { + "description": "Workload subscription ID" + } + }, + "storageObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name where to deploy Azure NetApp Files." + } + }, + "accountName": { + "type": "string", + "metadata": { + "description": "ANF account name." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Capacity pool volume name." + } + }, + "createFslogixStorage": { + "type": "bool", + "metadata": { + "description": "Capacity pool volume name." + } + }, + "createAppAttachStorage": { + "type": "bool", + "metadata": { + "description": "Capacity pool volume name." + } + }, + "volumes": { + "type": "array", + "metadata": { + "description": "ANF volumes." + } + }, + "smbServerNamePrefix": { + "type": "string", + "metadata": { + "description": "ANF SMB prefix." + } + }, + "dnsServers": { + "type": "string", + "metadata": { + "description": "DNS servers IPs." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy resources." + } + }, + "identityDomainName": { + "type": "string", + "metadata": { + "description": "Identity domain name." + } + }, + "storageOuPath": { + "type": "string", + "metadata": { + "description": "Organizational Unit (OU) storage path for domain join." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Keyvault resource ID to get credentials from." + } + }, + "domainJoinUserName": { + "type": "string", + "metadata": { + "description": "AVD session host domain join credentials." + } + }, + "performance": { + "type": "string", + "metadata": { + "description": "ANF performance tier." + } + }, + "capacityPoolSize": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "ANF capacity pool size in TiBs." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + } + }, + "variables": { + "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-ANF-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subId'))]", + "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('accountName')]" + }, + "adName": { + "value": "[parameters('accountName')]" + }, + "domainName": { + "value": "[parameters('identityDomainName')]" + }, + "domainJoinUser": { + "value": "[parameters('domainJoinUserName')]" + }, + "domainJoinPassword": { + "reference": { + "keyVault": { + "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))]" + }, + "secretName": "domainJoinUserPassword" + } + }, + "domainJoinOU": { + "value": "[format('CN={0}', parameters('storageOuPath'))]" + }, + "dnsServers": { + "value": "[parameters('dnsServers')]" + }, + "smbServerNamePrefix": { + "value": "[parameters('smbServerNamePrefix')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "capacityPools": { + "value": [ + { + "name": "[parameters('capacityPoolName')]", + "serviceLevel": "[parameters('performance')]", + "size": "[mul(parameters('capacityPoolSize'), 1073741824)]", + "volumes": "[parameters('volumes')]" + } + ] + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "943345456492784680" + }, + "name": "Azure NetApp Files", + "description": "This module deploys an Azure NetApp File." + }, + "definitions": { + "backupVaultType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "backups": { + "type": "array", + "items": { + "$ref": "#/definitions/backupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of backups to create." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the backup vault." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backup vault." + } + }, + "capacityPoolType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for the capcity pool." + } + }, + "serviceLevel": { + "type": "string", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "nullable": true, + "metadata": { + "description": "Optional. The pool service level." + } + }, + "size": { + "type": "int", + "metadata": { + "description": "Required. Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104)." + } + }, + "qosType": { + "type": "string", + "allowedValues": [ + "Auto", + "Manual" + ], + "nullable": true, + "metadata": { + "description": "Optional. The qos type of the pool." + } + }, + "volumes": { + "type": "array", + "items": { + "$ref": "#/definitions/volumeType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of volumes to create in the capacity pool." + } + }, + "coolAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "encryptionType": { + "type": "string", + "allowedValues": [ + "Double", + "Single" + ], + "nullable": true, + "metadata": { + "description": "Optional. Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a capacity pool." + } + }, + "snapshotPolicyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the snapshot policy." + } + }, + "dailySchedule": { + "$ref": "#/definitions/dailyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Daily schedule for the snapshot policy." + } + }, + "hourlySchedule": { + "$ref": "#/definitions/hourlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Hourly schedule for the snapshot policy." + } + }, + "monthlySchedule": { + "$ref": "#/definitions/monthlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Monthly schedule for the snapshot policy." + } + }, + "weeklySchedule": { + "$ref": "#/definitions/weeklyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Weekly schedule for the snapshot policy." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a snapshot policy." + } + }, + "backupPolicyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup policy." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location of the backup policy." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "nullable": true, + "minValue": 2, + "maxValue": 1019, + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backup policy." + } + }, + "_1.backupType": { + "type": "object", + "properties": { + "backupPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the backup policy to link." + } + }, + "policyEnforced": { + "type": "bool", + "metadata": { + "description": "Required. Enable to enforce the policy." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Backup Vault." + } + } + }, + "metadata": { + "description": "The type for the backup properties.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } + } + }, + "_1.dataProtectionType": { + "type": "object", + "properties": { + "replication": { + "$ref": "#/definitions/_1.replicationType", + "nullable": true, + "metadata": { + "description": "Optional. Replication properties." + } + }, + "backup": { + "$ref": "#/definitions/_1.backupType", + "nullable": true, + "metadata": { + "description": "Optional. Backup properties." + } + }, + "snapshot": { + "$ref": "#/definitions/_1.snapshotType", + "nullable": true, + "metadata": { + "description": "Optional. Snapshot properties." + } + } + }, + "metadata": { + "description": "The type for the data protection properties.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } + } + }, + "_1.exportPolicyType": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleIndex": { + "type": "int", + "metadata": { + "description": "Required. Order index." + } + }, + "allowedClients": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." + } + }, + "chownMode": { + "type": "string", + "allowedValues": [ + "Restricted", + "Unrestricted" + ], + "nullable": true, + "metadata": { + "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." + } + }, + "cifs": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allows CIFS protocol." + } + }, + "hasRootAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Has root access to volume." + } + }, + "kerberos5ReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read only access." + } + }, + "kerberos5ReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read and write access." + } + }, + "kerberos5iReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read only access." + } + }, + "kerberos5iReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read and write access." + } + }, + "kerberos5pReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read only access." + } + }, + "kerberos5pReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read and write access." + } + }, + "nfsv3": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." + } + }, + "nfsv41": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." + } + }, + "unixReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Read only access." + } + }, + "unixReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Read and write access." + } + } + } + }, + "metadata": { + "description": "Required. The Export policy rules." + } + } + }, + "metadata": { + "description": "The type for export policy rules.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } + } + }, + "_1.replicationType": { + "type": "object", + "properties": { + "endpointType": { + "type": "string", + "allowedValues": [ + "dst", + "src" + ], + "metadata": { + "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." + } + }, + "remoteVolumeRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." + } + }, + "remoteVolumeResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." + } + }, + "replicationSchedule": { + "type": "string", + "allowedValues": [ + "_10minutely", + "daily", + "hourly" + ], + "metadata": { + "description": "Required. The replication schedule for the volume." + } + }, + "remotePath": { + "type": "object", + "properties": { + "externalHostName": { + "type": "string", + "metadata": { + "description": "Required. The Path to a ONTAP Host." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Required. The name of a server on the ONTAP Host." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of a volume on the server." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." + } + } + }, + "metadata": { + "description": "The type for the replication properties.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } + } + }, + "_1.snapshotType": { + "type": "object", + "properties": { + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy to link." + } + } + }, + "metadata": { + "description": "The type for the snapshot properties.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/volume/main.bicep" + } + } + }, + "backupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "metadata": { + "description": "The type for a backup.", + "__bicep_imported_from!": { + "sourceTemplate": "backup-vault/main.bicep" + } + } + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "dailyScheduleType": { + "type": "object", + "properties": { + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The daily snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The daily snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Daily snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "description": "The type for a daily schedule for the snapshot policy.", + "__bicep_imported_from!": { + "sourceTemplate": "snapshot-policies/main.bicep" + } + } + }, + "hourlyScheduleType": { + "type": "object", + "properties": { + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The hourly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Hourly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "description": "The type for an hourly schedule for the snapshot policy.", + "__bicep_imported_from!": { + "sourceTemplate": "snapshot-policies/main.bicep" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "managedIdentityOnlyUserAssignedType": { + "type": "object", + "properties": { + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "monthlyScheduleType": { + "type": "object", + "properties": { + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Required. Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The monthly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The monthly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Monthly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "description": "The type for a monthly schedule for the snapshot policy.", + "__bicep_imported_from!": { + "sourceTemplate": "snapshot-policies/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "volumeType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the pool volume." + } + }, + "coolAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "coolnessPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." + } + }, + "coolAccessRetrievalPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." + } + }, + "encryptionKeySource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source of the encryption key." + } + }, + "keyVaultPrivateEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the key vault private endpoint." + } + }, + "dataProtection": { + "$ref": "#/definitions/_1.dataProtectionType", + "nullable": true, + "metadata": { + "description": "Optional. DataProtection type volumes include an object containing details of the replication." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. Zone where the volume will be placed." + } + }, + "serviceLevel": { + "type": "string", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "nullable": true, + "metadata": { + "description": "Optional. The pool service level. Must match the one of the parent capacity pool." + } + }, + "networkFeatures": { + "type": "string", + "allowedValues": [ + "Basic", + "Basic_Standard", + "Standard", + "Standard_Basic" + ], + "nullable": true, + "metadata": { + "description": "Optional. Network feature for the volume." + } + }, + "creationToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." + } + }, + "usageThreshold": { + "type": "int", + "metadata": { + "description": "Required. Maximum storage quota allowed for a file system in bytes." + } + }, + "protocolTypes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Set of protocol types." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." + } + }, + "exportPolicy": { + "$ref": "#/definitions/_1.exportPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Export policy rules." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "smbEncryption": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." + } + }, + "smbContinuouslyAvailable": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." + } + }, + "smbNonBrowsable": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." + } + }, + "kerberosEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Define if a volume is KerberosEnabled." + } + }, + "volumeType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of the volume. DataProtection volumes are used for replication." + } + } + }, + "metadata": { + "description": "The type for a volume in the capacity pool.", + "__bicep_imported_from!": { + "sourceTemplate": "capacity-pool/main.bicep" + } + } + }, + "weeklyScheduleType": { + "type": "object", + "properties": { + "day": { + "type": "string", + "allowedValues": [ + "Friday", + "Monday", + "Saturday", + "Sunday", + "Thursday", + "Tuesday", + "Wednesday" + ], + "metadata": { + "description": "Required. The weekly snapshot day." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The weekly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The weekly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Weekly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "description": "The type for a weekly schedule for the snapshot policy.", + "__bicep_imported_from!": { + "sourceTemplate": "snapshot-policies/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the NetApp account." + } + }, + "adName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the active directory host as part of Kerberos Realm used for Kerberos authentication." + } + }, + "aesEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable AES encryption on the SMB Server." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "domainName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Fully Qualified Active Directory DNS Domain Name (e.g. 'contoso.com')." + } + }, + "domainJoinUser": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if domainName is specified. Username of Active Directory domain administrator, with permissions to create SMB server machine account in the AD domain." + } + }, + "domainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if domainName is specified. Password of the user specified in domainJoinUser parameter." + } + }, + "domainJoinOU": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Used only if domainName is specified. LDAP Path for the Organization Unit (OU) where SMB Server machine accounts will be created (i.e. 'OU=SecondLevel,OU=FirstLevel')." + } + }, + "dnsServers": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if domainName is specified. Comma separated list of DNS server IP addresses (IPv4 only) required for the Active Directory (AD) domain join and SMB authentication operations to succeed." + } + }, + "encryptDCConnections": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether encryption should be used for communication between SMB server and domain controller (DC). SMB3 only." + } + }, + "smbServerNamePrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if domainName is specified. NetBIOS name of the SMB server. A computer account with this prefix will be registered in the AD and used to mount volumes." + } + }, + "capacityPools": { + "type": "array", + "items": { + "$ref": "#/definitions/capacityPoolType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Capacity pools to create." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlyUserAssignedType", + "nullable": true, + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "kdcIP": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Kerberos Key Distribution Center (KDC) as part of Kerberos Realm used for Kerberos authentication." + } + }, + "ldapOverTLS": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether to use TLS when NFS (with/without Kerberos) and SMB volumes communicate with an LDAP server. A server root CA certificate must be uploaded if enabled (serverRootCACertificate)." + } + }, + "ldapSigning": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether or not the LDAP traffic needs to be signed." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "serverRootCACertificate": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. A server Root certificate is required of ldapOverTLS is enabled." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "backupVault": { + "$ref": "#/definitions/backupVaultType", + "nullable": true, + "metadata": { + "description": "Optional. The netapp backup vault to create & configure." + } + }, + "snapshotPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/snapshotPolicyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The snapshot policies to create." + } + }, + "backupPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/backupPolicyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The backup policies to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "activeDirectoryConnectionProperties": [ + { + "adName": "[if(not(empty(parameters('domainName'))), parameters('adName'), null())]", + "aesEncryption": "[if(not(empty(parameters('domainName'))), parameters('aesEncryption'), false())]", + "username": "[if(not(empty(parameters('domainName'))), parameters('domainJoinUser'), null())]", + "password": "[if(not(empty(parameters('domainName'))), parameters('domainJoinPassword'), null())]", + "domain": "[if(not(empty(parameters('domainName'))), parameters('domainName'), null())]", + "dns": "[if(not(empty(parameters('domainName'))), parameters('dnsServers'), null())]", + "encryptDCConnections": "[if(not(empty(parameters('domainName'))), parameters('encryptDCConnections'), false())]", + "kdcIP": "[if(not(empty(parameters('domainName'))), parameters('kdcIP'), null())]", + "ldapOverTLS": "[if(not(empty(parameters('domainName'))), parameters('ldapOverTLS'), false())]", + "ldapSigning": "[if(not(empty(parameters('domainName'))), parameters('ldapSigning'), false())]", + "serverRootCACertificate": "[if(not(empty(parameters('domainName'))), parameters('serverRootCACertificate'), null())]", + "smbServerName": "[if(not(empty(parameters('domainName'))), parameters('smbServerNamePrefix'), null())]", + "organizationalUnit": "[if(not(empty(parameters('domainJoinOU'))), parameters('domainJoinOU'), null())]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None'), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.netapp-netappaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "netAppAccount": { + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "location": "[parameters('location')]", + "properties": { + "activeDirectories": "[if(not(empty(parameters('domainName'))), variables('activeDirectoryConnectionProperties'), null())]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('identity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), createObject('userAssignedIdentity', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/')))), null()), 'keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('keyName', parameters('customerManagedKey').keyName, 'keyVaultResourceId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]), 'Microsoft.KeyVault/vaults', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))), 'keyVaultUri', reference('cMKKeyVault').vaultUri)), null())]" + }, + "dependsOn": [ + "cMKKeyVault" + ] + }, + "netAppAccount_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "netAppAccount" + ] + }, + "netAppAccount_roleAssignments": { + "copy": { + "name": "netAppAccount_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "netAppAccount" + ] + }, + "netAppAccount_backupPolicies": { + "copy": { + "name": "netAppAccount_backupPolicies", + "count": "[length(coalesce(parameters('backupPolicies'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-backupPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'name')]" + }, + "dailyBackupsToKeep": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'dailyBackupsToKeep')]" + }, + "monthlyBackupsToKeep": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'monthlyBackupsToKeep')]" + }, + "weeklyBackupsToKeep": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'weeklyBackupsToKeep')]" + }, + "enabled": { + "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'enabled')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'location'), parameters('location'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "16432727764202874682" + }, + "name": "Azure NetApp Files Backup Policy", + "description": "This module deploys a Backup Policy for Azure NetApp File." + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "backupPolicy", + "metadata": { + "description": "Optional. The name of the backup policy." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the backup policy." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "defaultValue": 2, + "minValue": 2, + "maxValue": 1019, + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "enabled": "[parameters('enabled')]", + "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", + "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]", + "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the backup Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Backup Policy was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "netAppAccount" + ] + }, + "netAppAccount_snapshotPolicies": { + "copy": { + "name": "netAppAccount_snapshotPolicies", + "count": "[length(coalesce(parameters('snapshotPolicies'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-snapshotPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "snapEnabled": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'snapEnabled')]" + }, + "dailySchedule": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'dailySchedule')]" + }, + "hourlySchedule": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'hourlySchedule')]" + }, + "monthlySchedule": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'monthlySchedule')]" + }, + "weeklySchedule": { + "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'weeklySchedule')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "15408772009434991440" + }, + "name": "Azure NetApp Files Snapshot Policy", + "description": "This module deploys a Snapshot Policy for an Azure NetApp File." + }, + "definitions": { + "dailyScheduleType": { + "type": "object", + "properties": { + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The daily snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The daily snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Daily snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a daily schedule for the snapshot policy." + } + }, + "hourlyScheduleType": { + "type": "object", + "properties": { + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The hourly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Hourly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for an hourly schedule for the snapshot policy." + } + }, + "weeklyScheduleType": { + "type": "object", + "properties": { + "day": { + "type": "string", + "allowedValues": [ + "Friday", + "Monday", + "Saturday", + "Sunday", + "Thursday", + "Tuesday", + "Wednesday" + ], + "metadata": { + "description": "Required. The weekly snapshot day." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The weekly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The weekly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Weekly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a weekly schedule for the snapshot policy." + } + }, + "monthlyScheduleType": { + "type": "object", + "properties": { + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Required. Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'." + } + }, + "hour": { + "type": "int", + "minValue": 0, + "maxValue": 23, + "metadata": { + "description": "Required. The monthly snapshot hour." + } + }, + "minute": { + "type": "int", + "minValue": 0, + "maxValue": 59, + "metadata": { + "description": "Required. The monthly snapshot minute." + } + }, + "snapshotsToKeep": { + "type": "int", + "minValue": 1, + "maxValue": 255, + "metadata": { + "description": "Required. Monthly snapshot count to keep." + } + }, + "usedBytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a monthly schedule for the snapshot policy." + } + } + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "snapshotPolicy", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the snapshot policy." + } + }, + "hourlySchedule": { + "$ref": "#/definitions/hourlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for hourly snapshots." + } + }, + "dailySchedule": { + "$ref": "#/definitions/dailyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for daily snapshots." + } + }, + "monthlySchedule": { + "$ref": "#/definitions/monthlyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for monthly snapshots." + } + }, + "weeklySchedule": { + "$ref": "#/definitions/weeklyScheduleType", + "nullable": true, + "metadata": { + "description": "Optional. Schedule for weekly snapshots." + } + }, + "snapEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether the snapshot policy is enabled." + } + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "snapshotPolicies": { + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "enabled": "[parameters('snapEnabled')]", + "dailySchedule": "[parameters('dailySchedule')]", + "hourlySchedule": "[parameters('hourlySchedule')]", + "monthlySchedule": "[parameters('monthlySchedule')]", + "weeklySchedule": "[parameters('weeklySchedule')]" + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the snapshot Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Snapshot was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "netAppAccount" + ] + }, + "netAppAccount_backupVault": { + "condition": "[not(empty(parameters('backupVault')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-BackupVault', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(parameters('backupVault'), 'name')]" + }, + "location": { + "value": "[coalesce(tryGet(parameters('backupVault'), 'location'), parameters('location'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12673365749567452459" + }, + "name": "Azure NetApp Files Volume Backup Vault", + "description": "This module deploys a NetApp Files Backup Vault." + }, + "definitions": { + "backupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backup." + } + } + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "vault", + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the backup vault." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backups": { + "type": "array", + "items": { + "$ref": "#/definitions/backupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of backups to create." + } + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backupVault": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": {} + }, + "backupVault_backups": { + "copy": { + "name": "backupVault_backups", + "count": "[length(coalesce(parameters('backups'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANF-Backup-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "backupVaultName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'name')]" + }, + "label": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'label')]" + }, + "snapshotName": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'snapshotName')]" + }, + "volumeName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].volumeName]" + }, + "capacityPoolName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].capacityPoolName]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "2218257802133394577" + }, + "name": "Azure NetApp Files Volume Backup", + "description": "This module deploys a backup of a NetApp Files Volume." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "backup", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent backup vault. Required if the template is used in a standalone deployment." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "resources": { + "netAppAccount::remoteCapacityPool::volume": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + }, + "netAppAccount::backupVault": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupVaultName'))]" + }, + "netAppAccount::remoteCapacityPool": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" + }, + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backup": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults/backups", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]", + "properties": { + "label": "[parameters('label')]", + "snapshotName": "[parameters('snapshotName')]", + "volumeResourceId": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults/backups', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "backupVault" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup vault." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup vault." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup vault was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('backupVault', '2024-07-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "netAppAccount" + ] + }, + "netAppAccount_capacityPools": { + "copy": { + "name": "netAppAccount_capacityPools", + "count": "[length(coalesce(parameters('capacityPools'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-CapPool-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('capacityPools'), createArray())[copyIndex()].name]" + }, + "size": { + "value": "[coalesce(parameters('capacityPools'), createArray())[copyIndex()].size]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "serviceLevel": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'serviceLevel'), 'Standard')]" + }, + "qosType": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'qosType'), 'Auto')]" + }, + "volumes": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'volumes'), createArray())]" + }, + "coolAccess": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'coolAccess'), false())]" + }, + "roleAssignments": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'roleAssignments'), createArray())]" + }, + "encryptionType": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'encryptionType'), 'Single')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "8976617662375535030" + }, + "name": "Azure NetApp Files Capacity Pools", + "description": "This module deploys an Azure NetApp Files Capacity Pool." + }, + "definitions": { + "volumeType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the pool volume." + } + }, + "coolAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "coolnessPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." + } + }, + "coolAccessRetrievalPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." + } + }, + "encryptionKeySource": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source of the encryption key." + } + }, + "keyVaultPrivateEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the key vault private endpoint." + } + }, + "dataProtection": { + "$ref": "#/definitions/dataProtectionType", + "nullable": true, + "metadata": { + "description": "Optional. DataProtection type volumes include an object containing details of the replication." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. Zone where the volume will be placed." + } + }, + "serviceLevel": { + "type": "string", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "nullable": true, + "metadata": { + "description": "Optional. The pool service level. Must match the one of the parent capacity pool." + } + }, + "networkFeatures": { + "type": "string", + "allowedValues": [ + "Basic", + "Basic_Standard", + "Standard", + "Standard_Basic" + ], + "nullable": true, + "metadata": { + "description": "Optional. Network feature for the volume." + } + }, + "creationToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." + } + }, + "usageThreshold": { + "type": "int", + "metadata": { + "description": "Required. Maximum storage quota allowed for a file system in bytes." + } + }, + "protocolTypes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Set of protocol types." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." + } + }, + "exportPolicy": { + "$ref": "#/definitions/exportPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. Export policy rules." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "smbEncryption": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." + } + }, + "smbContinuouslyAvailable": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." + } + }, + "smbNonBrowsable": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." + } + }, + "kerberosEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Define if a volume is KerberosEnabled." + } + }, + "volumeType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of the volume. DataProtection volumes are used for replication." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a volume in the capacity pool." + } + }, + "_1.backupType": { + "type": "object", + "properties": { + "backupPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the backup policy to link." + } + }, + "policyEnforced": { + "type": "bool", + "metadata": { + "description": "Required. Enable to enforce the policy." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Backup Vault." + } + } + }, + "metadata": { + "description": "The type for the backup properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "_1.replicationType": { + "type": "object", + "properties": { + "endpointType": { + "type": "string", + "allowedValues": [ + "dst", + "src" + ], + "metadata": { + "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." + } + }, + "remoteVolumeRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." + } + }, + "remoteVolumeResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." + } + }, + "replicationSchedule": { + "type": "string", + "allowedValues": [ + "_10minutely", + "daily", + "hourly" + ], + "metadata": { + "description": "Required. The replication schedule for the volume." + } + }, + "remotePath": { + "type": "object", + "properties": { + "externalHostName": { + "type": "string", + "metadata": { + "description": "Required. The Path to a ONTAP Host." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Required. The name of a server on the ONTAP Host." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of a volume on the server." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." + } + } + }, + "metadata": { + "description": "The type for the replication properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "_1.snapshotType": { + "type": "object", + "properties": { + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy to link." + } + } + }, + "metadata": { + "description": "The type for the snapshot properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "dataProtectionType": { + "type": "object", + "properties": { + "replication": { + "$ref": "#/definitions/_1.replicationType", + "nullable": true, + "metadata": { + "description": "Optional. Replication properties." + } + }, + "backup": { + "$ref": "#/definitions/_1.backupType", + "nullable": true, + "metadata": { + "description": "Optional. Backup properties." + } + }, + "snapshot": { + "$ref": "#/definitions/_1.snapshotType", + "nullable": true, + "metadata": { + "description": "Optional. Snapshot properties." + } + } + }, + "metadata": { + "description": "The type for the data protection properties.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "exportPolicyType": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleIndex": { + "type": "int", + "metadata": { + "description": "Required. Order index." + } + }, + "allowedClients": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." + } + }, + "chownMode": { + "type": "string", + "allowedValues": [ + "Restricted", + "Unrestricted" + ], + "nullable": true, + "metadata": { + "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." + } + }, + "cifs": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allows CIFS protocol." + } + }, + "hasRootAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Has root access to volume." + } + }, + "kerberos5ReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read only access." + } + }, + "kerberos5ReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read and write access." + } + }, + "kerberos5iReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read only access." + } + }, + "kerberos5iReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read and write access." + } + }, + "kerberos5pReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read only access." + } + }, + "kerberos5pReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read and write access." + } + }, + "nfsv3": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." + } + }, + "nfsv41": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." + } + }, + "unixReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Read only access." + } + }, + "unixReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Read and write access." + } + } + } + }, + "metadata": { + "description": "Required. The Export policy rules." + } + } + }, + "metadata": { + "description": "The type for export policy rules.", + "__bicep_imported_from!": { + "sourceTemplate": "volume/main.bicep" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + } + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for all resources." + } + }, + "serviceLevel": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "metadata": { + "description": "Optional. The pool service level." + } + }, + "size": { + "type": "int", + "metadata": { + "description": "Required. Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104)." + } + }, + "qosType": { + "type": "string", + "defaultValue": "Auto", + "allowedValues": [ + "Auto", + "Manual" + ], + "metadata": { + "description": "Optional. The qos type of the pool." + } + }, + "volumes": { + "type": "array", + "items": { + "$ref": "#/definitions/volumeType" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of volumes to create in the capacity pool." + } + }, + "coolAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "encryptionType": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Double", + "Single" + ], + "metadata": { + "description": "Optional. Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "capacityPool": { + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "serviceLevel": "[parameters('serviceLevel')]", + "size": "[parameters('size')]", + "qosType": "[parameters('qosType')]", + "coolAccess": "[parameters('coolAccess')]", + "encryptionType": "[parameters('encryptionType')]" + } + }, + "capacityPool_roleAssignments": { + "copy": { + "name": "capacityPool_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}/capacityPools/{1}', parameters('netAppAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts/capacityPools', parameters('netAppAccountName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "capacityPool" + ] + }, + "capacityPool_volumes": { + "copy": { + "name": "capacityPool_volumes", + "count": "[length(coalesce(parameters('volumes'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Vol-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "capacityPoolName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "serviceLevel": { + "value": "[parameters('serviceLevel')]" + }, + "creationToken": { + "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'creationToken'), coalesce(parameters('volumes'), createArray())[copyIndex()].name)]" + }, + "usageThreshold": { + "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].usageThreshold]" + }, + "protocolTypes": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'protocolTypes')]" + }, + "subnetResourceId": { + "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].subnetResourceId]" + }, + "exportPolicy": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'exportPolicy')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "networkFeatures": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'networkFeatures')]" + }, + "zones": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'zones')]" + }, + "coolAccess": { + "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolAccess'), false())]" + }, + "coolAccessRetrievalPolicy": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolAccessRetrievalPolicy')]" + }, + "coolnessPeriod": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolnessPeriod')]" + }, + "encryptionKeySource": { + "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'encryptionKeySource'), 'Microsoft.NetApp')]" + }, + "keyVaultPrivateEndpointResourceId": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'keyVaultPrivateEndpointResourceId')]" + }, + "dataProtection": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'dataProtection')]" + }, + "kerberosEnabled": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'kerberosEnabled')]" + }, + "smbContinuouslyAvailable": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbContinuouslyAvailable')]" + }, + "smbEncryption": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbEncryption')]" + }, + "smbNonBrowsable": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbNonBrowsable')]" + }, + "volumeType": { + "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'volumeType')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "17068369293044189585" + }, + "name": "Azure NetApp Files Capacity Pool Volumes", + "description": "This module deploys an Azure NetApp Files Capacity Pool Volume." + }, + "definitions": { + "dataProtectionType": { + "type": "object", + "properties": { + "replication": { + "$ref": "#/definitions/replicationType", + "nullable": true, + "metadata": { + "description": "Optional. Replication properties." + } + }, + "backup": { + "$ref": "#/definitions/backupType", + "nullable": true, + "metadata": { + "description": "Optional. Backup properties." + } + }, + "snapshot": { + "$ref": "#/definitions/snapshotType", + "nullable": true, + "metadata": { + "description": "Optional. Snapshot properties." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for the data protection properties." + } + }, + "replicationType": { + "type": "object", + "properties": { + "endpointType": { + "type": "string", + "allowedValues": [ + "dst", + "src" + ], + "metadata": { + "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." + } + }, + "remoteVolumeRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." + } + }, + "remoteVolumeResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." + } + }, + "replicationSchedule": { + "type": "string", + "allowedValues": [ + "_10minutely", + "daily", + "hourly" + ], + "metadata": { + "description": "Required. The replication schedule for the volume." + } + }, + "remotePath": { + "type": "object", + "properties": { + "externalHostName": { + "type": "string", + "metadata": { + "description": "Required. The Path to a ONTAP Host." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Required. The name of a server on the ONTAP Host." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of a volume on the server." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." + } + } + }, + "metadata": { + "description": "The type for the replication properties." + } + }, + "backupType": { + "type": "object", + "properties": { + "backupPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the backup policy to link." + } + }, + "policyEnforced": { + "type": "bool", + "metadata": { + "description": "Required. Enable to enforce the policy." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Backup Vault." + } + } + }, + "metadata": { + "description": "The type for the backup properties." + } + }, + "snapshotType": { + "type": "object", + "properties": { + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the snapshot policy to link." + } + } + }, + "metadata": { + "description": "The type for the snapshot properties." + } + }, + "exportPolicyType": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleIndex": { + "type": "int", + "metadata": { + "description": "Required. Order index." + } + }, + "allowedClients": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." + } + }, + "chownMode": { + "type": "string", + "allowedValues": [ + "Restricted", + "Unrestricted" + ], + "nullable": true, + "metadata": { + "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." + } + }, + "cifs": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allows CIFS protocol." + } + }, + "hasRootAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Has root access to volume." + } + }, + "kerberos5ReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read only access." + } + }, + "kerberos5ReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5 Read and write access." + } + }, + "kerberos5iReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read only access." + } + }, + "kerberos5iReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5i Read and write access." + } + }, + "kerberos5pReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read only access." + } + }, + "kerberos5pReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Kerberos5p Read and write access." + } + }, + "nfsv3": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." + } + }, + "nfsv41": { + "type": "bool", + "metadata": { + "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." + } + }, + "unixReadOnly": { + "type": "bool", + "metadata": { + "description": "Required. Read only access." + } + }, + "unixReadWrite": { + "type": "bool", + "metadata": { + "description": "Required. Read and write access." + } + } + } + }, + "metadata": { + "description": "Required. The Export policy rules." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for export policy rules." + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + } + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent capacity pool. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the pool volume." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the pool volume." + } + }, + "coolAccess": { + "type": "bool", + "metadata": { + "description": "Required. If enabled (true) the pool can contain cool Access enabled volumes." + } + }, + "coolnessPeriod": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." + } + }, + "coolAccessRetrievalPolicy": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." + } + }, + "encryptionKeySource": { + "type": "string", + "metadata": { + "description": "Required. The source of the encryption key." + } + }, + "keyVaultPrivateEndpointResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the key vault private endpoint." + } + }, + "volumeType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of the volume. DataProtection volumes are used for replication." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. Zone where the volume will be placed." + } + }, + "serviceLevel": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Premium", + "Standard", + "StandardZRS", + "Ultra" + ], + "metadata": { + "description": "Optional. The pool service level. Must match the one of the parent capacity pool." + } + }, + "networkFeatures": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Basic_Standard", + "Standard", + "Standard_Basic" + ], + "metadata": { + "description": "Optional. Network feature for the volume." + } + }, + "creationToken": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." + } + }, + "usageThreshold": { + "type": "int", + "metadata": { + "description": "Required. Maximum storage quota allowed for a file system in bytes." + } + }, + "protocolTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Set of protocol types." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." + } + }, + "exportPolicy": { + "$ref": "#/definitions/exportPolicyType", + "nullable": true, + "metadata": { + "description": "Optional. The export policy rules." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "dataProtection": { + "$ref": "#/definitions/dataProtectionType", + "nullable": true, + "metadata": { + "description": "Optional. DataProtection type volumes include an object containing details of the replication." + } + }, + "smbEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." + } + }, + "smbContinuouslyAvailable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." + } + }, + "smbNonBrowsable": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." + } + }, + "kerberosEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Define if a volume is KerberosEnabled." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "remoteCapacityPoolName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], '')]", + "remoteNetAppName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], '')]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "netAppAccount::capacityPool": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" + }, + "netAppAccount::backupVault": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))]" + }, + "netAppAccount::backupPolicy": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName'))]" + }, + "netAppAccount::snapshotPolicy": { + "condition": "[not(empty(tryGet(parameters('dataProtection'), 'snapshot')))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))]" + }, + "remoteNetAppAccount::remoteCapacityPool::remoteVolume": { + "condition": "[and(and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName'))))), not(empty(tryGet(parameters('dataProtection'), 'replication'))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}/{2}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/')))]" + }, + "remoteNetAppAccount::remoteCapacityPool": { + "condition": "[and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName')))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10])]" + }, + "vnet::subnet": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/')))]" + }, + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "keyVaultPrivateEndpoint": { + "condition": "[not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp'))]", + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/'))]" + }, + "remoteNetAppAccount": { + "condition": "[and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName'))))]", + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", + "name": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8]]" + }, + "vnet": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-03-01", + "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", + "name": "[split(parameters('subnetResourceId'), '/')[8]]" + }, + "volume": { + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": "[shallowMerge(createArray(createObject('coolAccess', parameters('coolAccess'), 'coolAccessRetrievalPolicy', parameters('coolAccessRetrievalPolicy'), 'coolnessPeriod', parameters('coolnessPeriod'), 'encryptionKeySource', parameters('encryptionKeySource')), if(not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp')), createObject('keyVaultPrivateEndpointResourceId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2], split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]), 'Microsoft.Network/privateEndpoints', last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/')))), createObject()), if(not(empty(parameters('volumeType'))), createObject('volumeType', parameters('volumeType')), createObject()), createObject('dataProtection', if(not(empty(parameters('dataProtection'))), createObject('replication', if(not(empty(tryGet(parameters('dataProtection'), 'replication'))), createObject('endpointType', tryGet(parameters('dataProtection'), 'replication', 'endpointType'), 'remoteVolumeRegion', if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]), 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/'))), null()), 'remoteVolumeResourceId', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'replicationSchedule', tryGet(parameters('dataProtection'), 'replication', 'replicationSchedule'), 'remotePath', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remotePath')), createObject()), 'backup', if(not(empty(tryGet(parameters('dataProtection'), 'backup'))), createObject('backupPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName')), 'policyEnforced', coalesce(tryGet(parameters('dataProtection'), 'backup', 'policyEnforced'), false()), 'backupVaultId', resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))), createObject()), 'snapshot', if(not(empty(tryGet(parameters('dataProtection'), 'snapshot'))), createObject('snapshotPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))), createObject())), null()), 'networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('subnetResourceId'), '/')[2], split(parameters('subnetResourceId'), '/')[4]), 'Microsoft.Network/virtualNetworks/subnets', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/'))), 'exportPolicy', parameters('exportPolicy'), 'smbContinuouslyAvailable', parameters('smbContinuouslyAvailable'), 'smbEncryption', parameters('smbEncryption'), 'smbNonBrowsable', parameters('smbNonBrowsable'), 'kerberosEnabled', parameters('kerberosEnabled'))))]", + "zones": "[map(parameters('zones'), lambda('zone', format('{0}', lambdaVariables('zone'))))]" + }, + "volume_roleAssignments": { + "copy": { + "name": "volume_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}/capacityPools/{1}/volumes/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "volume" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Volume." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the Volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Volume was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('volume', '2024-07-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "capacityPool" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Capacity Pool." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Capacity Pool." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools', parameters('netAppAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Capacity Pool was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('capacityPool', '2024-07-01', 'full').location]" + }, + "volumeResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the volume created in the capacity pool." + }, + "copy": { + "count": "[length(coalesce(parameters('volumes'), createArray()))]", + "input": "[reference(format('capacityPool_volumes[{0}]', copyIndex())).outputs.resourceId.value]" + } + } + } + } + }, + "dependsOn": [ + "netAppAccount", + "netAppAccount_backupPolicies", + "netAppAccount_backupVault", + "netAppAccount_snapshotPolicies" + ] + }, + "netAppAccount_backupVaultBackups": { + "condition": "[not(empty(tryGet(parameters('backupVault'), 'backups')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANFAccount-BackupVault-Backups', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(parameters('backupVault'), 'name')]" + }, + "backups": { + "value": "[tryGet(parameters('backupVault'), 'backups')]" + }, + "location": { + "value": "[coalesce(tryGet(parameters('backupVault'), 'location'), parameters('location'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12673365749567452459" + }, + "name": "Azure NetApp Files Volume Backup Vault", + "description": "This module deploys a NetApp Files Backup Vault." + }, + "definitions": { + "backupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type for a backup." + } + } + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "vault", + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location of the backup vault." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backups": { + "type": "array", + "items": { + "$ref": "#/definitions/backupType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of backups to create." + } + } + }, + "resources": { + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backupVault": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": {} + }, + "backupVault_backups": { + "copy": { + "name": "backupVault_backups", + "count": "[length(coalesce(parameters('backups'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ANF-Backup-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "backupVaultName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'name')]" + }, + "label": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'label')]" + }, + "snapshotName": { + "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'snapshotName')]" + }, + "volumeName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].volumeName]" + }, + "capacityPoolName": { + "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].capacityPoolName]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "2218257802133394577" + }, + "name": "Azure NetApp Files Volume Backup", + "description": "This module deploys a backup of a NetApp Files Volume." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "backup", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent backup vault. Required if the template is used in a standalone deployment." + } + }, + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "label": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Label for backup." + } + }, + "snapshotName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume to backup." + } + }, + "capacityPoolName": { + "type": "string", + "metadata": { + "description": "Required. The name of the capacity pool containing the volume." + } + } + }, + "resources": { + "netAppAccount::remoteCapacityPool::volume": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + }, + "netAppAccount::backupVault": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/backupVaults", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupVaultName'))]" + }, + "netAppAccount::remoteCapacityPool": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts/capacityPools", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" + }, + "netAppAccount": { + "existing": true, + "type": "Microsoft.NetApp/netAppAccounts", + "apiVersion": "2024-07-01", + "name": "[parameters('netAppAccountName')]" + }, + "backup": { + "type": "Microsoft.NetApp/netAppAccounts/backupVaults/backups", + "apiVersion": "2024-07-01", + "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]", + "properties": { + "label": "[parameters('label')]", + "snapshotName": "[parameters('snapshotName')]", + "volumeResourceId": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults/backups', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "backupVault" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the backup vault." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the backup vault." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the backup vault was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('backupVault', '2024-07-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "netAppAccount", + "netAppAccount_capacityPools" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the NetApp account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the NetApp account." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the NetApp account was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('netAppAccount', '2024-07-01', 'full').location]" + }, + "capacityPoolResourceIds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "resourceId": { + "type": "string" + }, + "volumeResourceIds": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "metadata": { + "description": "The resource IDs of the created capacity pools & their volumes." + }, + "copy": { + "count": "[length(coalesce(parameters('capacityPools'), createArray()))]", + "input": { + "resourceId": "[reference(format('netAppAccount_capacityPools[{0}]', copyIndex())).outputs.resourceId.value]", + "volumeResourceIds": "[reference(format('netAppAccount_capacityPools[{0}]', copyIndex())).outputs.volumeResourceIds.value]" + } + } + } + } + } + } + } + ], + "outputs": { + "anfFslogixVolumeResourceId": { + "type": "string", + "value": "[if(parameters('createFslogixStorage'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.capacityPoolResourceIds.value[0].volumeResourceIds[0], '')]" + }, + "anfAppAttachVolumeResourceId": { + "type": "string", + "value": "[if(and(parameters('createAppAttachStorage'), parameters('createFslogixStorage')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.capacityPoolResourceIds.value[1].volumeResourceIds[1], if(and(parameters('createAppAttachStorage'), not(parameters('createFslogixStorage'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.capacityPoolResourceIds.value[0].volumeResourceIds[0], ''))]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]" + ] + }, + { + "condition": "[equals(parameters('storageService'), 'ANF')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Get-ANF-SMB-Server-FQDN-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "netAppVolumeResourceId": "[if(and(parameters('createFslogixDeployment'), equals(parameters('storageService'), 'ANF')), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfFslogixVolumeResourceId.value), if(and(parameters('createAppAttachDeployment'), equals(parameters('storageService'), 'ANF')), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfAppAttachVolumeResourceId.value), createObject('value', '')))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "1092509597594508559" + }, + "name": "AVD LZA storage ANF volume SMB server FQDN", + "description": "This module returns the SMB server FQDN of an ANF volume.", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "netAppVolumeResourceId": { + "type": "string" + } + }, + "resources": [], + "outputs": { + "anfSmbServerFqdn": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('netAppVolumeResourceId'), '/')[2], split(parameters('netAppVolumeResourceId'), '/')[4]), 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', split(parameters('netAppVolumeResourceId'), '/')[8], split(parameters('netAppVolumeResourceId'), '/')[10], last(split(parameters('netAppVolumeResourceId'), '/'))), '2024-09-01').mountTargets[0].smbServerFqdn]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time')))]" + ] + }, + { + "condition": "[and(parameters('createFslogixDeployment'), not(equals(parameters('storageService'), 'ANF')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-FSLogix-ST-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storagePurpose": { + "value": "fslogix" + }, + "vmLocalUserName": { + "value": "[parameters('vmLocalUserName')]" + }, + "fileShareName": { + "value": "[variables('varFslogixFileShareName')]" + }, + "fileShareMultichannel": "[if(equals(variables('varFslogixStoragePerformance'), 'Premium'), createObject('value', true()), createObject('value', false()))]", + "storageSku": { + "value": "[variables('varFslogixStorageSku')]" + }, + "fileShareQuotaSize": { + "value": "[parameters('fslogixFileShareQuotaSize')]" + }, + "storageAccountFqdn": { + "value": "[variables('varFslogixStorageFqdn')]" + }, + "storageAccountName": { + "value": "[variables('varFslogixStorageName')]" + }, + "storageToDomainScript": { + "value": "[variables('varStorageToDomainScript')]" + }, + "storageToDomainScriptUri": { + "value": "[variables('varStorageToDomainScriptUri')]" + }, + "identityServiceProvider": { + "value": "[parameters('identityServiceProvider')]" + }, + "dscAgentPackageLocation": { + "value": "[variables('varStorageAzureFilesDscAgentPackageLocation')]" + }, + "storageCustomOuPath": { + "value": "[variables('varStorageCustomOuPath')]" + }, + "managementVmName": { + "value": "[variables('varManagementVmName')]" + }, + "deployPrivateEndpoint": { + "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" + }, + "keyVaultResourceId": { + "value": "[parameters('keyVaultResourceId')]" + }, + "storageOuPath": { + "value": "[variables('varOuStgPath')]" + }, + "managedIdentityClientId": { + "value": "[parameters('managedIdentityClientId')]" + }, + "securityPrincipalName": { + "value": "[parameters('securityPrincipalName')]" + }, + "domainJoinUserName": { + "value": "[parameters('domainJoinUserName')]" + }, + "serviceObjectsRgName": { + "value": "[parameters('serviceObjectsRgName')]" + }, + "identityDomainName": { + "value": "[parameters('identityDomainName')]" + }, + "identityDomainGuid": { + "value": "[parameters('identityDomainGuid')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "storageObjectsRgName": { + "value": "[parameters('storageObjectsRgName')]" + }, + "privateEndpointSubnetResourceId": { + "value": "[parameters('privateEndpointSubnetResourceId')]" + }, + "vmsSubnetResourceId": { + "value": "[parameters('vmsSubnetResourceId')]" + }, + "privateDnsZoneFilesResourceId": { + "value": "[parameters('privateDnsZoneFilesResourceId')]" + }, + "subId": { + "value": "[parameters('subId')]" + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]", + "alaWorkspaceResourceId": { + "value": "[parameters('alaWorkspaceResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4958601852198550361" + }, + "name": "AVD LZA storage", + "description": "This module deploys storage account, azure files. domain join logic", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "subId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "storageObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name for Azure Files." + } + }, + "identityServiceProvider": { + "type": "string", + "metadata": { + "description": "Required, The service providing domain services for Azure Virtual Desktop." + } + }, + "serviceObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name for management VM." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Storage account name." + } + }, + "fileShareName": { + "type": "string", + "metadata": { + "description": "Storage account file share name." + } + }, + "privateEndpointSubnetResourceId": { + "type": "string", + "metadata": { + "description": "Private endpoint subnet ID." + } + }, + "vmsSubnetResourceId": { + "type": "string", + "metadata": { + "description": "VMs subnet ID." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy resources." + } + }, + "fileShareMultichannel": { + "type": "bool", + "metadata": { + "description": "File share SMB multichannel." + } + }, + "identityDomainName": { + "type": "string", + "metadata": { + "description": "Identity domain name." + } + }, + "identityDomainGuid": { + "type": "string", + "metadata": { + "description": "AD domain GUID." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Key Vault Resource ID." + } + }, + "domainJoinUserName": { + "type": "string", + "metadata": { + "description": "AVD session host domain join credentials." + } + }, + "vmLocalUserName": { + "type": "string", + "metadata": { + "description": "AVD session host local admin credentials." + } + }, + "storageSku": { + "type": "string", + "metadata": { + "description": "Azure Files storage account SKU." + } + }, + "fileShareQuotaSize": { + "type": "int", + "metadata": { + "description": "*Azure File share quota" + } + }, + "privateDnsZoneFilesResourceId": { + "type": "string", + "metadata": { + "description": "Use Azure private DNS zones for private endpoints." + } + }, + "storageToDomainScript": { + "type": "string", + "metadata": { + "description": "Script name for adding storage account to Active Directory." + } + }, + "storageToDomainScriptUri": { + "type": "string", + "metadata": { + "description": "URI for the script for adding the storage account to Active Directory." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "managementVmName": { + "type": "string", + "metadata": { + "description": "Name for management virtual machine. for tools and to join Azure Files to domain." + } + }, + "deployPrivateEndpoint": { + "type": "bool", + "metadata": { + "description": "Optional. AVD Accelerator will deploy with private endpoints by default." + } + }, + "alaWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Log analytics workspace for diagnostic logs." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + }, + "storagePurpose": { + "type": "string", + "metadata": { + "description": "Sets purpose of the storage account." + } + }, + "dscAgentPackageLocation": { + "type": "string", + "metadata": { + "description": "Sets location of DSC Agent." + } + }, + "storageCustomOuPath": { + "type": "string", + "metadata": { + "description": "Custom OU path for storage." + } + }, + "storageOuPath": { + "type": "string", + "metadata": { + "description": "OU Storage Path" + } + }, + "managedIdentityClientId": { + "type": "string", + "metadata": { + "description": "Managed Identity Client ID" + } + }, + "securityPrincipalName": { + "type": "string", + "metadata": { + "description": "Identity name array to grant RBAC role to access AVD application group and NTFS permissions." + } + }, + "storageAccountFqdn": { + "type": "string", + "metadata": { + "description": "storage account FDQN." + } + } + }, + "variables": { + "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]", + "varAzureCloudName": "[environment().name]", + "varWrklStoragePrivateEndpointName": "[format('pe-{0}-file', parameters('storageAccountName'))]", + "varSecurityPrincipalName": "[if(not(empty(parameters('securityPrincipalName'))), parameters('securityPrincipalName'), 'none')]", + "varAdminUserName": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('vmLocalUserName'), parameters('domainJoinUserName'))]", + "varStorageToDomainScriptArgs": "[format('-DscPath {0} -StorageAccountName {1} -StorageAccountRG {2} -StoragePurpose {3} -DomainName {4} -IdentityServiceProvider {5} -AzureCloudEnvironment {6} -SubscriptionId {7} -AdminUserName {8} -CustomOuPath {9} -OUName {10} -ShareName {11} -ClientId {12} -SecurityPrincipalName \"{13}\" -StorageAccountFqdn {14} ', parameters('dscAgentPackageLocation'), parameters('storageAccountName'), parameters('storageObjectsRgName'), parameters('storagePurpose'), parameters('identityDomainName'), parameters('identityServiceProvider'), variables('varAzureCloudName'), parameters('subId'), variables('varAdminUserName'), parameters('storageCustomOuPath'), parameters('storageOuPath'), parameters('fileShareName'), parameters('managedIdentityClientId'), variables('varSecurityPrincipalName'), parameters('storageAccountFqdn'))]", + "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subId'))]", + "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('storageAccountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": { + "value": "[parameters('storageSku')]" + }, + "allowBlobPublicAccess": { + "value": false + }, + "publicNetworkAccess": "[if(parameters('deployPrivateEndpoint'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "kind": "[if(or(equals(parameters('storageSku'), 'Premium_LRS'), equals(parameters('storageSku'), 'Premium_ZRS')), createObject('value', 'FileStorage'), createObject('value', 'StorageV2'))]", + "largeFileSharesState": "[if(or(equals(parameters('storageSku'), 'Standard_LRS'), equals(parameters('storageSku'), 'Standard_ZRS')), createObject('value', 'Enabled'), createObject('value', 'Disabled'))]", + "azureFilesIdentityBasedAuthentication": "[if(not(equals(parameters('identityServiceProvider'), 'EntraID')), createObject('value', createObject('directoryServiceOptions', if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDS', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), 'AADKERB', 'none')), 'activeDirectoryProperties', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), createObject('domainGuid', parameters('identityDomainGuid'), 'domainName', parameters('identityDomainName')), createObject()))), createObject('value', null()))]", + "accessTier": { + "value": "Hot" + }, + "networkAcls": "[if(parameters('deployPrivateEndpoint'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', parameters('vmsSubnetResourceId'), 'action', 'Allow')), 'ipRules', createArray())))]", + "fileServices": { + "value": { + "shares": [ + { + "name": "[parameters('fileShareName')]", + "shareQuota": "[parameters('fileShareQuotaSize')]" + } + ], + "protocolSettings": "[if(parameters('fileShareMultichannel'), createObject('smb', createObject('multichannel', createObject('enabled', parameters('fileShareMultichannel')))), createObject())]", + "diagnosticSettings": "[variables('varDiagnosticSettings')]" + } + }, + "privateEndpoints": "[if(parameters('deployPrivateEndpoint'), createObject('value', createArray(createObject('name', variables('varWrklStoragePrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklStoragePrivateEndpointName')), 'service', 'file', 'privateDnsZoneGroupName', split(parameters('privateDnsZoneFilesResourceId'), '/')[8], 'privateDnsZoneResourceIds', createArray(parameters('privateDnsZoneFilesResourceId'))))), createObject('value', createArray()))]", + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "15994741654178645865" + }, + "name": "Storage Accounts", + "description": "This module deploys a Storage Account.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + } + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Manual PrivateLink Service Connections." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Storage Account. Must be lower-case." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], + "metadata": { + "description": "Optional. Type of Storage Account to create." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS", + "Premium_ZRS", + "Standard_GZRS", + "Standard_RAGZRS" + ], + "metadata": { + "description": "Optional. Storage Account Sku Name." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool" + ], + "metadata": { + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + } + }, + "largeFileSharesState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + } + }, + "azureFilesIdentityBasedAuthentication": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Provides the identity based authentication settings for Azure Files." + } + }, + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "managementPolicyRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The Storage Account ManagementPolicies Rules." + } + }, + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + } + }, + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + } + }, + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + } + }, + "dnsEndpointType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." + } + }, + "blobServices": { + "type": "object", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", + "metadata": { + "description": "Optional. Blob service and containers to deploy." + } + }, + "fileServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_0", + "TLS1_1", + "TLS1_2" + ], + "metadata": { + "description": "Optional. Set the minimum TLS version on request to storage." + } + }, + "enableHierarchicalNamespace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + } + }, + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables local users feature, if set to true." + } + }, + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "allowedCopyScope": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AAD", + "PrivateLink" + ], + "metadata": { + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } + } + }, + "variables": { + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", + "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", + "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", + "customDomain": { + "name": "[parameters('customDomainName')]", + "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" + }, + "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", + "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", + "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", + "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", + "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", + "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", + "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", + "isSftpEnabled": "[parameters('enableSftp')]", + "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", + "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", + "minimumTlsVersion": "[parameters('minimumTlsVersion')]", + "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", + "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_privateEndpoints": { + "copy": { + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "5572402757180298542" + }, + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Protocol settings for file service." + } + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "defaultValue": { + "enabled": true, + "days": 7 + }, + "metadata": { + "description": "Optional. The service properties for soft delete." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + } + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "2846593244669729605" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "TransactionOptimized", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" + } + }, + "fileShare_roleAssignments": { + "condition": "[not(empty(parameters('roleAssignments')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "fileShareResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "11422901802944437310" + } + }, + "parameters": { + "roleAssignments": { + "type": "array", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "fileShareResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the file share to assign the roles to." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "description": "[[parameters('description')]", + "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + }, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": [ + { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2021-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" + }, + "name": { + "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" + }, + "roleDefinitionId": { + "value": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]" + }, + "principalId": { + "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "condition": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": { + "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" + }, + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + } + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "fileServices", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed storage account." + }, + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2022-09-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[not(equals(parameters('identityServiceProvider'), 'EntraID'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Add-{0}-Storage-Setup-{1}', parameters('storagePurpose'), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "virtualMachineName": { + "value": "[parameters('managementVmName')]" + }, + "file": { + "value": "[parameters('storageToDomainScript')]" + }, + "scriptArguments": { + "value": "[variables('varStorageToDomainScriptArgs')]" + }, + "adminUserPassword": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'vmLocalUserPassword')), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'domainJoinUserPassword')))]", + "baseScriptUri": { + "value": "[parameters('storageToDomainScriptUri')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "7337889415739790800" + }, + "name": "AVD LZA storage", + "description": "Configures domain join settings on storage account via VM custom script extension", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Virtual machine name." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy compute services." + } + }, + "baseScriptUri": { + "type": "string", + "metadata": { + "description": "Location for the AVD agent installation package." + } + }, + "file": { + "type": "string" + }, + "scriptArguments": { + "type": "string", + "metadata": { + "description": "Arguments for domain join script." + } + }, + "adminUserPassword": { + "type": "securestring", + "metadata": { + "description": "Domain join user password." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('VM-Ext-AVM-{0}', parameters('time'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "AzureFilesDomainJoin" + }, + "virtualMachineName": { + "value": "[parameters('virtualMachineName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "CustomScriptExtension" + }, + "typeHandlerVersion": { + "value": "1.10" + }, + "autoUpgradeMinorVersion": { + "value": true + }, + "enableAutomaticUpgrade": { + "value": false + }, + "settings": { + "value": {} + }, + "protectedSettings": { + "value": { + "fileUris": "[array(parameters('baseScriptUri'))]", + "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -File {0} {1} -AdminUserPassword {2} -verbose', parameters('file'), parameters('scriptArguments'), parameters('adminUserPassword'))]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time')))]" + ] + } + ], + "outputs": { + "storageAccountResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))), '2022-09-01').outputs.resourceId.value]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]" + ] + }, + { + "condition": "[and(parameters('createFslogixDeployment'), not(equals(parameters('storageService'), 'ANF')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-AppA-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storagePurpose": { + "value": "AppAttach" + }, + "vmLocalUserName": { + "value": "[parameters('vmLocalUserName')]" + }, + "fileShareName": { + "value": "[variables('varAppAttachFileShareName')]" + }, + "fileShareMultichannel": "[if(equals(variables('varAppAttachStoragePerformance'), 'Premium'), createObject('value', true()), createObject('value', false()))]", + "storageSku": { + "value": "[variables('varAppAttachStorageSku')]" + }, + "fileShareQuotaSize": { + "value": "[parameters('appAttachFileShareQuotaSize')]" + }, + "storageAccountFqdn": { + "value": "[variables('varAppAttachStorageFqdn')]" + }, + "storageAccountName": { + "value": "[variables('varAppAttachStorageName')]" + }, + "storageToDomainScript": { + "value": "[variables('varStorageToDomainScript')]" + }, + "storageToDomainScriptUri": { + "value": "[variables('varStorageToDomainScriptUri')]" + }, + "identityServiceProvider": { + "value": "[parameters('identityServiceProvider')]" + }, + "dscAgentPackageLocation": { + "value": "[variables('varStorageAzureFilesDscAgentPackageLocation')]" + }, + "storageCustomOuPath": { + "value": "[variables('varStorageCustomOuPath')]" + }, + "managementVmName": { + "value": "[variables('varManagementVmName')]" + }, + "deployPrivateEndpoint": { + "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" + }, + "storageOuPath": { + "value": "[variables('varOuStgPath')]" + }, + "managedIdentityClientId": { + "value": "[parameters('managedIdentityClientId')]" + }, + "securityPrincipalName": { + "value": "[parameters('securityPrincipalName')]" + }, + "domainJoinUserName": { + "value": "[parameters('domainJoinUserName')]" + }, + "keyVaultResourceId": { + "value": "[parameters('keyVaultResourceId')]" + }, + "serviceObjectsRgName": { + "value": "[parameters('serviceObjectsRgName')]" + }, + "identityDomainName": { + "value": "[parameters('identityDomainName')]" + }, + "identityDomainGuid": { + "value": "[parameters('identityDomainGuid')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "storageObjectsRgName": { + "value": "[parameters('storageObjectsRgName')]" + }, + "privateEndpointSubnetResourceId": { + "value": "[parameters('privateEndpointSubnetResourceId')]" + }, + "vmsSubnetResourceId": { + "value": "[parameters('vmsSubnetResourceId')]" + }, + "privateDnsZoneFilesResourceId": { + "value": "[parameters('privateDnsZoneFilesResourceId')]" + }, + "subId": { + "value": "[parameters('subId')]" + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]", + "alaWorkspaceResourceId": { + "value": "[parameters('alaWorkspaceResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4958601852198550361" + }, + "name": "AVD LZA storage", + "description": "This module deploys storage account, azure files. domain join logic", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "subId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "storageObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name for Azure Files." + } + }, + "identityServiceProvider": { + "type": "string", + "metadata": { + "description": "Required, The service providing domain services for Azure Virtual Desktop." + } + }, + "serviceObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name for management VM." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Storage account name." + } + }, + "fileShareName": { + "type": "string", + "metadata": { + "description": "Storage account file share name." + } + }, + "privateEndpointSubnetResourceId": { + "type": "string", + "metadata": { + "description": "Private endpoint subnet ID." + } + }, + "vmsSubnetResourceId": { + "type": "string", + "metadata": { + "description": "VMs subnet ID." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy resources." + } + }, + "fileShareMultichannel": { + "type": "bool", + "metadata": { + "description": "File share SMB multichannel." + } + }, + "identityDomainName": { + "type": "string", + "metadata": { + "description": "Identity domain name." + } + }, + "identityDomainGuid": { + "type": "string", + "metadata": { + "description": "AD domain GUID." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Key Vault Resource ID." + } + }, + "domainJoinUserName": { + "type": "string", + "metadata": { + "description": "AVD session host domain join credentials." + } + }, + "vmLocalUserName": { + "type": "string", + "metadata": { + "description": "AVD session host local admin credentials." + } + }, + "storageSku": { + "type": "string", + "metadata": { + "description": "Azure Files storage account SKU." + } + }, + "fileShareQuotaSize": { + "type": "int", + "metadata": { + "description": "*Azure File share quota" + } + }, + "privateDnsZoneFilesResourceId": { + "type": "string", + "metadata": { + "description": "Use Azure private DNS zones for private endpoints." + } + }, + "storageToDomainScript": { + "type": "string", + "metadata": { + "description": "Script name for adding storage account to Active Directory." + } + }, + "storageToDomainScriptUri": { + "type": "string", + "metadata": { + "description": "URI for the script for adding the storage account to Active Directory." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "managementVmName": { + "type": "string", + "metadata": { + "description": "Name for management virtual machine. for tools and to join Azure Files to domain." + } + }, + "deployPrivateEndpoint": { + "type": "bool", + "metadata": { + "description": "Optional. AVD Accelerator will deploy with private endpoints by default." + } + }, + "alaWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Log analytics workspace for diagnostic logs." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + }, + "storagePurpose": { + "type": "string", + "metadata": { + "description": "Sets purpose of the storage account." + } + }, + "dscAgentPackageLocation": { + "type": "string", + "metadata": { + "description": "Sets location of DSC Agent." + } + }, + "storageCustomOuPath": { + "type": "string", + "metadata": { + "description": "Custom OU path for storage." + } + }, + "storageOuPath": { + "type": "string", + "metadata": { + "description": "OU Storage Path" + } + }, + "managedIdentityClientId": { + "type": "string", + "metadata": { + "description": "Managed Identity Client ID" + } + }, + "securityPrincipalName": { + "type": "string", + "metadata": { + "description": "Identity name array to grant RBAC role to access AVD application group and NTFS permissions." + } + }, + "storageAccountFqdn": { + "type": "string", + "metadata": { + "description": "storage account FDQN." + } + } + }, + "variables": { + "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", + "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", + "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]", + "varAzureCloudName": "[environment().name]", + "varWrklStoragePrivateEndpointName": "[format('pe-{0}-file', parameters('storageAccountName'))]", + "varSecurityPrincipalName": "[if(not(empty(parameters('securityPrincipalName'))), parameters('securityPrincipalName'), 'none')]", + "varAdminUserName": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('vmLocalUserName'), parameters('domainJoinUserName'))]", + "varStorageToDomainScriptArgs": "[format('-DscPath {0} -StorageAccountName {1} -StorageAccountRG {2} -StoragePurpose {3} -DomainName {4} -IdentityServiceProvider {5} -AzureCloudEnvironment {6} -SubscriptionId {7} -AdminUserName {8} -CustomOuPath {9} -OUName {10} -ShareName {11} -ClientId {12} -SecurityPrincipalName \"{13}\" -StorageAccountFqdn {14} ', parameters('dscAgentPackageLocation'), parameters('storageAccountName'), parameters('storageObjectsRgName'), parameters('storagePurpose'), parameters('identityDomainName'), parameters('identityServiceProvider'), variables('varAzureCloudName'), parameters('subId'), variables('varAdminUserName'), parameters('storageCustomOuPath'), parameters('storageOuPath'), parameters('fileShareName'), parameters('managedIdentityClientId'), variables('varSecurityPrincipalName'), parameters('storageAccountFqdn'))]", + "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subId'))]", + "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('storageAccountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": { + "value": "[parameters('storageSku')]" + }, + "allowBlobPublicAccess": { + "value": false + }, + "publicNetworkAccess": "[if(parameters('deployPrivateEndpoint'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "kind": "[if(or(equals(parameters('storageSku'), 'Premium_LRS'), equals(parameters('storageSku'), 'Premium_ZRS')), createObject('value', 'FileStorage'), createObject('value', 'StorageV2'))]", + "largeFileSharesState": "[if(or(equals(parameters('storageSku'), 'Standard_LRS'), equals(parameters('storageSku'), 'Standard_ZRS')), createObject('value', 'Enabled'), createObject('value', 'Disabled'))]", + "azureFilesIdentityBasedAuthentication": "[if(not(equals(parameters('identityServiceProvider'), 'EntraID')), createObject('value', createObject('directoryServiceOptions', if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDS', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), 'AADKERB', 'none')), 'activeDirectoryProperties', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), createObject('domainGuid', parameters('identityDomainGuid'), 'domainName', parameters('identityDomainName')), createObject()))), createObject('value', null()))]", + "accessTier": { + "value": "Hot" + }, + "networkAcls": "[if(parameters('deployPrivateEndpoint'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', parameters('vmsSubnetResourceId'), 'action', 'Allow')), 'ipRules', createArray())))]", + "fileServices": { + "value": { + "shares": [ + { + "name": "[parameters('fileShareName')]", + "shareQuota": "[parameters('fileShareQuotaSize')]" + } + ], + "protocolSettings": "[if(parameters('fileShareMultichannel'), createObject('smb', createObject('multichannel', createObject('enabled', parameters('fileShareMultichannel')))), createObject())]", + "diagnosticSettings": "[variables('varDiagnosticSettings')]" + } + }, + "privateEndpoints": "[if(parameters('deployPrivateEndpoint'), createObject('value', createArray(createObject('name', variables('varWrklStoragePrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklStoragePrivateEndpointName')), 'service', 'file', 'privateDnsZoneGroupName', split(parameters('privateDnsZoneFilesResourceId'), '/')[8], 'privateDnsZoneResourceIds', createArray(parameters('privateDnsZoneFilesResourceId'))))), createObject('value', createArray()))]", + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "15994741654178645865" + }, + "name": "Storage Accounts", + "description": "This module deploys a Storage Account.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + } + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Manual PrivateLink Service Connections." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Storage Account. Must be lower-case." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], + "metadata": { + "description": "Optional. Type of Storage Account to create." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS", + "Premium_ZRS", + "Standard_GZRS", + "Standard_RAGZRS" + ], + "metadata": { + "description": "Optional. Storage Account Sku Name." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool" + ], + "metadata": { + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + } + }, + "largeFileSharesState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + } + }, + "azureFilesIdentityBasedAuthentication": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Provides the identity based authentication settings for Azure Files." + } + }, + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "managementPolicyRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The Storage Account ManagementPolicies Rules." + } + }, + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + } + }, + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + } + }, + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + } + }, + "dnsEndpointType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." + } + }, + "blobServices": { + "type": "object", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", + "metadata": { + "description": "Optional. Blob service and containers to deploy." + } + }, + "fileServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_0", + "TLS1_1", + "TLS1_2" + ], + "metadata": { + "description": "Optional. Set the minimum TLS version on request to storage." + } + }, + "enableHierarchicalNamespace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + } + }, + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables local users feature, if set to true." + } + }, + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "allowedCopyScope": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AAD", + "PrivateLink" + ], + "metadata": { + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } + } + }, + "variables": { + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", + "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", + "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", + "customDomain": { + "name": "[parameters('customDomainName')]", + "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" + }, + "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", + "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", + "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", + "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", + "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", + "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", + "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", + "isSftpEnabled": "[parameters('enableSftp')]", + "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", + "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", + "minimumTlsVersion": "[parameters('minimumTlsVersion')]", + "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", + "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_privateEndpoints": { + "copy": { + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "5572402757180298542" + }, + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Protocol settings for file service." + } + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "defaultValue": { + "enabled": true, + "days": 7 + }, + "metadata": { + "description": "Optional. The service properties for soft delete." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + } + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "2846593244669729605" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "TransactionOptimized", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" + } + }, + "fileShare_roleAssignments": { + "condition": "[not(empty(parameters('roleAssignments')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "fileShareResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "11422901802944437310" + } + }, + "parameters": { + "roleAssignments": { + "type": "array", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "fileShareResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the file share to assign the roles to." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "description": "[[parameters('description')]", + "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + }, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": [ + { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2021-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" + }, + "name": { + "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" + }, + "roleDefinitionId": { + "value": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]" + }, + "principalId": { + "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "condition": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": { + "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" + }, + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + } + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "fileServices", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed storage account." + }, + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2022-09-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[not(equals(parameters('identityServiceProvider'), 'EntraID'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Add-{0}-Storage-Setup-{1}', parameters('storagePurpose'), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "virtualMachineName": { + "value": "[parameters('managementVmName')]" + }, + "file": { + "value": "[parameters('storageToDomainScript')]" + }, + "scriptArguments": { + "value": "[variables('varStorageToDomainScriptArgs')]" + }, + "adminUserPassword": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'vmLocalUserPassword')), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'domainJoinUserPassword')))]", + "baseScriptUri": { + "value": "[parameters('storageToDomainScriptUri')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "7337889415739790800" + }, + "name": "AVD LZA storage", + "description": "Configures domain join settings on storage account via VM custom script extension", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Virtual machine name." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy compute services." + } + }, + "baseScriptUri": { + "type": "string", + "metadata": { + "description": "Location for the AVD agent installation package." + } + }, + "file": { + "type": "string" + }, + "scriptArguments": { + "type": "string", + "metadata": { + "description": "Arguments for domain join script." + } + }, + "adminUserPassword": { + "type": "securestring", + "metadata": { + "description": "Domain join user password." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('VM-Ext-AVM-{0}', parameters('time'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "AzureFilesDomainJoin" + }, + "virtualMachineName": { + "value": "[parameters('virtualMachineName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "CustomScriptExtension" + }, + "typeHandlerVersion": { + "value": "1.10" + }, + "autoUpgradeMinorVersion": { + "value": true + }, + "enableAutomaticUpgrade": { + "value": false + }, + "settings": { + "value": {} + }, + "protectedSettings": { + "value": { + "fileUris": "[array(parameters('baseScriptUri'))]", + "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -File {0} {1} -AdminUserPassword {2} -verbose', parameters('file'), parameters('scriptArguments'), parameters('adminUserPassword'))]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time')))]" + ] + } + ], + "outputs": { + "storageAccountResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))), '2022-09-01').outputs.resourceId.value]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]" + ] + } + ], + "outputs": { + "fslogixFileSharePath": { + "type": "string", + "value": "[if(parameters('createFslogixDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('\\\\{0}.file.{1}\\{2}', variables('varFslogixStorageName'), environment().suffixes.storage, variables('varFslogixFileShareName')), if(equals(parameters('storageService'), 'ANF'), format('\\\\{0}\\{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Get-ANF-SMB-Server-FQDN-{0}', parameters('time'))), '2022-09-01').outputs.anfSmbServerFqdn.value, last(split(reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfFslogixVolumeResourceId.value, '/'))), '')), '')]" + }, + "appAttachFileSharePath": { + "type": "string", + "value": "[if(parameters('createAppAttachDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('\\\\{0}.file.{1}\\{2}', variables('varAppAttachStorageName'), environment().suffixes.storage, variables('varAppAttachFileShareName')), if(equals(parameters('storageService'), 'ANF'), format('\\\\{0}\\{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Get-ANF-SMB-Server-FQDN-{0}', parameters('time'))), '2022-09-01').outputs.anfSmbServerFqdn.value, last(split(reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfAppAttachVolumeResourceId.value, '/'))), '')), '')]" + }, + "fslogixStorageAccountResourceId": { + "type": "string", + "value": "[if(and(parameters('createFslogixDeployment'), equals(parameters('storageService'), 'AzureFiles')), reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-FSLogix-ST-{0}', parameters('time'))), '2022-09-01').outputs.storageAccountResourceId.value, '')]" + }, + "appAttachStorageAccountResourceId": { + "type": "string", + "value": "[if(and(parameters('createAppAttachDeployment'), equals(parameters('storageService'), 'AzureFiles')), reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-AppA-{0}', parameters('time'))), '2022-09-01').outputs.storageAccountResourceId.value, '')]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]", + "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time')))]" + ] + }, + { + "copy": { + "name": "sessionHosts", + "count": "[length(range(1, variables('varSessionHostBatchCount')))]", + "mode": "serial", + "batchSize": 3 + }, + "condition": "[parameters('avdDeploySessionHosts')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('SH-Batch-{0}-{1}', range(1, variables('varSessionHostBatchCount'))[copyIndex()], parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "asgResourceId": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', format('{0}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.applicationSecurityGroupResourceId.value)), createObject('value', ''))]", + "availability": { + "value": "[parameters('availability')]" + }, + "availabilityZones": { + "value": "[parameters('availabilityZones')]" + }, + "batchId": { + "value": "[sub(range(1, variables('varSessionHostBatchCount'))[copyIndex()], 1)]" + }, + "computeObjectsRgName": { + "value": "[variables('varComputeObjectsRgName')]" + }, + "configureFslogix": { + "value": "[parameters('createFslogixDeployment')]" + }, + "count": "[if(and(equals(range(1, variables('varSessionHostBatchCount'))[copyIndex()], variables('varSessionHostBatchCount')), greater(variables('varMaxSessionHostsDivisionRemainderValue'), 0)), createObject('value', variables('varMaxSessionHostsDivisionRemainderValue')), createObject('value', variables('varMaxSessionHostsPerTemplate')))]", + "countIndex": "[if(equals(range(1, variables('varSessionHostBatchCount'))[copyIndex()], 1), createObject('value', parameters('avdSessionHostCountIndex')), createObject('value', add(mul(sub(range(1, variables('varSessionHostBatchCount'))[copyIndex()], 1), variables('varMaxSessionHostsPerTemplate')), parameters('avdSessionHostCountIndex'))))]", + "createIntuneEnrollment": { + "value": "[parameters('createIntuneEnrollment')]" + }, + "customImageDefinitionId": { + "value": "[parameters('avdCustomImageDefinitionId')]" + }, + "dataCollectionRuleId": "[if(parameters('avdDeployMonitoring'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.dataCollectionRuleId.value), createObject('value', ''))]", + "deployAntiMalwareExt": { + "value": "[parameters('deployAntiMalwareExt')]" + }, + "deployMonitoring": { + "value": "[parameters('avdDeployMonitoring')]" + }, + "diskEncryptionSetResourceId": "[if(parameters('diskZeroTrust'), createObject('value', reference(subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time'))), '2022-09-01').outputs.ztDiskEncryptionSetResourceId.value), createObject('value', ''))]", + "customOsDiskSizeGB": { + "value": "[parameters('customOsDiskSizeGB')]" + }, + "diskType": { + "value": "[parameters('avdSessionHostDiskType')]" + }, + "domainJoinUserPrincipalName": { + "value": "[parameters('avdDomainJoinUserName')]" + }, + "enableAcceleratedNetworking": { + "value": "[parameters('enableAcceleratedNetworking')]" + }, + "encryptionAtHost": { + "value": "[parameters('diskZeroTrust')]" + }, + "fslogixSharePath": "[if(parameters('createFslogixDeployment'), createObject('value', reference(subscriptionResourceId(format('{0}', parameters('avdWorkloadSubsId')), 'Microsoft.Resources/deployments', format('SMB-Storage-{0}', parameters('time'))), '2022-09-01').outputs.fslogixFileSharePath.value), createObject('value', ''))]", + "fslogixStorageAccountResourceId": "[if(and(equals(parameters('avdIdentityServiceProvider'), 'EntraID'), parameters('createFslogixDeployment')), createObject('value', reference(subscriptionResourceId(format('{0}', parameters('avdWorkloadSubsId')), 'Microsoft.Resources/deployments', format('SMB-Storage-{0}', parameters('time'))), '2022-09-01').outputs.fslogixStorageAccountResourceId.value), createObject('value', ''))]", + "hostPoolResourceId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', format('AVD-MGMT-Plane-{0}', parameters('time'))), '2022-09-01').outputs.hostPoolResourceId.value]" + }, + "identityDomainName": { + "value": "[parameters('identityDomainName')]" + }, + "identityServiceProvider": { + "value": "[parameters('avdIdentityServiceProvider')]" + }, + "keyVaultResourceId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" + }, + "location": { + "value": "[parameters('avdSessionHostLocation')]" + }, + "mpImageOffer": { + "value": "[parameters('mpImageOffer')]" + }, + "mpImageSku": { + "value": "[parameters('mpImageSku')]" + }, + "namePrefix": { + "value": "[variables('varSessionHostNamePrefix')]" + }, + "secureBootEnabled": { + "value": "[parameters('secureBootEnabled')]" + }, + "securityType": "[if(equals(parameters('securityType'), 'Standard'), createObject('value', ''), createObject('value', parameters('securityType')))]", + "sessionHostConfigurationScriptUri": { + "value": "[variables('varSessionHostConfigurationScriptUri')]" + }, + "sessionHostConfigurationScript": { + "value": "[variables('varSessionHostConfigurationScript')]" + }, + "sessionHostOuPath": { + "value": "[parameters('avdOuPath')]" + }, + "subscriptionId": { + "value": "[parameters('avdWorkloadSubsId')]" + }, + "subnetId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", + "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]", + "timeZone": { + "value": "[variables('varTimeZoneSessionHosts')]" + }, + "useSharedImage": { + "value": "[parameters('useSharedImage')]" + }, + "vmSize": { + "value": "[parameters('avdSessionHostsSize')]" + }, + "vTpmEnabled": { + "value": "[parameters('vTpmEnabled')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13361150904998745536" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy compute services." + } + }, + "computeObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group name for the session hosts." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "metadata": { + "description": "AVD disk encryption set resource ID to enable server side encryption." + } + }, + "subnetId": { + "type": "string", + "metadata": { + "description": "AVD subnet ID." + } + }, + "timeZone": { + "type": "string", + "metadata": { + "description": "Virtual machine time zone." + } + }, + "batchId": { + "type": "int", + "metadata": { + "description": "General session host batch identifier" + } + }, + "namePrefix": { + "type": "string", + "metadata": { + "description": "AVD Session Host prefix." + } + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "count": { + "type": "int", + "metadata": { + "description": "Quantity of session hosts to deploy." + } + }, + "countIndex": { + "type": "int", + "metadata": { + "description": "The session host number to begin with for the deployment." + } + }, + "availability": { + "type": "string", + "metadata": { + "description": "When true VMs are distributed across availability zones, when set to false, VMs will be deployed at regional level. (Default: true)." + } + }, + "availabilityZones": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Defines the Availability Zones for the VMs." + } + }, + "identityServiceProvider": { + "type": "string", + "metadata": { + "description": "The service providing domain services for Azure Virtual Desktop." + } + }, + "createIntuneEnrollment": { + "type": "bool", + "metadata": { + "description": "Enroll session hosts on Intune." + } + }, + "encryptionAtHost": { + "type": "bool", + "metadata": { + "description": "This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "Session host VM size." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "metadata": { + "description": "Enables accelerated Networking on the session hosts." + } + }, + "securityType": { + "type": "string", + "metadata": { + "description": "Specifies the securityType of the virtual machine. Must be TrustedLaunch or ConfidentialVM enable UefiSettings." + } + }, + "secureBootEnabled": { + "type": "bool", + "metadata": { + "description": "Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "vTpmEnabled": { + "type": "bool", + "metadata": { + "description": "Specifies whether virtual TPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "diskType": { + "type": "string", + "metadata": { + "description": "OS disk type for session host." + } + }, + "customOsDiskSizeGB": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Define custom OS disk size if larger than image size." + } + }, + "useSharedImage": { + "type": "bool", + "metadata": { + "description": "Set to deploy image from Azure Compute Gallery." + } + }, + "mpImagePublisher": { + "type": "string", + "defaultValue": "MicrosoftWindowsDesktop", + "metadata": { + "description": "AVD OS image publisher." + } + }, + "mpImageOffer": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "AVD OS image SKU." + } + }, + "mpImageSku": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "AVD OS image SKU." + } + }, + "customImageDefinitionId": { + "type": "string", + "metadata": { + "description": "Source custom image ID." + } + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of keyvault that contains credentials." + } + }, + "identityDomainName": { + "type": "string", + "metadata": { + "description": "Identity domain name." + } + }, + "domainJoinUserPrincipalName": { + "type": "string", + "metadata": { + "description": "AVD session host domain join credentials." + } + }, + "sessionHostOuPath": { + "type": "string", + "metadata": { + "description": "OU path to join AVd VMs." + } + }, + "asgResourceId": { + "type": "string", + "metadata": { + "description": "Application Security Group (ASG) for the session hosts." + } + }, + "configureFslogix": { + "type": "bool", + "metadata": { + "description": "Configure Fslogix on session hosts." + } + }, + "fslogixSharePath": { + "type": "string", + "metadata": { + "description": "Path for the FSlogix share." + } + }, + "fslogixStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "FSLogix storage account resource ID." + } + }, + "hostPoolResourceId": { + "type": "string", + "metadata": { + "description": "Host pool resource ID." + } + }, + "sessionHostConfigurationScriptUri": { + "type": "string", + "metadata": { + "description": "URI for AVD session host configuration script URI." + } + }, + "sessionHostConfigurationScript": { + "type": "string", + "metadata": { + "description": "URI for AVD session host configuration script." + } + }, + "tags": { + "type": "object", + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "deployMonitoring": { + "type": "bool", + "metadata": { + "description": "Deploy AVD monitoring resources and setings." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + }, + "dataCollectionRuleId": { + "type": "string", + "metadata": { + "description": "Data collection rule ID." + } + }, + "deployAntiMalwareExt": { + "type": "bool", + "metadata": { + "description": "Deploys anti malware extension on session hosts." + } + } + }, + "variables": { + "copy": [ + { + "name": "varZones", + "count": "[length(parameters('availabilityZones'))]", + "input": "[int(parameters('availabilityZones')[copyIndex('varZones')])]" + } + ], + "varManagedDisk": "[if(empty(parameters('diskEncryptionSetResourceId')), createObject('storageAccountType', parameters('diskType')), createObject('diskEncryptionSetResourceId', parameters('diskEncryptionSetResourceId'), 'storageAccountType', parameters('diskType')))]", + "varOsDiskProperties": { + "createOption": "FromImage", + "deleteOption": "Delete", + "caching": "ReadWrite", + "managedDisk": "[variables('varManagedDisk')]" + }, + "varCustomOsDiskProperties": { + "createOption": "FromImage", + "deleteOption": "Delete", + "caching": "ReadWrite", + "managedDisk": "[variables('varManagedDisk')]", + "diskSizeGB": "[if(not(equals(parameters('customOsDiskSizeGB'), 0)), parameters('customOsDiskSizeGB'), null())]" + } + }, + "resources": [ + { + "copy": { + "name": "sessionHosts", + "count": "[length(range(0, parameters('count')))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('SH-{0}-{1}-{2}', add(parameters('batchId'), 1), add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}{1}', parameters('namePrefix'), padLeft(add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), 4, '0'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "timeZone": { + "value": "[parameters('timeZone')]" + }, + "zone": "[if(equals(parameters('availability'), 'AvailabilityZones'), createObject('value', variables('varZones')[mod(range(0, parameters('count'))[copyIndex()], length(variables('varZones')))]), createObject('value', 0))]", + "managedIdentities": "[if(or(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('deployMonitoring')), createObject('value', createObject('systemAssigned', true())), createObject('value', null()))]", + "encryptionAtHost": { + "value": "[parameters('encryptionAtHost')]" + }, + "osType": { + "value": "Windows" + }, + "licenseType": { + "value": "Windows_Client" + }, + "vmSize": { + "value": "[parameters('vmSize')]" + }, + "securityType": "[if(equals(parameters('securityType'), 'Standard'), createObject('value', ''), createObject('value', parameters('securityType')))]", + "secureBootEnabled": { + "value": "[parameters('secureBootEnabled')]" + }, + "vTpmEnabled": { + "value": "[parameters('vTpmEnabled')]" + }, + "imageReference": "[if(parameters('useSharedImage'), createObject('value', createObject('id', parameters('customImageDefinitionId'))), createObject('value', createObject('publisher', parameters('mpImagePublisher'), 'offer', parameters('mpImageOffer'), 'sku', parameters('mpImageSku'), 'version', 'latest')))]", + "osDisk": "[if(not(equals(parameters('customOsDiskSizeGB'), 0)), createObject('value', variables('varCustomOsDiskProperties')), createObject('value', variables('varOsDiskProperties')))]", + "adminUsername": { + "reference": { + "keyVault": { + "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('keyVaultResourceId'), '/')[4]), 'Microsoft.KeyVault/vaults', last(split(parameters('keyVaultResourceId'), '/')))]" + }, + "secretName": "vmLocalUserName" + } + }, + "adminPassword": { + "reference": { + "keyVault": { + "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('keyVaultResourceId'), '/')[4]), 'Microsoft.KeyVault/vaults', last(split(parameters('keyVaultResourceId'), '/')))]" + }, + "secretName": "vmLocalUserPassword" + } + }, + "nicConfigurations": { + "value": [ + { + "name": "[format('nic-01-{0}{1}', parameters('namePrefix'), padLeft(add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), 4, '0'))]", + "deleteOption": "Delete", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "ipConfigurations": "[if(not(empty(parameters('asgResourceId'))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetId'), 'applicationSecurityGroups', createArray(createObject('id', parameters('asgResourceId'))))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetId'))))]" + } + ] + }, + "extensionDomainJoinPassword": "[if(contains(parameters('identityServiceProvider'), 'DS'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('keyVaultResourceId'), '/')[4]), 'Microsoft.KeyVault/vaults', last(split(parameters('keyVaultResourceId'), '/')))), 'secretName', 'domainJoinUserPassword')), createObject('value', null()))]", + "extensionDomainJoinConfig": "[if(contains(parameters('identityServiceProvider'), 'DS'), createObject('value', createObject('enabled', true(), 'settings', createObject('name', parameters('identityDomainName'), 'ouPath', if(not(empty(parameters('sessionHostOuPath'))), parameters('sessionHostOuPath'), null()), 'user', parameters('domainJoinUserPrincipalName'), 'restart', 'true', 'options', '3'))), createObject('value', null()))]", + "extensionAadJoinConfig": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('value', createObject('enabled', if(contains(parameters('identityServiceProvider'), 'EntraID'), true(), false()), 'settings', if(parameters('createIntuneEnrollment'), createObject('mdmId', '0000000a-0000-0000-c000-000000000000'), createObject()))), createObject('value', null()))]", + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "13031055217657209142" + }, + "name": "Virtual Machines", + "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "osDiskType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "metadata": { + "description": "Required. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + } + } + }, + "dataDisksType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } + }, + "lun": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the logical unit number of the data disk." + } + }, + "diskSizeGB": { + "type": "int", + "maxValue": 1023, + "metadata": { + "description": "Required. Specifies the size of an empty data disk in gigabytes." + } + }, + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "metadata": { + "description": "Required. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } + } + }, + "metadata": { + "description": "Required. The managed disk parameters." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." + } + }, + "computerName": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." + } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "Required. Specifies the size for the VMs." + } + }, + "encryptionAtHost": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "securityType": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the SecurityType of the virtual machine. It is set as TrustedLaunch to enable UefiSettings." + } + }, + "secureBootEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "vTpmEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "imageReference": { + "type": "object", + "metadata": { + "description": "Required. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image." + } + }, + "plan": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." + } + }, + "osDisk": { + "$ref": "#/definitions/osDiskType", + "metadata": { + "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "dataDisks": { + "$ref": "#/definitions/dataDisksType", + "metadata": { + "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "ultraSSDEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." + } + }, + "adminUsername": { + "type": "securestring", + "metadata": { + "description": "Required. Administrator username." + } + }, + "adminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. When specifying a Windows Virtual Machine, this value should be passed." + } + }, + "customData": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." + } + }, + "certificatesToBeInstalled": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." + } + }, + "priority": { + "type": "string", + "defaultValue": "Regular", + "allowedValues": [ + "Regular", + "Low", + "Spot" + ], + "metadata": { + "description": "Optional. Specifies the priority for the virtual machine." + } + }, + "enableEvictionPolicy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy." + } + }, + "maxPriceForLowPriorityVm": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." + } + }, + "dedicatedHostId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." + } + }, + "licenseType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "RHEL_BYOS", + "SLES_BYOS", + "Windows_Client", + "Windows_Server", + "" + ], + "metadata": { + "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." + } + }, + "bootDiagnostics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." + } + }, + "bootDiagnosticStorageAccountName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." + } + }, + "bootDiagnosticStorageAccountUri": { + "type": "string", + "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", + "metadata": { + "description": "Optional. Storage account boot diagnostic base URI." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a proximity placement group." + } + }, + "virtualMachineScaleSetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." + } + }, + "availabilitySetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." + } + }, + "zone": { + "type": "int", + "allowedValues": [ + 0, + 1, + 2, + 3 + ], + "metadata": { + "description": "Required. If set to 1, 2 or 3, the availability zone for all VMs is hardcoded to that value. If zero, then availability zones is not used. Cannot be used in combination with availability set nor scale set." + } + }, + "nicConfigurations": { + "type": "array", + "metadata": { + "description": "Required. Configures NICs and PIPs." + } + }, + "allowExtensionOperations": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." + } + }, + "extensionDomainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if name is specified. Password of the user specified in user parameter." + } + }, + "extensionDomainJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAadJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." + } + }, + "extensionAzureDiskEncryptionConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." + } + }, + "extensionDSCConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "fileData": [] + }, + "metadata": { + "description": "Optional. The configuration for the [Custom Script] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionNvidiaGpuDriverWindows": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptProtectedSetting": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. An object that contains the extension specific protected settings." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to generate a registration token." + } + }, + "sasTokenValidityLength": { + "type": "string", + "defaultValue": "PT8H", + "metadata": { + "description": "Optional. SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. The chosen OS type." + } + }, + "provisionVMAgent": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." + } + }, + "enableAutomaticUpdates": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." + } + }, + "patchMode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "AutomaticByPlatform", + "AutomaticByOS", + "Manual", + "ImageDefault", + "" + ], + "metadata": { + "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." + } + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables customer to schedule patching without accidental upgrades." + } + }, + "rebootSetting": { + "type": "string", + "defaultValue": "IfRequired", + "allowedValues": [ + "Always", + "IfRequired", + "Never", + "Unknown" + ], + "metadata": { + "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." + } + }, + "patchAssessmentMode": { + "type": "string", + "defaultValue": "ImageDefault", + "allowedValues": [ + "AutomaticByPlatform", + "ImageDefault" + ], + "metadata": { + "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." + } + }, + "additionalUnattendContent": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." + } + }, + "winRM": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object." + } + }, + "configurationProfile": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." + } + } + }, + "variables": { + "windowsConfiguration": { + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting'))), null())]", + "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", + "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), parameters('additionalUnattendContent'))]", + "winRM": "[if(not(empty(parameters('winRM'))), createObject('listeners', parameters('winRM')), null())]" + }, + "accountSasProperties": { + "signedServices": "b", + "signedPermission": "r", + "signedExpiry": "[dateTimeAdd(parameters('baseTime'), parameters('sasTokenValidityLength'))]", + "signedResourceTypes": "o", + "signedProtocol": "https" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "vm": { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "zones": "[if(not(equals(parameters('zone'), 0)), array(string(parameters('zone'))), null())]", + "plan": "[if(not(empty(parameters('plan'))), parameters('plan'), null())]", + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "securityProfile": { + "encryptionAtHost": "[if(parameters('encryptionAtHost'), parameters('encryptionAtHost'), null())]", + "securityType": "[parameters('securityType')]", + "uefiSettings": "[if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null())]" + }, + "storageProfile": { + "copy": [ + { + "name": "dataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", + "input": { + "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", + "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))]", + "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createoption'), 'Empty')]", + "deleteOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete')]", + "caching": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly')]", + "managedDisk": { + "storageAccountType": "[coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.storageAccountType]", + "diskEncryptionSet": "[coalesce(tryGet(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'managedDisk'), 'diskEncryptionSet'), null())]" + } + } + } + ], + "imageReference": "[parameters('imageReference')]", + "osDisk": { + "name": "[coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name')))]", + "createOption": "[coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage')]", + "deleteOption": "[coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete')]", + "caching": "[coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly')]", + "managedDisk": { + "storageAccountType": "[parameters('osDisk').managedDisk.storageAccountType]", + "diskEncryptionSet": { + "id": "[tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')]" + } + } + } + }, + "additionalCapabilities": { + "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]" + }, + "osProfile": { + "computerName": "[parameters('computerName')]", + "adminUsername": "[parameters('adminUsername')]", + "adminPassword": "[parameters('adminPassword')]", + "customData": "[if(not(empty(parameters('customData'))), base64(parameters('customData')), null())]", + "windowsConfiguration": "[if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null())]", + "secrets": "[parameters('certificatesToBeInstalled')]", + "allowExtensionOperations": "[parameters('allowExtensionOperations')]" + }, + "networkProfile": { + "copy": [ + { + "name": "networkInterfaces", + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "properties": { + "deleteOption": "[if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].deleteOption, 'Delete')]", + "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" + }, + "id": "[resourceId('Microsoft.Network/networkInterfaces', if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].name, format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].nicSuffix)))]" + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", + "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" + } + }, + "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", + "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", + "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", + "priority": "[parameters('priority')]", + "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", + "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", + "host": "[if(not(empty(parameters('dedicatedHostId'))), createObject('id', parameters('dedicatedHostId')), null())]", + "licenseType": "[if(not(empty(parameters('licenseType'))), parameters('licenseType'), null())]" + }, + "dependsOn": [ + "vm_nic" + ] + }, + "vm_configurationProfileAssignment": { + "condition": "[not(empty(parameters('configurationProfile')))]", + "type": "Microsoft.Automanage/configurationProfileAssignments", + "apiVersion": "2022-05-04", + "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", + "name": "default", + "properties": { + "configurationProfile": "[parameters('configurationProfile')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_nic": { + "copy": { + "name": "vm_nic", + "count": "[length(parameters('nicConfigurations'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkInterfaceName": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'name'), createObject('value', parameters('nicConfigurations')[copyIndex()].name), createObject('value', format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex()].nicSuffix)))]", + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableIPForwarding": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableIPForwarding), createObject('value', false()))]", + "enableAcceleratedNetworking": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableAcceleratedNetworking), createObject('value', true()))]", + "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(parameters('nicConfigurations')[copyIndex()].dnsServers)), createObject('value', parameters('nicConfigurations')[copyIndex()].dnsServers), createObject('value', createArray())), createObject('value', createArray()))]", + "networkSecurityGroupResourceId": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('nicConfigurations')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", + "ipConfigurations": { + "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4081873631846149092" + } + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "networkInterfaceName": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + }, + "ipConfigurations": { + "type": "array" + }, + "location": { + "type": "string", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false + }, + "dnsServers": { + "type": "array", + "defaultValue": [] + }, + "enableTelemetry": { + "type": "bool", + "metadata": { + "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the Network Interface." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "resources": { + "networkInterface_publicIPAddresses": { + "copy": { + "name": "networkInterface_publicIPAddresses", + "count": "[length(parameters('ipConfigurations'))]" + }, + "condition": "[contains(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIpNameSuffix)]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "idleTimeoutInMinutes": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'idleTimeoutInMinutes')]" + }, + "ddosSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'ddosSettings')]" + }, + "dnsSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'dnsSettings')]" + }, + "publicIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressVersion'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAddressVersion), createObject('value', 'IPv4'))]", + "publicIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAllocationMethod'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAllocationMethod), createObject('value', 'Static'))]", + "publicIpPrefixResourceId": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPPrefixResourceId'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPPrefixResourceId), createObject('value', ''))]", + "roleAssignments": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'roleAssignments'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.roleAssignments), createObject('value', createArray()))]", + "skuName": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuName'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuName), createObject('value', 'Standard'))]", + "skuTier": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuTier'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuTier), createObject('value', 'Regional'))]", + "tags": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "zones": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.zones), createObject('value', createArray(1, 2, 3)))]", + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.54.24096", + "templateHash": "4718335757080871925" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "", + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "metadata": { + "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "metadata": { + "description": "Required. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + } + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": null + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkInterface', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('networkInterfaceName')]" + }, + "ipConfigurations": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('ipConfigurations'))]", + "input": "[createObject('name', if(not(empty(parameters('ipConfigurations')[copyIndex('value')].name)), parameters('ipConfigurations')[copyIndex('value')].name, null()), 'primary', equals(copyIndex('value'), 0), 'privateIPAllocationMethod', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod, null()), null()), 'privateIPAddress', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('value')].privateIPAddress, null()), null()), 'publicIPAddressResourceId', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), resourceId('Microsoft.Network/publicIPAddresses', format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.publicIpNameSuffix)), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerBackendAddressPools, null()), 'applicationSecurityGroups', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('value')].applicationSecurityGroups, null()), 'applicationGatewayBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].applicationGatewayBackendAddressPools, null()), 'gatewayLoadBalancer', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('value')].gatewayLoadBalancer, null()), 'loadBalancerInboundNatRules', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerInboundNatRules, null()), 'privateIPAddressVersion', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('value')].privateIPAddressVersion, null()), 'virtualNetworkTaps', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('value')].virtualNetworkTaps, null()))]" + } + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" + }, + "dnsServers": "[if(not(empty(parameters('dnsServers'))), createObject('value', parameters('dnsServers')), createObject('value', createArray()))]", + "enableAcceleratedNetworking": { + "value": "[parameters('enableAcceleratedNetworking')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enableIPForwarding": { + "value": "[parameters('enableIPForwarding')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", + "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "1612343535299711142" + }, + "name": "Network Interface", + "description": "This module deploys a Network Interface.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the network interface." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." + } + }, + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If the network interface is accelerated networking enabled." + } + }, + "dnsServers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The network security group (NSG) to attach to the network interface." + } + }, + "auxiliaryMode": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Floating", + "MaxConnections", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "auxiliarySku": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "A1", + "A2", + "A4", + "A8", + "None" + ], + "metadata": { + "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "disableTcpStateTracking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." + } + }, + "ipConfigurations": { + "type": "array", + "metadata": { + "description": "Required. A list of IPConfigurations of the network interface." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.2.4', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkInterface": { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "ipConfigurations", + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].name, format('ipconfig0{0}', add(copyIndex('ipConfigurations'), 1)))]", + "properties": { + "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", + "privateIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod, null()), null())]", + "privateIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress, null()), null())]", + "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId, null())), createObject('id', parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId), null()), null())]", + "subnet": { + "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" + }, + "loadBalancerBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerBackendAddressPools, null())]", + "applicationSecurityGroups": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationSecurityGroups, null())]", + "applicationGatewayBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationGatewayBackendAddressPools, null())]", + "gatewayLoadBalancer": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].gatewayLoadBalancer, null())]", + "loadBalancerInboundNatRules": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerInboundNatRules, null())]", + "privateIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddressVersion, null())]", + "virtualNetworkTaps": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].virtualNetworkTaps, null())]" + } + } + } + ], + "auxiliaryMode": "[parameters('auxiliaryMode')]", + "auxiliarySku": "[parameters('auxiliarySku')]", + "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", + "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "enableIPForwarding": "[parameters('enableIPForwarding')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" + } + }, + "networkInterface_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_diagnosticSettings": { + "copy": { + "name": "networkInterface_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_roleAssignments": { + "copy": { + "name": "networkInterface_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkInterface" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed resource." + }, + "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed resource." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkInterface', '2023-04-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "networkInterface_publicIPAddresses" + ] + } + } + } + } + }, + "vm_aadJoinExtension": { + "condition": "[parameters('extensionAadJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "AADLogin" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.ActiveDirectory" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", + "typeHandlerVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAadJoinConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.0'), createObject('value', '1.0')))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAadJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAadJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": "[if(contains(parameters('extensionAadJoinConfig'), 'settings'), createObject('value', parameters('extensionAadJoinConfig').settings), createObject('value', createObject()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] + }, + "vm_domainJoinExtension": { + "condition": "[parameters('extensionDomainJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DomainJoin" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "JsonADDomainExtension" + }, + "typeHandlerVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDomainJoinConfig').typeHandlerVersion), createObject('value', '1.3'))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDomainJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDomainJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": { + "value": "[parameters('extensionDomainJoinConfig').settings]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": { + "Password": "[parameters('extensionDomainJoinPassword')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_aadJoinExtension" + ] + }, + "vm_desiredStateConfigurationExtension": { + "condition": "[parameters('extensionDSCConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DesiredStateConfiguration" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Powershell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": "[if(contains(parameters('extensionDSCConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDSCConfig').typeHandlerVersion), createObject('value', '2.77'))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDSCConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDSCConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": "[if(contains(parameters('extensionDSCConfig'), 'settings'), createObject('value', parameters('extensionDSCConfig').settings), createObject('value', createObject()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": "[if(contains(parameters('extensionDSCConfig'), 'protectedSettings'), createObject('value', parameters('extensionDSCConfig').protectedSettings), createObject('value', createObject()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] + }, + "vm_customScriptExtension": { + "condition": "[parameters('extensionCustomScriptConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "CustomScriptExtension" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", + "typeHandlerVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionCustomScriptConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '1.10'), createObject('value', '2.1')))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionCustomScriptConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionCustomScriptConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": { + "value": { + "copy": [ + { + "name": "fileUris", + "count": "[length(parameters('extensionCustomScriptConfig').fileData)]", + "input": "[if(contains(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')], 'storageAccountId'), format('{0}?{1}', parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri, listAccountSas(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].storageAccountId, '2019-04-01', variables('accountSasProperties')).accountSasToken), parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri)]" + } + ] + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": "[parameters('extensionCustomScriptProtectedSetting')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_desiredStateConfigurationExtension" + ] + }, + "vm_azureDiskEncryptionExtension": { + "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "AzureDiskEncryption" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", + "typeHandlerVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.2'), createObject('value', '1.1')))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "forceUpdateTag": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').forceUpdateTag), createObject('value', '1.0'))]", + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] + }, + "vm_nvidiaGpuDriverWindowsExtension": { + "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "NvidiaGpuDriverWindows" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.HpcCompute" + }, + "type": { + "value": "NvidiaGpuDriverWindows" + }, + "typeHandlerVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').typeHandlerVersion), createObject('value', '1.4'))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').enableAutomaticUpgrade), createObject('value', false()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureDiskEncryptionExtension" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the VM." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the VM." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the VM was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('vm', '2023-09-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vm', '2023-09-01', 'full').location]" + } + } + } + } + }, + { + "copy": { + "name": "sessionHostsAntimalwareExtension", + "count": "[length(range(0, parameters('count')))]" + }, + "condition": "[parameters('deployAntiMalwareExt')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('SH-Antimal-{0}-{1}-{2}', add(parameters('batchId'), 1), add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "virtualMachineName": { + "value": "[format('{0}{1}', parameters('namePrefix'), padLeft(add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), 4, '0'))]" + }, + "name": { + "value": "MicrosoftAntiMalware" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": { + "value": "IaaSAntimalware" + }, + "typeHandlerVersion": { + "value": "1.3" + }, + "autoUpgradeMinorVersion": { + "value": true + }, + "enableAutomaticUpgrade": { + "value": false + }, + "settings": { + "value": { + "AntimalwareEnabled": true, + "RealtimeProtectionEnabled": "true", + "ScheduledScanSettings": { + "isEnabled": "true", + "day": "7", + "time": "120", + "scanType": "Quick" + }, + "Exclusions": "[if(parameters('configureFslogix'), createObject('Extensions', '*.vhd;*.vhdx', 'Paths', format('\"%ProgramFiles%\\FSLogix\\Apps\\frxdrv.sys;%ProgramFiles%\\FSLogix\\Apps\\frxccd.sys;%ProgramFiles%\\FSLogix\\Apps\\frxdrvvt.sys;%TEMP%\\*.VHD;%TEMP%\\*.VHDX;%Windir%\\TEMP\\*.VHD;%Windir%\\TEMP\\*.VHDX;{0}\\*\\*.VHD;{1}\\*\\*.VHDX', parameters('fslogixSharePath'), parameters('fslogixSharePath')), 'Processes', '%ProgramFiles%\\FSLogix\\Apps\\frxccd.exe;%ProgramFiles%\\FSLogix\\Apps\\frxccds.exe;%ProgramFiles%\\FSLogix\\Apps\\frxsvc.exe'), createObject())]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "sessionHosts" + ] + }, + { + "copy": { + "name": "ama", + "count": "[length(range(0, parameters('count')))]" + }, + "condition": "[parameters('deployMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('SH-Mon-{0}-{1}-{2}', add(parameters('batchId'), 1), add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "virtualMachineName": { + "value": "[format('{0}{1}', parameters('namePrefix'), padLeft(add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), 4, '0'))]" + }, + "name": { + "value": "AzureMonitorWindowsAgent" + }, + "publisher": { + "value": "Microsoft.Azure.Monitor" + }, + "type": { + "value": "AzureMonitorWindowsAgent" + }, + "typeHandlerVersion": { + "value": "1.0" + }, + "autoUpgradeMinorVersion": { + "value": true + }, + "enableAutomaticUpgrade": { + "value": true + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "sessionHostsAntimalwareExtension" + ] + }, + { + "copy": { + "name": "dataCollectionRuleAssociation", + "count": "[length(range(0, parameters('count')))]" + }, + "condition": "[parameters('deployMonitoring')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('DCR-Asso-{0}-{1}-{2}', add(parameters('batchId'), 1), add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[format('{0}{1}', parameters('namePrefix'), padLeft(add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), 4, '0'))]" + }, + "dataCollectionRuleId": { + "value": "[parameters('dataCollectionRuleId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "5134409313697181849" + } + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "VM name." + } + }, + "dataCollectionRuleId": { + "type": "string", + "metadata": { + "description": "Data collection rule ID." + } + } + }, + "resources": [ + { + "type": "Microsoft.Insights/dataCollectionRuleAssociations", + "apiVersion": "2022-06-01", + "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('virtualMachineName'))]", + "name": "[parameters('virtualMachineName')]", + "properties": { + "dataCollectionRuleId": "[parameters('dataCollectionRuleId')]", + "description": "AVD Insights data collection rule association" + } + } + ] + } + }, + "dependsOn": [ + "ama", + "sessionHostsAntimalwareExtension" + ] + }, + { + "copy": { + "name": "sessionHostConfiguration", + "count": "[length(range(0, parameters('count')))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('SH-Config-{0}-{1}-{2}', add(parameters('batchId'), 1), add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "baseScriptUri": { + "value": "[parameters('sessionHostConfigurationScriptUri')]" + }, + "fslogix": { + "value": "[parameters('configureFslogix')]" + }, + "fslogixSharePath": { + "value": "[parameters('fslogixSharePath')]" + }, + "fslogixStorageAccountResourceId": { + "value": "[parameters('fslogixStorageAccountResourceId')]" + }, + "hostPoolResourceId": { + "value": "[parameters('hostPoolResourceId')]" + }, + "identityDomainName": { + "value": "[parameters('identityDomainName')]" + }, + "identityServiceProvider": { + "value": "[parameters('identityServiceProvider')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "name": { + "value": "[format('{0}{1}', parameters('namePrefix'), padLeft(add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), 4, '0'))]" + }, + "scriptName": { + "value": "[parameters('sessionHostConfigurationScript')]" + }, + "vmSize": { + "value": "[parameters('vmSize')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "1149225665070592315" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Extension deployment name." + } + }, + "identityServiceProvider": { + "type": "string", + "metadata": { + "description": "The service providing domain services for Azure Virtual Desktop." + } + }, + "identityDomainName": { + "type": "string", + "metadata": { + "description": "Identity domain name." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy compute services." + } + }, + "baseScriptUri": { + "type": "string", + "metadata": { + "description": "URI for AVD session host configuration URI path." + } + }, + "scriptName": { + "type": "string", + "metadata": { + "description": "URI for AVD session host configuration script." + } + }, + "fslogix": { + "type": "bool", + "metadata": { + "description": "Deploy FSlogix configuration." + } + }, + "fslogixStorageAccountResourceId": { + "type": "string", + "metadata": { + "description": "FSLogix storage account resource ID." + } + }, + "fslogixSharePath": { + "type": "string", + "metadata": { + "description": "File share name for FSlogix storage." + } + }, + "vmSize": { + "type": "string", + "metadata": { + "description": "Session host VM size." + } + }, + "hostPoolResourceId": { + "type": "string", + "metadata": { + "description": "AVD Host Pool Resource Id" + } + } + }, + "variables": { + "fslogixStorageAccountName": "[if(parameters('fslogix'), last(split(parameters('fslogixStorageAccountResourceId'), '/')), '')]", + "varBaseFSLogixScriptArguments": "[format('-FslogixFileShare \"{0}\"', parameters('fslogixSharePath'))]", + "varAmdVmSizes": [ + "Standard_NV4as_v4", + "Standard_NV8as_v4", + "Standard_NV16as_v4", + "Standard_NV32as_v4" + ], + "varAmdVmSize": "[contains(variables('varAmdVmSizes'), parameters('vmSize'))]", + "varNvidiaVmSizes": [ + "Standard_NV6", + "Standard_NV12", + "Standard_NV24", + "Standard_NV12s_v3", + "Standard_NV24s_v3", + "Standard_NV48s_v3", + "Standard_NC4as_T4_v3", + "Standard_NC8as_T4_v3", + "Standard_NC16as_T4_v3", + "Standard_NC64as_T4_v3", + "Standard_NV6ads_A10_v5", + "Standard_NV12ads_A10_v5", + "Standard_NV18ads_A10_v5", + "Standard_NV36ads_A10_v5", + "Standard_NV36adms_A10_v5", + "Standard_NV72ads_A10_v5" + ], + "varNvidiaVmSize": "[contains(variables('varNvidiaVmSizes'), parameters('vmSize'))]" + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2023-09-01", + "name": "[format('{0}/SessionHostConfig', parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "publisher": "Microsoft.Compute", + "type": "CustomScriptExtension", + "typeHandlerVersion": "1.10", + "autoUpgradeMinorVersion": true, + "settings": { + "fileUris": "[array(parameters('baseScriptUri'))]" + }, + "protectedSettings": { + "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -Command .\\{0} {1}', parameters('scriptName'), if(parameters('fslogix'), format('{0} {1}', format('-IdentityServiceProvider {0} -Fslogix {1} -HostPoolRegistrationToken \"{2}\" -AmdVmSize {3} -NvidiaVmSize {4}', parameters('identityServiceProvider'), parameters('fslogix'), listRegistrationTokens(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('hostPoolResourceId'), '/')[4]), 'Microsoft.DesktopVirtualization/hostPools', last(split(parameters('hostPoolResourceId'), '/'))), '2023-09-05').value[0].token, variables('varAmdVmSize'), variables('varNvidiaVmSize')), if(equals(parameters('identityServiceProvider'), 'EntraID'), format('{0} -FslogixStorageAccountKey \"{1}\"', variables('varBaseFSLogixScriptArguments'), listkeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('fslogixStorageAccountResourceId'), '/')[4]), 'Microsoft.Storage/storageAccounts', variables('fslogixStorageAccountName')), '2023-05-01').keys[0].value), if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), format('{0} -IdentityDomainName {1}', variables('varBaseFSLogixScriptArguments'), parameters('identityDomainName')), variables('varBaseFSLogixScriptArguments')))), format('-IdentityServiceProvider {0} -Fslogix {1} -HostPoolRegistrationToken \"{2}\" -AmdVmSize {3} -NvidiaVmSize {4}', parameters('identityServiceProvider'), parameters('fslogix'), listRegistrationTokens(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('hostPoolResourceId'), '/')[4]), 'Microsoft.DesktopVirtualization/hostPools', last(split(parameters('hostPoolResourceId'), '/'))), '2023-09-05').value[0].token, variables('varAmdVmSize'), variables('varNvidiaVmSize'))))]" + } + } + } + ] + } + }, + "dependsOn": [ + "ama", + "sessionHosts" + ] + } + ] + } + }, + "dependsOn": [ + "baselineResourceGroups", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('AVD-MGMT-Plane-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", + "[subscriptionResourceId(format('{0}', parameters('avdWorkloadSubsId')), 'Microsoft.Resources/deployments', format('SMB-Storage-{0}', parameters('time')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]", + "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time')))]" + ] + }, + { + "condition": "[parameters('deployGpuPolicies')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('GPU-VM-Extensions-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('avdWorkloadSubsId'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "computeObjectsRgName": { + "value": "[variables('varComputeObjectsRgName')]" + }, + "location": { + "value": "[parameters('avdSessionHostLocation')]" + }, + "subscriptionId": { + "value": "[parameters('avdWorkloadSubsId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12630662508259220166" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy compute services." + } + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "computeObjectsRgName": { + "type": "string", + "metadata": { + "description": "AVD Resource Group Name for the service objects." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + } + }, + "variables": { + "$fxv#0": "{\r\n \"name\": \"policy-deploy-amd-gpu-driver\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy AMD GPU Driver Extension\",\r\n \"description\": \"This policy definition deploys the AMD GPU Driver extension on AMD's SKU VMs.\",\r\n \"metadata\": {\r\n \"version\": \"1.1.0\",\r\n \"category\": \"Drivers\"\r\n },\r\n \"parameters\": {\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Compute/virtualMachines\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/sku.name\",\r\n \"in\": [\r\n \"Standard_NV4as_v4\",\r\n \"Standard_NV8as_v4\",\r\n \"Standard_NV16as_v4\",\r\n \"Standard_NV32as_v4\"\r\n ]\r\n }\r\n ]\r\n },\r\n \"then\": {\r\n \"effect\": \"deployIfNotExists\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Compute/virtualMachines/extensions\",\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c\"\r\n ],\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/extensions/publisher\",\r\n \"equals\": \"Microsoft.HpcCompute\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/extensions/type\",\r\n \"equals\": \"AmdGpuDriverWindows\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/extensions/provisioningState\",\r\n \"in\": [\r\n \"Succeeded\"\r\n ]\r\n }\r\n ]\r\n },\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"vmName\": {\r\n \"type\": \"string\"\r\n },\r\n \"location\": {\r\n \"type\": \"string\"\r\n }\r\n },\r\n \"variables\": {\r\n \"vmExtensionName\": \"AmdGpuDriverWindows\",\r\n \"vmExtensionPublisher\": \"Microsoft.HpcCompute\",\r\n \"vmExtensionType\": \"AmdGpuDriverWindows\",\r\n \"vmExtensionTypeHandlerVersion\": \"1.0\"\r\n },\r\n \"resources\": [\r\n {\r\n \"name\": \"[concat(parameters('vmName'), '/', variables('vmExtensionName'))]\",\r\n \"type\": \"Microsoft.Compute/virtualMachines/extensions\",\r\n \"location\": \"[parameters('location')]\",\r\n \"apiVersion\": \"2018-06-01\",\r\n \"properties\": {\r\n \"publisher\": \"[variables('vmExtensionPublisher')]\",\r\n \"type\": \"[variables('vmExtensionType')]\",\r\n \"typeHandlerVersion\": \"[variables('vmExtensionTypeHandlerVersion')]\",\r\n \"autoUpgradeMinorVersion\": true\r\n }\r\n }\r\n ],\r\n \"outputs\": {\r\n \"policy\": {\r\n \"type\": \"string\",\r\n \"value\": \"[concat('Enabled extension for VM', ': ', parameters('vmName'))]\"\r\n }\r\n }\r\n },\r\n \"parameters\": {\r\n \"vmName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}", + "$fxv#1": "{\r\n \"name\": \"policy-deploy-nvidia-gpu-driver\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Nvidia GPU Driver Extension\",\r\n \"description\": \"This policy definition deploys the Nvidia GPU Driver extension on Nvidia's SKU VMs.\",\r\n \"metadata\": {\r\n \"version\": \"1.1.0\",\r\n \"category\": \"Drivers\"\r\n },\r\n \"parameters\": {\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Compute/virtualMachines\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/sku.name\",\r\n \"in\": [\r\n \"Standard_NV6\",\r\n \"Standard_NV12\",\r\n \"Standard_NV24\",\r\n \"Standard_NV12s_v3\",\r\n \"Standard_NV24s_v3\",\r\n \"Standard_NV48s_v3\",\r\n \"Standard_NC4as_T4_v3\",\r\n \"Standard_NC8as_T4_v3\",\r\n \"Standard_NC16as_T4_v3\",\r\n \"Standard_NC64as_T4_v3\",\r\n \"Standard_NV6ads_A10_v5\",\r\n \"Standard_NV12ads_A10_v5\",\r\n \"Standard_NV18ads_A10_v5\",\r\n \"Standard_NV36ads_A10_v5\",\r\n \"Standard_NV36adms_A10_v5\",\r\n \"Standard_NV72ads_A10_v5\"\r\n ]\r\n }\r\n ]\r\n },\r\n \"then\": {\r\n \"effect\": \"deployIfNotExists\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Compute/virtualMachines/extensions\",\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c\"\r\n ],\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/extensions/publisher\",\r\n \"equals\": \"Microsoft.HpcCompute\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/extensions/type\",\r\n \"equals\": \"NvidiaGpuDriverWindows\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/extensions/provisioningState\",\r\n \"in\": [\r\n \"Succeeded\"\r\n ]\r\n }\r\n ]\r\n },\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"vmName\": {\r\n \"type\": \"string\"\r\n },\r\n \"location\": {\r\n \"type\": \"string\"\r\n }\r\n },\r\n \"variables\": {\r\n \"vmExtensionName\": \"NvidiaGpuDriverWindows\",\r\n \"vmExtensionPublisher\": \"Microsoft.HpcCompute\",\r\n \"vmExtensionType\": \"NvidiaGpuDriverWindows\",\r\n \"vmExtensionTypeHandlerVersion\": \"1.2\"\r\n },\r\n \"resources\": [\r\n {\r\n \"name\": \"[concat(parameters('vmName'), '/', variables('vmExtensionName'))]\",\r\n \"type\": \"Microsoft.Compute/virtualMachines/extensions\",\r\n \"location\": \"[parameters('location')]\",\r\n \"apiVersion\": \"2018-06-01\",\r\n \"properties\": {\r\n \"publisher\": \"[variables('vmExtensionPublisher')]\",\r\n \"type\": \"[variables('vmExtensionType')]\",\r\n \"typeHandlerVersion\": \"[variables('vmExtensionTypeHandlerVersion')]\",\r\n \"autoUpgradeMinorVersion\": true\r\n }\r\n }\r\n ],\r\n \"outputs\": {\r\n \"policy\": {\r\n \"type\": \"string\",\r\n \"value\": \"[concat('Enabled extension for VM', ': ', parameters('vmName'))]\"\r\n }\r\n }\r\n },\r\n \"parameters\": {\r\n \"vmName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}", + "varCustomPolicyDefinitions": [ + { + "deploymentName": "AMD-Policy", + "libDefinition": "[json(variables('$fxv#0'))]" + }, + { + "deploymentName": "Nvidia-Policy", + "libDefinition": "[json(variables('$fxv#1'))]" + } + ] + }, + "resources": [ + { + "copy": { + "name": "gpuPolicyDefinitions", + "count": "[length(variables('varCustomPolicyDefinitions'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "description": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.description]" + }, + "displayName": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.displayName]" + }, + "name": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.name]" + }, + "metadata": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.metadata]" + }, + "mode": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.mode]" + }, + "parameters": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.parameters]" + }, + "policyRule": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.policyRule]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "15296566503434303805" + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. Specifies the name of the policy definition. Maximum length is 64 characters." + } + }, + "displayName": { + "type": "string", + "defaultValue": "", + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy definition. Maximum length is 128 characters." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The policy definition description." + } + }, + "mode": { + "type": "string", + "defaultValue": "All", + "allowedValues": [ + "All", + "Indexed", + "Microsoft.KeyVault.Data", + "Microsoft.ContainerService.Data", + "Microsoft.Kubernetes.Data", + "Microsoft.Network.Data" + ], + "metadata": { + "description": "Optional. The policy definition mode. Default is All, Some examples are All, Indexed, Microsoft.KeyVault.Data." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy Definition metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy definition parameters that can be used in policy definition references." + } + }, + "policyRule": { + "type": "object", + "metadata": { + "description": "Required. The Policy Rule details for the Policy Definition." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyDefinitions", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "properties": { + "policyType": "Custom", + "mode": "[parameters('mode')]", + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "parameters": "[if(not(empty(parameters('parameters'))), parameters('parameters'), null())]", + "policyRule": "[parameters('policyRule')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy Definition Name." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Definition resource ID." + }, + "value": "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name'))]" + }, + "roleDefinitionIds": { + "type": "array", + "metadata": { + "description": "Policy Definition Role Definition IDs." + }, + "value": "[if(contains(reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then, 'details'), if(contains(reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then.details, 'roleDefinitionIds'), reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then.details.roleDefinitionIds, createArray()), createArray())]" + } + } + } + } + }, + { + "copy": { + "name": "gpuPolicyAssignmentsCompute", + "count": "[length(variables('varCustomPolicyDefinitions'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Policy-Assign-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.name]" + }, + "displayName": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.displayName]" + }, + "description": { + "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.description]" + }, + "identity": { + "value": "SystemAssigned" + }, + "location": { + "value": "[parameters('location')]" + }, + "policyDefinitionId": { + "value": "[reference(subscriptionResourceId(format('{0}', parameters('subscriptionId')), 'Microsoft.Resources/deployments', format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.resourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "10386382608825992636" + }, + "name": "Policy Assignments (Resource Group scope)", + "description": "This module deploys a Policy Assignment at a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 64, + "metadata": { + "description": "Required. Specifies the name of the policy assignment. Maximum length is 64 characters for resource group scope." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. This message will be part of response in case of policy violation." + } + }, + "displayName": { + "type": "string", + "defaultValue": "", + "maxLength": 128, + "metadata": { + "description": "Optional. The display name of the policy assignment. Maximum length is 128 characters." + } + }, + "policyDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. Specifies the ID of the policy definition or policy set definition being assigned." + } + }, + "parameters": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Parameters for the policy assignment if needed." + } + }, + "identity": { + "type": "string", + "defaultValue": "SystemAssigned", + "allowedValues": [ + "SystemAssigned", + "UserAssigned", + "None" + ], + "metadata": { + "description": "Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions." + } + }, + "userAssignedIdentityId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource ID for the user assigned identity to assign to the policy assignment." + } + }, + "roleDefinitionIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs." + } + }, + "nonComplianceMessages": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The messages that describe why a resource is non-compliant with the policy." + } + }, + "enforcementMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "DoNotEnforce" + ], + "metadata": { + "description": "Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce." + } + }, + "notScopes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy excluded scopes." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "overrides": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition." + } + }, + "resourceSelectors": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location." + } + }, + "subscriptionId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "Optional. The Target Scope for the Policy. The name of the resource group for the policy assignment. If not provided, will use the current scope for deployment." + } + } + }, + "variables": { + "identityVar": "[if(equals(parameters('identity'), 'SystemAssigned'), createObject('type', parameters('identity')), if(equals(parameters('identity'), 'UserAssigned'), createObject('type', parameters('identity'), 'userAssignedIdentities', createObject(format('{0}', parameters('userAssignedIdentityId')), createObject())), null()))]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2022-06-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "properties": { + "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", + "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", + "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", + "policyDefinitionId": "[parameters('policyDefinitionId')]", + "parameters": "[parameters('parameters')]", + "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), parameters('nonComplianceMessages'), createArray())]", + "enforcementMode": "[parameters('enforcementMode')]", + "notScopes": "[if(not(empty(parameters('notScopes'))), parameters('notScopes'), createArray())]", + "overrides": "[if(not(empty(parameters('overrides'))), parameters('overrides'), createArray())]", + "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), createArray())]" + }, + "identity": "[variables('identityVar')]" + }, + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('roleDefinitionIds'))]" + }, + "condition": "[and(not(empty(parameters('roleDefinitionIds'))), equals(parameters('identity'), 'SystemAssigned'))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), parameters('roleDefinitionIds')[copyIndex()], parameters('location'), parameters('name'))]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionIds')[copyIndex()]]", + "principalId": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "Policy Assignment Name." + }, + "value": "[parameters('name')]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Policy Assignment principal ID." + }, + "value": "[coalesce(tryGet(tryGet(reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Policy Assignment resource ID." + }, + "value": "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the policy was assigned to." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId(format('{0}', parameters('subscriptionId')), 'Microsoft.Resources/deployments', format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time')))]" + ] + }, + { + "copy": { + "name": "policySetRemediationCompute", + "count": "[length(variables('varCustomPolicyDefinitions'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('remediate-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, copyIndex())]", + "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, copyIndex())]" + }, + "policyAssignmentId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('computeObjectsRgName'))), 'Microsoft.Resources/deployments', format('Policy-Assign-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.resourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "8141314117626850328" + }, + "name": "Policy Insights Remediations (Resource Group scope)", + "description": "This module deploys a Policy Insights Remediation on a Resource Group scope.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specifies the name of the policy remediation." + } + }, + "failureThresholdPercentage": { + "type": "string", + "defaultValue": "1", + "metadata": { + "description": "Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail." + } + }, + "filtersLocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The filters that will be applied to determine which resources to remediate." + } + }, + "parallelDeployments": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "maxValue": 30, + "metadata": { + "description": "Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used." + } + }, + "resourceCount": { + "type": "int", + "defaultValue": 500, + "minValue": 1, + "maxValue": 50000, + "metadata": { + "description": "Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used." + } + }, + "resourceDiscoveryMode": { + "type": "string", + "defaultValue": "ExistingNonCompliant", + "allowedValues": [ + "ExistingNonCompliant", + "ReEvaluateCompliance" + ], + "metadata": { + "description": "Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified." + } + }, + "policyAssignmentId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the policy assignment that should be remediated." + } + }, + "policyDefinitionReferenceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location deployment metadata." + } + } + }, + "resources": [ + { + "type": "Microsoft.PolicyInsights/remediations", + "apiVersion": "2021-10-01", + "name": "[parameters('name')]", + "properties": { + "failureThreshold": { + "percentage": "[json(parameters('failureThresholdPercentage'))]" + }, + "filters": { + "locations": "[parameters('filtersLocations')]" + }, + "parallelDeployments": "[parameters('parallelDeployments')]", + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceId": "[parameters('policyDefinitionReferenceId')]", + "resourceCount": "[parameters('resourceCount')]", + "resourceDiscoveryMode": "[parameters('resourceDiscoveryMode')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the remediation." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the remediation." + }, + "value": "[resourceId('Microsoft.PolicyInsights/remediations', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed remediation." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[parameters('location')]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('computeObjectsRgName'))), 'Microsoft.Resources/deployments', format('Policy-Assign-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time')))]" + ] + } + ] + } + }, + "dependsOn": [ + "sessionHosts" + ] + }, + { + "condition": "[parameters('deployDefender')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Defender-Policies-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('avdWorkloadSubsId'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "enableDefForServers": { + "value": "[parameters('enableDefForServers')]" + }, + "enableDefForStorage": { + "value": "[parameters('enableDefForStorage')]" + }, + "enableDefForKeyVault": { + "value": "[parameters('enableDefForKeyVault')]" + }, + "enableDefForArm": { + "value": "[parameters('enableDefForArm')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "17973539529965183406" + } + }, + "parameters": { + "initiativeName": { + "type": "string", + "defaultValue": "Custom - Deploy Microsoft Defender for Cloud Security - AVD", + "metadata": { + "description": "Name of the initiative definition." + } + }, + "initiativeDisplayName": { + "type": "string", + "defaultValue": "Custom - Deploy Microsoft Defender for Cloud Security - AVD", + "metadata": { + "description": "Display name of the initiative." + } + }, + "initiativeDescription": { + "type": "string", + "defaultValue": "This initiative deploys Microsoft Defender for Cloud Security for AVD.", + "metadata": { + "description": "Description of the initiative." + } + }, + "initiativeCategory": { + "type": "string", + "defaultValue": "Security Center", + "metadata": { + "description": "Category of the initiative." + } + }, + "effect": { + "type": "string", + "defaultValue": "DeployIfNotExists", + "allowedValues": [ + "DeployIfNotExists", + "Disabled" + ], + "metadata": { + "description": "Effect for the policy." + } + }, + "isOnUploadMalwareScanningEnabled": { + "type": "string", + "defaultValue": "true", + "allowedValues": [ + "true", + "false" + ], + "metadata": { + "description": "Enable or disable the Malware Scanning add-on feature." + } + }, + "capGBPerMonthPerStorageAccount": { + "type": "int", + "defaultValue": 5000, + "metadata": { + "description": "Cap GB scanned per month per storage account." + } + }, + "isSensitiveDataDiscoveryEnabled": { + "type": "string", + "defaultValue": "true", + "allowedValues": [ + "true", + "false" + ], + "metadata": { + "description": "Enable or disable the Sensitive Data Threat Detection add-on feature." + } + }, + "keyVaultSubPlan": { + "type": "string", + "defaultValue": "PerTransaction", + "allowedValues": [ + "PerTransaction", + "PerKeyVault" + ], + "metadata": { + "description": "Select a Defender for Key Vault plan." + } + }, + "resourceManagerSubPlan": { + "type": "string", + "defaultValue": "PerApiCall", + "allowedValues": [ + "PerSubscription", + "PerApiCall" + ], + "metadata": { + "description": "Select a Defender for Resource Manager plan." + } + }, + "enableDefForServers": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable or disable the \"Configure Azure Defender for servers to be enabled\" policy." + } + }, + "enableDefForStorage": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable or disable the \"Configure Microsoft Defender for Storage to be enabled\" policy." + } + }, + "enableDefForKeyVault": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable or disable the \"Configure Microsoft Defender for Key Vault plan\" policy." + } + }, + "enableDefForArm": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable or disable the \"Configure Azure Defender for Resource Manager to be enabled\" policy." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/policySetDefinitions", + "apiVersion": "2023-04-01", + "name": "[parameters('initiativeName')]", + "properties": { + "displayName": "[parameters('initiativeDisplayName')]", + "description": "[parameters('initiativeDescription')]", + "version": "1.0.0", + "metadata": { + "category": "[parameters('initiativeCategory')]", + "version": "1.0.0" + }, + "policyDefinitions": "[concat(createArray(createObject('policyDefinitionReferenceId', 'EnsureContactEmail', 'policyDefinitionId', tenantResourceId('Microsoft.Authorization/policyDefinitions', '4f4f78b8-e367-4b10-a341-d9a4ad5cf1c7'), 'parameters', createObject('effect', createObject('value', 'AuditIfNotExists')))), if(parameters('enableDefForServers'), createArray(createObject('policyDefinitionReferenceId', 'DefenderForServers', 'policyDefinitionId', tenantResourceId('Microsoft.Authorization/policyDefinitions', '8e86a5b6-b9bd-49d1-8e21-4bb8a0862222'), 'parameters', createObject('effect', createObject('value', parameters('effect'))))), createArray()), if(parameters('enableDefForStorage'), createArray(createObject('policyDefinitionReferenceId', 'DefenderForStorage', 'policyDefinitionId', tenantResourceId('Microsoft.Authorization/policyDefinitions', 'cfdc5972-75b3-4418-8ae1-7f5c36839390'), 'parameters', createObject('effect', createObject('value', parameters('effect')), 'isOnUploadMalwareScanningEnabled', createObject('value', parameters('isOnUploadMalwareScanningEnabled')), 'capGBPerMonthPerStorageAccount', createObject('value', parameters('capGBPerMonthPerStorageAccount')), 'isSensitiveDataDiscoveryEnabled', createObject('value', parameters('isSensitiveDataDiscoveryEnabled'))))), createArray()), if(parameters('enableDefForKeyVault'), createArray(createObject('policyDefinitionReferenceId', 'DefenderForKeyVault', 'policyDefinitionId', tenantResourceId('Microsoft.Authorization/policyDefinitions', '1f725891-01c0-420a-9059-4fa46cb770b7'), 'parameters', createObject('effect', createObject('value', parameters('effect')), 'subPlan', createObject('value', parameters('keyVaultSubPlan'))))), createArray()), if(parameters('enableDefForArm'), createArray(createObject('policyDefinitionReferenceId', 'DefenderForARM', 'policyDefinitionId', tenantResourceId('Microsoft.Authorization/policyDefinitions', 'b7021b2b-08fd-4dc0-9de7-3c6ece09faf9'), 'parameters', createObject('effect', createObject('value', parameters('effect')), 'subPlan', createObject('value', parameters('resourceManagerSubPlan'))))), createArray()))]" + } + } + ] + } + }, + "dependsOn": [ + "sessionHosts" + ] + } + ] +} \ No newline at end of file diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 82c176524..e83159891 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1135,6 +1135,31 @@ "placeholder": "Example: OU=storage,OU=avd,DC=contoso,DC=com", "constraints": {} }, + { + "name": "storageServiceSelector", + "type": "Microsoft.Common.DropDown", + "visible": "[steps('storage').storageFslogix.fslogixDeployment]", + "label": "Storage service", + "filter": true, + "defaultValue": "Azure Files", + "toolTip": "Select the storage service (Azure Files or ANF) to use for FSLogix and/or App Attach containers. ANF is only available when using AD DS or Microsoft Entra Domain Services identity service providers", + "constraints": { + "required": true, + "allowedValues": [ + { + "label": "Azure Files", + "description": "", + "value": "AzureFiles" + }, + { + "label": "Azure NetApp Files", + "description": "", + "value": "ANF", + "visible": "[or(equals(steps('identity').identityDomainInformation.identityServiceProvider, 'ADDS'), equals(steps('identity').identityDomainInformation.identityServiceProvider, 'EntraDS'))]" + } + ] + } + }, { "name": "storageApi", "type": "Microsoft.Solutions.ArmApiControl", @@ -1147,6 +1172,7 @@ "name": "storageGeneralSettingsZoneRedundancy", "type": "Microsoft.Common.DropDown", "label": "Storage account type", + "visible": "[if(steps('storage').storageGeneralSettings.storageServiceSelector, equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles'), true, false)]", "defaultValue": "[if(equals(steps('sessionHosts').sessionHostsRegionSection.sessionHostsAvailabilitySettings, true), 'Zone-Redundant Storage', 'Locally Redundant Storage')]", "toolTip": "Select to replicate storage across availability zones or only use local redundancy.", "constraints": { @@ -1165,7 +1191,8 @@ { "name": "fslogixDeployment", "type": "Microsoft.Common.CheckBox", - "label": "FSLogix profile management", + "label": "Deploy storage", + "visible": true, "defaultValue": true, "toolTip": "Deploys FSLogix containers and session host setup for user's profiles." }, @@ -1173,10 +1200,10 @@ "name": "fslogixStorageAccountSku", "type": "Microsoft.Common.DropDown", "visible": "[steps('storage').storageFslogix.fslogixDeployment]", - "label": "File share peformance", + "label": "File share performance", "filter": true, "defaultValue": "Premium", - "toolTip": "Storage account performance for FSLogix storage. Recommended tier is Premium.", + "toolTip": "Performance for App Attach storage (Azure files or ANF). Recommended tier is Premium for storage account and Standard for ANF.", "constraints": { "required": true, "allowedValues": [ @@ -1189,6 +1216,12 @@ "label": "Standard", "description": "", "value": "Standard" + }, + { + "label": "Ultra (ANF)", + "description": "", + "value": "Ultra", + "visible": "[equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')]" } ] } @@ -1198,10 +1231,10 @@ "type": "Microsoft.Common.Slider", "visible": "[steps('storage').storageFslogix.fslogixDeployment]", "label": "File share size", - "subLabel": "x 100GB", + "subLabel": "GB", "toolTip": "Size of Azure File share quota, the maximum sizes are 5TB for standard SKU and 100TB for premium SKU", - "min": 1, - "max": 100, + "min": 50, + "max": 100000, "defaultValue": 1, "showStepMarkers": true, "constraints": { @@ -1230,7 +1263,7 @@ "name": "appAttachStorageDeployment", "type": "Microsoft.Common.CheckBox", "visible": "[not(contains(steps('basics').resourceScope.location.name, 'china'))]", - "label": "Create App Attach storage", + "label": "Deploy storage", "toolTip": "Deploys App Attach containers and permissions setup." }, { @@ -1240,7 +1273,7 @@ "label": "File share performance", "filter": true, "defaultValue": "Premium", - "toolTip": "Storage account performance for App Attach storage. Recommended tier is Premium.", + "toolTip": "Performance for App Attach storage (Azure files or ANF). Recommended tier is Premium for storage account and Standard for ANF.", "constraints": { "required": true, "allowedValues": [ @@ -1253,6 +1286,12 @@ "label": "Standard", "description": "", "value": "Standard" + }, + { + "label": "Ultra (ANF)", + "description": "", + "value": "Ultra", + "visible": "[equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')]" } ] } @@ -1262,10 +1301,10 @@ "type": "Microsoft.Common.Slider", "visible": "[and(equals(steps('storage').storageAppAttach.appAttachStorageDeployment, true), not(contains(steps('basics').resourceScope.location.name, 'china')))]", "label": "File share size", - "subLabel": "x 100GB", + "subLabel": "GB", "toolTip": "Size of Azure File share quota, the maximum sizes are 5TB for standard SKU and 100TB for premium SKU", - "min": 1, - "max": 100, + "min": 50, + "max": 100000, "defaultValue": 1, "showStepMarkers": true, "constraints": { @@ -2777,7 +2816,7 @@ "avdArmServicePrincipalObjectId": "[if(and(equals(steps('identity').identityDomainInformation.identityServiceProvider, 'EntraID'), steps('storage').storageAppAttach.appAttachStorageDeployment), if(empty(first(steps('basics').avdArmServicePrincipal.value)), first(map(steps('storage').storageAppAttach.armServicePrincipalPickerBlade.transformed.selection, (sp) => sp.id)), first(steps('basics').avdArmServicePrincipal.value.id)), '')]", "deploymentPrefix": "[steps('basics').deploymentSpecs.deploymentPrefix]", "deploymentEnvironment": "[steps('basics').deploymentSpecs.deploymentEnvironment]", - "diskZeroTrust": "[steps('sessionHosts').sessionHostsSettingsSection.sessionHostDiskZeroTrust]", + "storageServiceSelector": "[if(or(steps('storage').storageFslogix.fslogixDeployment, equals(steps('storage').storageAppAttach.appAttachStorageDeployment), steps('storage').storageServiceSelector, 'AzureFiles')]", "avdManagementPlaneLocation": "[steps('basics').resourceScope.location.name]", "avdSessionHostLocation": "[if(equals(steps('sessionHosts').deploySessionHosts, true), steps('sessionHosts').sessionHostsRegionSection.sessionHostsRegion, steps('basics').resourceScope.location.name)]", "avdWorkloadSubsId": "[steps('basics').resourceScope.subscription.subscriptionId]", diff --git a/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 b/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 index ef18405c4..f642dde16 100644 --- a/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 +++ b/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 @@ -173,10 +173,6 @@ if ($StorageService -eq 'ANF') { Try { Write-Log "Mounting Profile storage $StorageAccountName as a drive $DriveLetter" if (-not (Get-PSDrive -Name $DriveLetter -ErrorAction SilentlyContinue)) { - #$UserStorage = "/user:Azure\$StorageAccountName" - #Write-Log "User storage: $UserStorage" - #$StorageKey = (Get-AzStorageAccountKey -ResourceGroupName $StorageAccountRG -AccountName $StorageAccountName) | Where-Object { $_.KeyName -eq "key1" } - #Write-Log "File Share location: $FileShareLocation" net use ${DriveLetter}: $FileShareLocation $UserStorage $StorageKey.Value } else { From 205199cef441fee7162e7e5a253a6b4e018e2875 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 09:12:32 -0500 Subject: [PATCH 22/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index e83159891..5850b127a 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -2816,7 +2816,7 @@ "avdArmServicePrincipalObjectId": "[if(and(equals(steps('identity').identityDomainInformation.identityServiceProvider, 'EntraID'), steps('storage').storageAppAttach.appAttachStorageDeployment), if(empty(first(steps('basics').avdArmServicePrincipal.value)), first(map(steps('storage').storageAppAttach.armServicePrincipalPickerBlade.transformed.selection, (sp) => sp.id)), first(steps('basics').avdArmServicePrincipal.value.id)), '')]", "deploymentPrefix": "[steps('basics').deploymentSpecs.deploymentPrefix]", "deploymentEnvironment": "[steps('basics').deploymentSpecs.deploymentEnvironment]", - "storageServiceSelector": "[if(or(steps('storage').storageFslogix.fslogixDeployment, equals(steps('storage').storageAppAttach.appAttachStorageDeployment), steps('storage').storageServiceSelector, 'AzureFiles')]", + "storageServiceSelector": "[if(or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment), steps('storage').storageServiceSelector, 'AzureFiles')]", "avdManagementPlaneLocation": "[steps('basics').resourceScope.location.name]", "avdSessionHostLocation": "[if(equals(steps('sessionHosts').deploySessionHosts, true), steps('sessionHosts').sessionHostsRegionSection.sessionHostsRegion, steps('basics').resourceScope.location.name)]", "avdWorkloadSubsId": "[steps('basics').resourceScope.subscription.subscriptionId]", From 3fb061e8ff038f0a678ee6826e9fe2133da9f5de Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 09:16:10 -0500 Subject: [PATCH 23/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 5850b127a..040594021 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -2816,7 +2816,7 @@ "avdArmServicePrincipalObjectId": "[if(and(equals(steps('identity').identityDomainInformation.identityServiceProvider, 'EntraID'), steps('storage').storageAppAttach.appAttachStorageDeployment), if(empty(first(steps('basics').avdArmServicePrincipal.value)), first(map(steps('storage').storageAppAttach.armServicePrincipalPickerBlade.transformed.selection, (sp) => sp.id)), first(steps('basics').avdArmServicePrincipal.value.id)), '')]", "deploymentPrefix": "[steps('basics').deploymentSpecs.deploymentPrefix]", "deploymentEnvironment": "[steps('basics').deploymentSpecs.deploymentEnvironment]", - "storageServiceSelector": "[if(or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment), steps('storage').storageServiceSelector, 'AzureFiles')]", + "storageServiceSelector": "[if(or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment), steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles')]", "avdManagementPlaneLocation": "[steps('basics').resourceScope.location.name]", "avdSessionHostLocation": "[if(equals(steps('sessionHosts').deploySessionHosts, true), steps('sessionHosts').sessionHostsRegionSection.sessionHostsRegion, steps('basics').resourceScope.location.name)]", "avdWorkloadSubsId": "[steps('basics').resourceScope.subscription.subscriptionId]", From d2068a16c507394db1c52fcb49d68dc075fddb82 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 09:19:35 -0500 Subject: [PATCH 24/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 040594021..99f4d37a5 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1172,7 +1172,7 @@ "name": "storageGeneralSettingsZoneRedundancy", "type": "Microsoft.Common.DropDown", "label": "Storage account type", - "visible": "[if(steps('storage').storageGeneralSettings.storageServiceSelector, equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles'), true, false)]", + "visible": "[if(equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles'), true, false)]", "defaultValue": "[if(equals(steps('sessionHosts').sessionHostsRegionSection.sessionHostsAvailabilitySettings, true), 'Zone-Redundant Storage', 'Locally Redundant Storage')]", "toolTip": "Select to replicate storage across availability zones or only use local redundancy.", "constraints": { From b173f98efe874fbff26fbc7d3c34944e6304f99c Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 09:26:53 -0500 Subject: [PATCH 25/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 99f4d37a5..fd2064c7a 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1138,7 +1138,7 @@ { "name": "storageServiceSelector", "type": "Microsoft.Common.DropDown", - "visible": "[steps('storage').storageFslogix.fslogixDeployment]", + "visible": "[or(steps('storage').storageFslogix.fslogixDeployment), steps('storage').storageAppAttach.appAttachStorageDeployment)]", "label": "Storage service", "filter": true, "defaultValue": "Azure Files", From 42e6ae1561e2e1e237222638847632239191676d Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 09:29:40 -0500 Subject: [PATCH 26/55] updates --- workload/portal-ui/portal-ui-baseline.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index fd2064c7a..7c5563940 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1155,7 +1155,7 @@ "label": "Azure NetApp Files", "description": "", "value": "ANF", - "visible": "[or(equals(steps('identity').identityDomainInformation.identityServiceProvider, 'ADDS'), equals(steps('identity').identityDomainInformation.identityServiceProvider, 'EntraDS'))]" + "visible": "[equals(steps('identity').identityDomainInformation.identityServiceProvider, 'ADDS')]" } ] } @@ -1172,7 +1172,7 @@ "name": "storageGeneralSettingsZoneRedundancy", "type": "Microsoft.Common.DropDown", "label": "Storage account type", - "visible": "[if(equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles'), true, false)]", + "visible": "[equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles')]", "defaultValue": "[if(equals(steps('sessionHosts').sessionHostsRegionSection.sessionHostsAvailabilitySettings, true), 'Zone-Redundant Storage', 'Locally Redundant Storage')]", "toolTip": "Select to replicate storage across availability zones or only use local redundancy.", "constraints": { From 553a85b92fd0a5f00d52a60b5e4687959dfcb3e9 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 09:34:23 -0500 Subject: [PATCH 27/55] updates --- workload/portal-ui/portal-ui-baseline.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 7c5563940..44752e980 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1154,8 +1154,7 @@ { "label": "Azure NetApp Files", "description": "", - "value": "ANF", - "visible": "[equals(steps('identity').identityDomainInformation.identityServiceProvider, 'ADDS')]" + "value": "ANF" } ] } @@ -1172,7 +1171,7 @@ "name": "storageGeneralSettingsZoneRedundancy", "type": "Microsoft.Common.DropDown", "label": "Storage account type", - "visible": "[equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles')]", + "visible": true, "defaultValue": "[if(equals(steps('sessionHosts').sessionHostsRegionSection.sessionHostsAvailabilitySettings, true), 'Zone-Redundant Storage', 'Locally Redundant Storage')]", "toolTip": "Select to replicate storage across availability zones or only use local redundancy.", "constraints": { From 1d7732b80e7cdaf84174d4981ef908f00727f046 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 09:36:06 -0500 Subject: [PATCH 28/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 44752e980..cfb0b8fa3 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1171,7 +1171,7 @@ "name": "storageGeneralSettingsZoneRedundancy", "type": "Microsoft.Common.DropDown", "label": "Storage account type", - "visible": true, + "visible": "[and(equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles'), or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment))]", "defaultValue": "[if(equals(steps('sessionHosts').sessionHostsRegionSection.sessionHostsAvailabilitySettings, true), 'Zone-Redundant Storage', 'Locally Redundant Storage')]", "toolTip": "Select to replicate storage across availability zones or only use local redundancy.", "constraints": { From d59cb2891ba929c212e047243e39c63028f07e3c Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 09:38:44 -0500 Subject: [PATCH 29/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index cfb0b8fa3..5f100528a 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1171,7 +1171,7 @@ "name": "storageGeneralSettingsZoneRedundancy", "type": "Microsoft.Common.DropDown", "label": "Storage account type", - "visible": "[and(equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles'), or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment))]", + "visible": "[and(equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'Azure Files'), or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment))]", "defaultValue": "[if(equals(steps('sessionHosts').sessionHostsRegionSection.sessionHostsAvailabilitySettings, true), 'Zone-Redundant Storage', 'Locally Redundant Storage')]", "toolTip": "Select to replicate storage across availability zones or only use local redundancy.", "constraints": { From 8fa3464b50190a6a9dc9adea7253e1550d7ddd7e Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 09:41:10 -0500 Subject: [PATCH 30/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 5f100528a..4ad3ac1d5 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1171,7 +1171,7 @@ "name": "storageGeneralSettingsZoneRedundancy", "type": "Microsoft.Common.DropDown", "label": "Storage account type", - "visible": "[and(equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'Azure Files'), or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment))]", + "visible": "[or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment)]", "defaultValue": "[if(equals(steps('sessionHosts').sessionHostsRegionSection.sessionHostsAvailabilitySettings, true), 'Zone-Redundant Storage', 'Locally Redundant Storage')]", "toolTip": "Select to replicate storage across availability zones or only use local redundancy.", "constraints": { From 1b552b0a0b0e106f2f67ee1898741d6aab2e1899 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 09:42:51 -0500 Subject: [PATCH 31/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 4ad3ac1d5..cfb0b8fa3 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1171,7 +1171,7 @@ "name": "storageGeneralSettingsZoneRedundancy", "type": "Microsoft.Common.DropDown", "label": "Storage account type", - "visible": "[or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment)]", + "visible": "[and(equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles'), or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment))]", "defaultValue": "[if(equals(steps('sessionHosts').sessionHostsRegionSection.sessionHostsAvailabilitySettings, true), 'Zone-Redundant Storage', 'Locally Redundant Storage')]", "toolTip": "Select to replicate storage across availability zones or only use local redundancy.", "constraints": { From cedc88344f1863b75d40bab992cced878aea67f1 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 10:05:37 -0500 Subject: [PATCH 32/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index cfb0b8fa3..707f042c4 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1171,7 +1171,7 @@ "name": "storageGeneralSettingsZoneRedundancy", "type": "Microsoft.Common.DropDown", "label": "Storage account type", - "visible": "[and(equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles'), or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment))]", + "visible": "[equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')]", "defaultValue": "[if(equals(steps('sessionHosts').sessionHostsRegionSection.sessionHostsAvailabilitySettings, true), 'Zone-Redundant Storage', 'Locally Redundant Storage')]", "toolTip": "Select to replicate storage across availability zones or only use local redundancy.", "constraints": { From 846d71b6a746dbe66235ea7b0de28d5ab101cef9 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 10:08:02 -0500 Subject: [PATCH 33/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 707f042c4..4447e2a0a 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1171,7 +1171,7 @@ "name": "storageGeneralSettingsZoneRedundancy", "type": "Microsoft.Common.DropDown", "label": "Storage account type", - "visible": "[equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')]", + "visible": "[if(equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF'), true, false)]", "defaultValue": "[if(equals(steps('sessionHosts').sessionHostsRegionSection.sessionHostsAvailabilitySettings, true), 'Zone-Redundant Storage', 'Locally Redundant Storage')]", "toolTip": "Select to replicate storage across availability zones or only use local redundancy.", "constraints": { From cc1e0fae23293bf51e1c26b02caafd73a0e73569 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 11:14:59 -0500 Subject: [PATCH 34/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 4447e2a0a..707f042c4 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1171,7 +1171,7 @@ "name": "storageGeneralSettingsZoneRedundancy", "type": "Microsoft.Common.DropDown", "label": "Storage account type", - "visible": "[if(equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF'), true, false)]", + "visible": "[equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')]", "defaultValue": "[if(equals(steps('sessionHosts').sessionHostsRegionSection.sessionHostsAvailabilitySettings, true), 'Zone-Redundant Storage', 'Locally Redundant Storage')]", "toolTip": "Select to replicate storage across availability zones or only use local redundancy.", "constraints": { From 809f206dcaf2784d38970491cbb95f742ec0e3cd Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 11:26:24 -0500 Subject: [PATCH 35/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 707f042c4..15db96975 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1129,7 +1129,7 @@ { "name": "identityDomainOuPathStorageExisting", "type": "Microsoft.Common.TextBox", - "visible": "[not(contains(steps('identity').identityDomainInformation.identityServiceProvider, 'EntraID'))]", + "visible": "[equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')]", "label": "Custom OU path (Optional)", "toolTip": "Provide OU where to locate storage account file share. If not provided, file share will be placed on the default (computers) OU.", "placeholder": "Example: OU=storage,OU=avd,DC=contoso,DC=com", From 6bea310032e450f2e9f41958eff4713f09a921fc Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Tue, 1 Apr 2025 11:30:20 -0500 Subject: [PATCH 36/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 15db96975..4e0bf24b6 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1129,7 +1129,7 @@ { "name": "identityDomainOuPathStorageExisting", "type": "Microsoft.Common.TextBox", - "visible": "[equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')]", + "visible": "[contains(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')]", "label": "Custom OU path (Optional)", "toolTip": "Provide OU where to locate storage account file share. If not provided, file share will be placed on the default (computers) OU.", "placeholder": "Example: OU=storage,OU=avd,DC=contoso,DC=com", From f0249cef6aaf032231451bb99264c7e1eacfd132 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 2 Apr 2025 08:54:05 -0500 Subject: [PATCH 37/55] updates --- workload/portal-ui/portal-ui-baseline.json | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 4e0bf24b6..c2a7a0aa4 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1129,7 +1129,7 @@ { "name": "identityDomainOuPathStorageExisting", "type": "Microsoft.Common.TextBox", - "visible": "[contains(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')]", + "visible": "[or(equals(steps('identity').identityDomainInformation.identityServiceProvider, 'ADDS'), equals(steps('identity').identityDomainInformation.identityServiceProvider, 'EntraDS'))]", "label": "Custom OU path (Optional)", "toolTip": "Provide OU where to locate storage account file share. If not provided, file share will be placed on the default (computers) OU.", "placeholder": "Example: OU=storage,OU=avd,DC=contoso,DC=com", @@ -1138,16 +1138,15 @@ { "name": "storageServiceSelector", "type": "Microsoft.Common.DropDown", - "visible": "[or(steps('storage').storageFslogix.fslogixDeployment), steps('storage').storageAppAttach.appAttachStorageDeployment)]", "label": "Storage service", "filter": true, - "defaultValue": "Azure Files", + "defaultValue": "AzureFiles", "toolTip": "Select the storage service (Azure Files or ANF) to use for FSLogix and/or App Attach containers. ANF is only available when using AD DS or Microsoft Entra Domain Services identity service providers", "constraints": { "required": true, "allowedValues": [ { - "label": "Azure Files", + "label": "AzureFiles", "description": "", "value": "AzureFiles" }, @@ -1171,7 +1170,7 @@ "name": "storageGeneralSettingsZoneRedundancy", "type": "Microsoft.Common.DropDown", "label": "Storage account type", - "visible": "[equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')]", + "visible": "[equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles')]", "defaultValue": "[if(equals(steps('sessionHosts').sessionHostsRegionSection.sessionHostsAvailabilitySettings, true), 'Zone-Redundant Storage', 'Locally Redundant Storage')]", "toolTip": "Select to replicate storage across availability zones or only use local redundancy.", "constraints": { @@ -2815,7 +2814,7 @@ "avdArmServicePrincipalObjectId": "[if(and(equals(steps('identity').identityDomainInformation.identityServiceProvider, 'EntraID'), steps('storage').storageAppAttach.appAttachStorageDeployment), if(empty(first(steps('basics').avdArmServicePrincipal.value)), first(map(steps('storage').storageAppAttach.armServicePrincipalPickerBlade.transformed.selection, (sp) => sp.id)), first(steps('basics').avdArmServicePrincipal.value.id)), '')]", "deploymentPrefix": "[steps('basics').deploymentSpecs.deploymentPrefix]", "deploymentEnvironment": "[steps('basics').deploymentSpecs.deploymentEnvironment]", - "storageServiceSelector": "[if(or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment), steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles')]", + "storageService": "[if(or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment), steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles')]", "avdManagementPlaneLocation": "[steps('basics').resourceScope.location.name]", "avdSessionHostLocation": "[if(equals(steps('sessionHosts').deploySessionHosts, true), steps('sessionHosts').sessionHostsRegionSection.sessionHostsRegion, steps('basics').resourceScope.location.name)]", "avdWorkloadSubsId": "[steps('basics').resourceScope.subscription.subscriptionId]", From 29775d1396adc559cca918123050df3da43063a4 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 2 Apr 2025 09:05:52 -0500 Subject: [PATCH 38/55] updates --- workload/portal-ui/portal-ui-baseline.json | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index c2a7a0aa4..3fc4ba550 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1139,6 +1139,7 @@ "name": "storageServiceSelector", "type": "Microsoft.Common.DropDown", "label": "Storage service", + "visible": "[or(equals(steps('identity').identityDomainInformation.identityServiceProvider, 'ADDS'), equals(steps('identity').identityDomainInformation.identityServiceProvider, 'EntraDS'))]", "filter": true, "defaultValue": "AzureFiles", "toolTip": "Select the storage service (Azure Files or ANF) to use for FSLogix and/or App Attach containers. ANF is only available when using AD DS or Microsoft Entra Domain Services identity service providers", @@ -1153,11 +1154,22 @@ { "label": "Azure NetApp Files", "description": "", - "value": "ANF" + "value": "ANF", + "visible": false } ] } }, + { + "name": "storageServiceSelectionWarning", + "type": "Microsoft.Common.InfoBox", + "visible": "[not(or(equals(steps('identity').identityDomainInformation.identityServiceProvider, 'ADDS'), equals(steps('identity').identityDomainInformation.identityServiceProvider, 'EntraDS')))]", + "options": { + "text": "Azure NetApp Files is only available when using AD DS or Entra ID Domain Services as the identity service provider. Therefore the FSLogix or App Attach deployments will use Azure Files.", + "uri": "https://learn.microsoft.com/en-us/azure/azure-netapp-files/azure-netapp-files-introduction", + "style": "Warning" + } + }, { "name": "storageApi", "type": "Microsoft.Solutions.ArmApiControl", From 4c09e8afc20dc2b7db3c7647b8bcb180c5a0a0ea Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 2 Apr 2025 09:15:27 -0500 Subject: [PATCH 39/55] updates --- workload/portal-ui/portal-ui-baseline.json | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 3fc4ba550..23830aa01 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1230,8 +1230,7 @@ { "label": "Ultra (ANF)", "description": "", - "value": "Ultra", - "visible": "[equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')]" + "value": "Ultra" } ] } @@ -1300,8 +1299,7 @@ { "label": "Ultra (ANF)", "description": "", - "value": "Ultra", - "visible": "[equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')]" + "value": "Ultra" } ] } @@ -2826,7 +2824,7 @@ "avdArmServicePrincipalObjectId": "[if(and(equals(steps('identity').identityDomainInformation.identityServiceProvider, 'EntraID'), steps('storage').storageAppAttach.appAttachStorageDeployment), if(empty(first(steps('basics').avdArmServicePrincipal.value)), first(map(steps('storage').storageAppAttach.armServicePrincipalPickerBlade.transformed.selection, (sp) => sp.id)), first(steps('basics').avdArmServicePrincipal.value.id)), '')]", "deploymentPrefix": "[steps('basics').deploymentSpecs.deploymentPrefix]", "deploymentEnvironment": "[steps('basics').deploymentSpecs.deploymentEnvironment]", - "storageService": "[if(or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment), steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles')]", + "storageService": "[if(or(steps('storage').storageFslogix.fslogixDeployment, steps('storage').storageAppAttach.appAttachStorageDeployment), if(or(equals(steps('identity').identityDomainInformation.identityServiceProvider, 'ADDS'), equals(steps('identity').identityDomainInformation.identityServiceProvider, 'EntraDS')), steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles'), '')]", "avdManagementPlaneLocation": "[steps('basics').resourceScope.location.name]", "avdSessionHostLocation": "[if(equals(steps('sessionHosts').deploySessionHosts, true), steps('sessionHosts').sessionHostsRegionSection.sessionHostsRegion, steps('basics').resourceScope.location.name)]", "avdWorkloadSubsId": "[steps('basics').resourceScope.subscription.subscriptionId]", From af7ed09e2a85111fda8040a902453bffb94f1c22 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 2 Apr 2025 09:28:45 -0500 Subject: [PATCH 40/55] updates --- workload/portal-ui/portal-ui-baseline.json | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 23830aa01..7188d1ee9 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1497,6 +1497,19 @@ "validationMessage": "Invalid CIDR range. The address prefix must be in the range 10 to 24." } }, + { + "name": "virtualNetworkAnfSubnetSize", + "type": "Microsoft.Common.TextBox", + "visible": "[and(steps('network').createAvdVirtualNetwork, equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF'))]", + "label": "Azure NetApp Files subnet address prefix", + "toolTip": "Virtual network subnet CIDR for Azure NetApp Files service", + "placeholder": "Example: 10.10.3.0/26", + "constraints": { + "required": true, + "regex": "^(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(?:\/(1[0-9]|2[0-6]))$", + "validationMessage": "Invalid CIDR range. The address prefix must be in the range 10 to 24." + } + }, { "name": "virtualNetworkDns", "type": "Microsoft.Common.TextBox", @@ -1549,6 +1562,23 @@ "name": "virtualNetworkAvdSubnetSelectorName", "label": "Azure Virtual Desktop subnet", "type": "Microsoft.Common.DropDown", + "visible": "[and(not(steps('network').createAvdVirtualNetwork), equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF'))]", + "defaultValue": "", + "toolTip": "Select the subnet.", + "multiselect": false, + "selectAll": false, + "filter": true, + "filterPlaceholder": "Filter items ...", + "multiLine": true, + "constraints": { + "allowedValues": "[map(steps('network').avdSubnetApi.value,(item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.id, '\",\"description\":\"', 'Resource Group: ', last(take(split(item.id, '/'), 5)), '\"}')))]", + "required": true + } + }, + { + "name": "virtualNetworkAnfSubnetSelectorName", + "label": "Azure NetApp Files subnet", + "type": "Microsoft.Common.DropDown", "visible": "[not(steps('network').createAvdVirtualNetwork)]", "defaultValue": "", "toolTip": "Select the subnet.", @@ -2846,6 +2876,10 @@ "createAvdVnet": "[steps('network').createAvdVirtualNetwork]", "avdVnetworkAddressPrefixes": "[if(equals(steps('network').createAvdVirtualNetwork, true), steps('network').virtualNetworkSize, '10.10.0.0/16')]", "vNetworkAvdSubnetAddressPrefix": "[if(equals(steps('network').createAvdVirtualNetwork, true), steps('network').virtualNetworkAvdSubnetSize, '10.10.1.0/24')]", + "vNetworkAnfSubnetAddressPrefix": "[if(and(equals(steps('network').createAvdVirtualNetwork, true), equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')), steps('network').virtualNetworkAnfSubnetSize, '10.10.3.0/26')]", + + + "vNetworkPrivateEndpointSubnetAddressPrefix": "[if(and(equals(steps('network').createAvdVirtualNetwork, true), equals(steps('network').deployPrivateEndpointKeyvaultStorage, true)), steps('network').virtualNetworkPrivateEndpointSubnetSize, '10.10.2.0/27')]", "customDnsIps": "[if(equals(steps('network').createAvdVirtualNetwork, true), steps('network').virtualNetworkDns, '')]", "existingHubVnetResourceId": "[if(equals(steps('network').createAvdVirtualNetwork, true), steps('network').hubVirtualNetworkPeering.existingHubVirtualNetwork, '')]", From 44e4e7c0b4d503d8f2f32e8da2c8b4eaeb29bf99 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 2 Apr 2025 09:33:23 -0500 Subject: [PATCH 41/55] updates --- workload/portal-ui/portal-ui-baseline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 7188d1ee9..a721cfb48 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1571,7 +1571,7 @@ "filterPlaceholder": "Filter items ...", "multiLine": true, "constraints": { - "allowedValues": "[map(steps('network').avdSubnetApi.value,(item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.id, '\",\"description\":\"', 'Resource Group: ', last(take(split(item.id, '/'), 5)), '\"}')))]", + "allowedValues": "[map(filter(steps('network').avdSubnetApi.value, (item) => not(empty(item.delegations))), (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.id, '\",\"description\":\"', 'Resource Group: ', last(take(split(item.id, '/'), 5)), '\"}')))]", "required": true } }, From 3bb60d39a1f6dc34be00c30b3be30c1bff1612da Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 2 Apr 2025 09:34:52 -0500 Subject: [PATCH 42/55] updates --- workload/portal-ui/portal-ui-baseline.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index a721cfb48..f263a7b2f 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -2885,6 +2885,12 @@ "existingHubVnetResourceId": "[if(equals(steps('network').createAvdVirtualNetwork, true), steps('network').hubVirtualNetworkPeering.existingHubVirtualNetwork, '')]", "vNetworkGatewayOnHub": "[if(equals(steps('network').createAvdVirtualNetwork, true), steps('network').hubVirtualNetworkPeering.hubVirtualNetworkGateway, false)]", "existingVnetAvdSubnetResourceId": "[if(equals(steps('network').createAvdVirtualNetwork, false), steps('network').virtualNetworkAvdSubnetSelectorName, '')]", + "existingVnetAnfSubnetResourceId": "[if(and(equals(steps('network').createAvdVirtualNetwork, false), equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')), steps('network').virtualNetworkAnfSubnetSelectorName, '')]", + + + + + "existingVnetPrivateEndpointSubnetResourceId": "[if(equals(steps('network').createAvdVirtualNetwork, false), steps('network').virtualNetworkPrivateEndpointSubnetSelectorName, '')]", "avdDeploySessionHosts": "[steps('sessionHosts').deploySessionHosts]", "avdStartVmOnConnect": "[steps('managementPlane').managementPlaneHostPoolScaling.startVmOnConnect]", From ac7e26de1a555842eb64e388140a4148ac4a2491 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 2 Apr 2025 09:49:12 -0500 Subject: [PATCH 43/55] updates --- workload/portal-ui/portal-ui-baseline.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index f263a7b2f..48a21dcda 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1212,7 +1212,7 @@ "visible": "[steps('storage').storageFslogix.fslogixDeployment]", "label": "File share performance", "filter": true, - "defaultValue": "Premium", + "defaultValue": "[if(equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles'), 'Premium', 'Standard')]", "toolTip": "Performance for App Attach storage (Azure files or ANF). Recommended tier is Premium for storage account and Standard for ANF.", "constraints": { "required": true, @@ -1228,7 +1228,7 @@ "value": "Standard" }, { - "label": "Ultra (ANF)", + "label": "Ultra (ANF only)", "description": "", "value": "Ultra" } @@ -1281,7 +1281,7 @@ "visible": "[and(equals(steps('storage').storageAppAttach.appAttachStorageDeployment, true), not(contains(steps('basics').resourceScope.location.name, 'china')))]", "label": "File share performance", "filter": true, - "defaultValue": "Premium", + "defaultValue": "[if(equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'AzureFiles'), 'Premium', 'Standard')]", "toolTip": "Performance for App Attach storage (Azure files or ANF). Recommended tier is Premium for storage account and Standard for ANF.", "constraints": { "required": true, @@ -1297,7 +1297,7 @@ "value": "Standard" }, { - "label": "Ultra (ANF)", + "label": "Ultra (ANF only)", "description": "", "value": "Ultra" } From 83b54c378c234b0aa9dda139604af0689779cf04 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Wed, 2 Apr 2025 11:18:51 -0500 Subject: [PATCH 44/55] updates --- workload/portal-ui/portal-ui-baseline.json | 1 - 1 file changed, 1 deletion(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 48a21dcda..caeef6fd7 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1141,7 +1141,6 @@ "label": "Storage service", "visible": "[or(equals(steps('identity').identityDomainInformation.identityServiceProvider, 'ADDS'), equals(steps('identity').identityDomainInformation.identityServiceProvider, 'EntraDS'))]", "filter": true, - "defaultValue": "AzureFiles", "toolTip": "Select the storage service (Azure Files or ANF) to use for FSLogix and/or App Attach containers. ANF is only available when using AD DS or Microsoft Entra Domain Services identity service providers", "constraints": { "required": true, From b6e4a5d82553502098203afa04d928df4152edd3 Mon Sep 17 00:00:00 2001 From: danycontre Date: Tue, 8 Apr 2025 17:33:40 -0500 Subject: [PATCH 45/55] updates --- .../1.0.3/Script-DomainJoinStorage.ps1 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 b/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 index f642dde16..834ee0ab8 100644 --- a/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 +++ b/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 @@ -125,11 +125,14 @@ if ($IdentityServiceProvider -eq 'ADDS' && $StorageService -eq 'AzureFiles') { Join-AzStorageAccount -ResourceGroupName $StorageAccountRG -StorageAccountName $StorageAccountName -OrganizationalUnitDistinguishedName $OUName -DomainAccountType 'ComputerAccount' -OverwriteExistingADObject #-SamAccountName $SamAccountName Write-Log -Message "Successfully domain joined the storage account $StorageAccountName to custom OU path $OUName" } - else { - #Join-AzStorageAccountForAuth -ResourceGroupName $StorageAccountRG -StorageAccountName $StorageAccountName -DomainAccountType 'ComputerAccount' -OrganizationalUnitName $OUName -OverwriteExistingADObject - Join-AzStorageAccount -ResourceGroupName $StorageAccountRG -StorageAccountName $StorageAccountName -OrganizationalUnitName $OUName -DomainAccountType 'ComputerAccount' -OverwriteExistingADObject #-SamAccountName $SamAccountName - Write-Log -Message "Successfully domain joined the storage account $StorageAccountName to default OU path $OUName" - } + +if ($IdentityServiceProvider -eq 'EntraDS' && $StorageService -eq 'AzureFiles') { + Write-Log "Domain joining storage account $StorageAccountName in Resource group $StorageAccountRG" + if ( $CustomOuPath -eq 'true') { + #Join-AzStorageAccountForAuth -ResourceGroupName $StorageAccountRG -StorageAccountName $StorageAccountName -DomainAccountType 'ComputerAccount' -OrganizationalUnitName $OUName -OverwriteExistingADObject + Join-AzStorageAccount -ResourceGroupName $StorageAccountRG -StorageAccountName $StorageAccountName -OrganizationalUnitName $OUName -DomainAccountType 'ComputerAccount' -OverwriteExistingADObject #-SamAccountName $SamAccountName + Write-Log -Message "Successfully domain joined the storage account $StorageAccountName to default OU path $OUName" + } } if ($StoragePurpose -eq 'fslogix') { From 111721d338659be212c052adfe94a986d061413e Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Thu, 10 Apr 2025 08:54:09 -0500 Subject: [PATCH 46/55] updates --- workload/portal-ui/brownfield/portalUiNewSessionHosts.json | 4 ++-- workload/portal-ui/portal-ui-baseline.json | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/workload/portal-ui/brownfield/portalUiNewSessionHosts.json b/workload/portal-ui/brownfield/portalUiNewSessionHosts.json index 340e56a3e..c6955e530 100644 --- a/workload/portal-ui/brownfield/portalUiNewSessionHosts.json +++ b/workload/portal-ui/brownfield/portalUiNewSessionHosts.json @@ -213,7 +213,7 @@ "defaultValue": "win11-24h2-avd-m365", "toolTip": "Select the desired marketplace image SKU.", "constraints": { - "allowedValues": "[map(filter(steps('sessionHosts').image.skusApi, (sku) => and(startsWith(sku.name, 'win'), not(contains(sku.name, 'entn')), or(contains(sku.name, 'ent'), contains(sku.name, 'avd')))), (sku) => parse(concat('{\"label\":\"', sku.name, '\",\"value\":\"', sku.name, '\"}')))]", + "allowedValues": "[map(filter(steps('sessionHosts').image.skusApi, (sku) => and(startsWith(sku.name, 'win'), not(contains(sku.name, 'ent')), or(contains(sku.name, 'ent'), contains(sku.name, 'avd')))), (sku) => parse(concat('{\"label\":\"', sku.name, '\",\"value\":\"', sku.name, '\"}')))]", "required": true }, "visible": "[equals(steps('sessionHosts').image.source, 'marketplace')]" @@ -592,7 +592,7 @@ "type": "Microsoft.Common.TextBox", "placeholder": "domainjoin@contoso.com", "label": "Domain Join User Principal Name", - "toolTip": "The User Principal Name of the domain join account.", + "toolTip": "Provide username with permissions to join session host to the domain, the expected format is @.", "constraints": { "regex": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", "required": true diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index caeef6fd7..6871b40dd 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -306,10 +306,11 @@ "name": "identityDomainJoinUserName", "type": "Microsoft.Common.TextBox", "label": "User principal name", - "toolTip": "Provide username with permissions to join session host to the domain.", + "toolTip": "Provide username with permissions to join session host to the domain, the expected format is @.", "placeholder": "Example: 'avdadmin@contoso.com'", "defaultValue": "", "constraints": { + "regex": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", "required": true } }, From 1e24c636d653d7629c945fdcce3b1bee4a0e87c4 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Thu, 10 Apr 2025 09:12:07 -0500 Subject: [PATCH 47/55] updates --- workload/portal-ui/portal-ui-baseline.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 6871b40dd..3dc6ea018 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -1536,7 +1536,7 @@ "name": "avdVirtualNetworkSelectorId", "type": "Microsoft.Solutions.ResourceSelector", "visible": "[not(steps('network').createAvdVirtualNetwork)]", - "label": "Azure Virtual Desktop virtual network", + "label": "Virtual network", "resourceType": "Microsoft.Network/virtualNetworks", "constraints": { "required": true @@ -1562,16 +1562,16 @@ "name": "virtualNetworkAvdSubnetSelectorName", "label": "Azure Virtual Desktop subnet", "type": "Microsoft.Common.DropDown", - "visible": "[and(not(steps('network').createAvdVirtualNetwork), equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF'))]", + "visible": "[not(steps('network').createAvdVirtualNetwork)]", "defaultValue": "", - "toolTip": "Select the subnet.", + "toolTip": "Select the AVD subnet.", "multiselect": false, "selectAll": false, "filter": true, "filterPlaceholder": "Filter items ...", "multiLine": true, "constraints": { - "allowedValues": "[map(filter(steps('network').avdSubnetApi.value, (item) => not(empty(item.delegations))), (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.id, '\",\"description\":\"', 'Resource Group: ', last(take(split(item.id, '/'), 5)), '\"}')))]", + "allowedValues": "[map(steps('network').avdSubnetApi.value,(item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.id, '\",\"description\":\"', 'Resource Group: ', last(take(split(item.id, '/'), 5)), '\"}')))]", "required": true } }, @@ -1579,9 +1579,9 @@ "name": "virtualNetworkAnfSubnetSelectorName", "label": "Azure NetApp Files subnet", "type": "Microsoft.Common.DropDown", - "visible": "[not(steps('network').createAvdVirtualNetwork)]", + "visible": "[and(not(steps('network').createAvdVirtualNetwork), equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF'))]", "defaultValue": "", - "toolTip": "Select the subnet.", + "toolTip": "Select the Azure NetApp Files subnet, this subnet needs to be delegated to service Microsoft.Netapp/volumes.", "multiselect": false, "selectAll": false, "filter": true, From a886f487b41ee88623d2dfc1afe6215eace43fbd Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Thu, 10 Apr 2025 09:33:17 -0500 Subject: [PATCH 48/55] updates --- .../brownfield/portalUiNewSessionHosts.json | 375 +++++++++--------- workload/portal-ui/portal-ui-baseline.json | 9 - 2 files changed, 186 insertions(+), 198 deletions(-) diff --git a/workload/portal-ui/brownfield/portalUiNewSessionHosts.json b/workload/portal-ui/brownfield/portalUiNewSessionHosts.json index c6955e530..543621228 100644 --- a/workload/portal-ui/brownfield/portalUiNewSessionHosts.json +++ b/workload/portal-ui/brownfield/portalUiNewSessionHosts.json @@ -82,6 +82,120 @@ } ] }, + { + "name": "identity", + "label": "Identity", + "visible": true, + "elements": [ + { + "name": "identityServiceProvider", + "type": "Microsoft.Common.OptionsGroup", + "label": "Identity Service Provider", + "defaultValue": "Active Directory (AD DS)", + "toolTip": "Choose the identity service provider for your users and session hosts. Your choices explained:

Active Directory (ADDS): The users are sourced from ADDS and session hosts will be domain joined.

Microsoft Entra Domain Services: The users are sourced from Entra ID or ADDS and the session hosts are joined to Entra Domain Services.

Microsoft Entra ID: The users are sourced from Entra ID and the session hosts will join Entra ID.

Microsoft Entra ID Kerberos: The Users are sourced from ADDS, but the session hosts will be joined to Entra ID.", + "constraints": { + "required": true, + "allowedValues": [ + { + "label": "Active Directory (AD DS)", + "value": "ADDS" + }, + { + "label": "Microsoft Entra Domain Services", + "value": "EntraDS" + }, + { + "label": "Microsoft Entra ID", + "value": "EntraID" + }, + { + "label": "Microsoft Entra ID Kerberos", + "value": "EntraIDKerberos" + } + ] + } + }, + { + "name": "identityServiceProviderInfo1", + "type": "Microsoft.Common.InfoBox", + "visible": "[equals(steps('identity').identityServiceProvider, 'EntraID')]", + "options": { + "text": "If you are deploying this solution with FSLogix Storage, storage account key access must be permitted within your subscription. This solution will securely configure your session host to access the FSLogix Azure Files storage with the storage account key.", + "uri": "https://techcommunity.microsoft.com/blog/fslogix-blog/fslogix-profile-containers-for-azure-ad-cloud-only-identities/3739352", + "style": "Warning" + } + }, + { + "name": "intuneEnrollment", + "type": "Microsoft.Common.CheckBox", + "visible": "[contains(steps('identity').identityServiceProvider, 'EntraID')]", + "label": "Intune enrollment", + "toolTip": "If Intune is configured in your Microsoft Entra ID tenant, you can choose to have the VM automatically enrolled during the deployment by selecting this box." + }, + { + "name": "identityDomainName", + "type": "Microsoft.Common.TextBox", + "label": "Domain name", + "visible": "[contains(steps('identity').identityServiceProvider, 'DS')]", + "toolTip": "The full qualified domain name of the domain to which the virtual machines will be joined.", + "placeholder": "Example: contoso.com", + "constraints": { + "required": true + } + }, + { + "name": "ouPath", + "type": "Microsoft.Common.TextBox", + "visible": "[contains(steps('identity').identityServiceProvider, 'DS')]", + "label": "OU Path", + "toolTip": "Optionally, input the distinguished name of the desired organization unit for the AVD session hosts.", + "placeholder": "Example: OU=pooled,OU=avd,DC=contoso,DC=com", + "constraints": { + "required": false + } + }, + { + "name": "domainJoinUserPrincipalName", + "type": "Microsoft.Common.TextBox", + "placeholder": "domainjoin@contoso.com", + "label": "Domain Join User Principal Name", + "visible": "[contains(steps('identity').identityServiceProvider, 'DS')]", + "toolTip": "Provide username with permissions to join session host to the domain, the expected format is @.", + "constraints": { + "regex": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", + "required": true + } + }, + { + "name": "secretsInfoBox1", + "type": "Microsoft.Common.InfoBox", + "visible": "[contains(steps('identity').identityServiceProvider, 'EntraID')]", + "options": { + "text": "This add-on requires that the following secret names and values are stored in a key vault that you will select below:
  • vmLocalUserName: The virtual machine administrator username.
  • vmLocalUserPassword: The virtual machine administrator password.", + "style": "Info" + } + }, + { + "name": "secretsInfoBox2", + "type": "Microsoft.Common.InfoBox", + "visible": "[contains(steps('identity').identityServiceProvider, 'DS')]", + "options": { + "text": "This add-on requires that the following secret names and values are stored in a key vault that you will select below:
    • domainJoinUserPassword: The password associated with the user principal name specified above.
    • vmLocalUserName: The virtual machine administrator username.
    • vmLocalUserPassword: The virtual machine administrator password.", + "style": "Info" + } + }, + { + "name": "keyVault", + "type": "Microsoft.Solutions.ResourceSelector", + "label": "Select Keyvault containing workload secrets", + "resourceType": "Microsoft.KeyVault/vaults", + "toolTip": "Select Keyvault which contains the secrets", + "constraints": { + "required": true + } + } + ] + }, { "name": "sessionHosts", "label": "Session Hosts", @@ -513,192 +627,49 @@ "toolTip": "Deploys anti-malware extension on session hosts." } ] - }, + } + ] + }, + { + "name": "networking", + "label": "Networking", + "elements": [ { - "name": "identityAndAccounts", - "type": "Microsoft.Common.Section", - "label": "Identity and Account Settings", - "elements": [ - { - "name": "identityServiceProvider", - "type": "Microsoft.Common.OptionsGroup", - "visible": true, - "label": "Identity Service Provider", - "defaultValue": "Active Directory (AD DS)", - "toolTip": "Choose the identity service provider for your users and session hosts. Your choices explained:

      Active Directory (ADDS): The users are sourced from ADDS and session hosts will be domain joined.

      Microsoft Entra Domain Services: The users are sourced from Entra ID or ADDS and the session hosts are joined to Entra Domain Services.

      Microsoft Entra ID: The users are sourced from Entra ID and the session hosts will join Entra ID.

      Microsoft Entra ID Kerberos: The Users are sourced from ADDS, but the session hosts will be joined to Entra ID.", - "constraints": { - "required": true, - "allowedValues": [ - { - "label": "Active Directory (AD DS)", - "value": "ADDS" - }, - { - "label": "Microsoft Entra Domain Services", - "value": "EntraDS" - }, - { - "label": "Microsoft Entra ID", - "value": "EntraID" - }, - { - "label": "Microsoft Entra ID Kerberos", - "value": "EntraIDKerberos" - } - ] - } - }, - { - "name": "identityServiceProviderInfo1", - "type": "Microsoft.Common.InfoBox", - "visible": "[equals(steps('sessionHosts').identityAndAccounts.identityServiceProvider, 'EntraID')]", - "options": { - "text": "If you are deploying this solution with FSLogix Storage, storage account key access must be permitted within your subscription. This solution will securely configure your session host to access the FSLogix Azure Files storage with the storage account key.", - "uri": "https://techcommunity.microsoft.com/blog/fslogix-blog/fslogix-profile-containers-for-azure-ad-cloud-only-identities/3739352", - "style": "Warning" - } - }, - { - "name": "intuneEnrollment", - "type": "Microsoft.Common.CheckBox", - "visible": "[contains(steps('sessionHosts').identityAndAccounts.identityServiceProvider, 'EntraID')]", - "label": "Intune enrollment", - "toolTip": "If Intune is configured in your Microsoft Entra ID tenant, you can choose to have the VM automatically enrolled during the deployment by selecting this box." - }, - { - "name": "identityDomainName", - "type": "Microsoft.Common.TextBox", - "label": "Domain name", - "visible": "[contains(steps('sessionHosts').identityAndAccounts.identityServiceProvider, 'DS')]", - "toolTip": "The full qualified domain name of the domain to which the virtual machines will be joined.", - "placeholder": "Example: contoso.com", - "constraints": { - "required": true - } - }, - { - "name": "ouPath", - "type": "Microsoft.Common.TextBox", - "visible": "[contains(steps('sessionHosts').identityAndAccounts.identityServiceProvider, 'DS')]", - "label": "OU Path", - "toolTip": "Optionally, input the distinguished name of the desired organization unit for the AVD session hosts.", - "placeholder": "Example: OU=pooled,OU=avd,DC=contoso,DC=com", - "constraints": { - "required": false - } - }, - { - "name": "domainJoinUserPrincipalName", - "type": "Microsoft.Common.TextBox", - "placeholder": "domainjoin@contoso.com", - "label": "Domain Join User Principal Name", - "toolTip": "Provide username with permissions to join session host to the domain, the expected format is @.", - "constraints": { - "regex": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", - "required": true - }, - "visible": "[contains(steps('sessionHosts').identityAndAccounts.identityServiceProvider, 'DS')]" - }, - { - "name": "secretsInfoBox1", - "type": "Microsoft.Common.InfoBox", - "visible": "[contains(steps('sessionHosts').identityAndAccounts.identityServiceProvider, 'EntraID')]", - "options": { - "text": "This add-on requires that the following secret names and values are stored in a key vault that you will select below:
      • vmLocalUserName: The virtual machine administrator username.
      • vmLocalUserPassword: The virtual machine administrator password.", - "style": "Info" - } - }, - { - "name": "secretsInfoBox2", - "type": "Microsoft.Common.InfoBox", - "visible": "[contains(steps('sessionHosts').identityAndAccounts.identityServiceProvider, 'DS')]", - "options": { - "text": "This add-on requires that the following secret names and values are stored in a key vault that you will select below:
        • domainJoinUserPassword: The password associated with the user principal name specified above.
        • vmLocalUserName: The virtual machine administrator username.
        • vmLocalUserPassword: The virtual machine administrator password.", - "style": "Info" - } - }, - { - "name": "keyVault", - "type": "Microsoft.Solutions.ResourceSelector", - "label": "Select Keyvault containing workload secrets", - "resourceType": "Microsoft.KeyVault/vaults", - "toolTip": "Select Keyvault which contains the secrets", - "constraints": { - "required": true - } - } - ] + "name": "virtualNetwork", + "type": "Microsoft.Solutions.ResourceSelector", + "label": "Virtual Network", + "resourceType": "Microsoft.Network/virtualNetworks", + "constraints": { + "required": true + }, + "scope": { + "subscriptionId": "[steps('basics').resourceScope.subscription.subscriptionId]", + "location": "[steps('basics').resourceScope.location.name]" + } }, { - "name": "network", - "type": "Microsoft.Common.Section", - "label": "Network", - "elements": [ - { - "name": "virtualNetwork", - "type": "Microsoft.Solutions.ResourceSelector", - "label": "Virtual Network", - "resourceType": "Microsoft.Network/virtualNetworks", - "constraints": { - "required": true - }, - "scope": { - "subscriptionId": "[steps('basics').resourceScope.subscription.subscriptionId]", - "location": "[steps('basics').resourceScope.location.name]" - } - }, - { - "name": "subnetsApi", - "condition": "[not(empty(steps('sessionHosts').network.virtualNetwork))]", - "type": "Microsoft.Solutions.ArmApiControl", - "request": { - "method": "GET", - "path": "[concat(steps('sessionHosts').network.virtualNetwork.id, '/subnets?api-version=2022-05-01')]", - "transforms": { - "list": "value|[*].{label:name, value:id}" - } - } - }, - { - "name": "subnet", - "type": "Microsoft.Common.DropDown", - "visible": true, - "label": "Subnet", - "defaultValue": "", - "toolTip": "Select an existing subnet for the AVD session hosts.", - "constraints": { - "required": true, - "allowedValues": "[steps('sessionHosts').network.subnetsApi.transformed.list]" - } + "name": "subnetsApi", + "condition": "[not(empty(steps('networking').virtualNetwork))]", + "type": "Microsoft.Solutions.ArmApiControl", + "request": { + "method": "GET", + "path": "[concat(steps('networking').virtualNetwork.id, '/subnets?api-version=2022-05-01')]", + "transforms": { + "list": "value|[*].{label:name, value:id}" } - ] + } }, { - "name": "monitoring", - "type": "Microsoft.Common.Section", - "label": "Monitoring", - "elements": [ - { - "name": "enableMonitoring", - "type": "Microsoft.Common.CheckBox", - "label": "Deploy Azure Monitor Agent and Associate Data Collection Rule", - "toolTip": "Deploy AVD monitoring resources and setings." - }, - { - "name": "dataCollectionRule", - "type": "Microsoft.Solutions.ResourceSelector", - "visible": "[steps('sessionHosts').monitoring.enableMonitoring]", - "label": "AVD Insights Data Collection Rule", - "resourceType": "Microsoft.Insights/dataCollectionRules", - "constraints": { - "required": true - }, - "scope": { - "subscriptionId": "[steps('basics').resourceScope.subscription.subscriptionId]", - "location": "[steps('basics').resourceScope.location.name]" - } - } - ] + "name": "subnet", + "type": "Microsoft.Common.DropDown", + "visible": true, + "label": "Subnet", + "defaultValue": "", + "toolTip": "Select an existing subnet for the AVD session hosts.", + "constraints": { + "required": true, + "allowedValues": "[steps('networking').subnetsApi.transformed.list]" + } } ] }, @@ -760,6 +731,32 @@ } ] }, + { + "name": "monitoring", + "label": "Monitoring", + "elements": [ + { + "name": "enableMonitoring", + "type": "Microsoft.Common.CheckBox", + "label": "Deploy Azure Monitor Agent and Associate Data Collection Rule", + "toolTip": "Deploy AVD monitoring resources and settings." + }, + { + "name": "dataCollectionRule", + "type": "Microsoft.Solutions.ResourceSelector", + "visible": "[steps('monitoring').enableMonitoring]", + "label": "AVD Insights Data Collection Rule", + "resourceType": "Microsoft.Insights/dataCollectionRules", + "constraints": { + "required": true + }, + "scope": { + "subscriptionId": "[steps('basics').resourceScope.subscription.subscriptionId]", + "location": "[steps('basics').resourceScope.location.name]" + } + } + ] + }, { "name": "tags", "label": "Tags", @@ -1005,15 +1002,15 @@ "encryptionAtHost": "[if(equals(steps('basics').encryptionAtHostFeatureApi.properties.state, 'Registered'), steps('sessionHosts').security.encryptionAtHost, false)]", "diskEncryptionSetResourceId": "[if(steps('sessionHosts').security.customerManagedKeys, steps('sessionHosts').security.diskEncryptionSet, '')]", "deployAntiMalwareExt": "[steps('sessionHosts').security.deployAntiMalwareExt]", - "identityServiceProvider": "[steps('sessionHosts').identityAndAccounts.identityServiceProvider]", - "createIntuneEnrollment": "[steps('sessionHosts').identityAndAccounts.intuneEnrollment]", - "identityDomainName": "[if(contains(steps('sessionHosts').identityAndAccounts.identityServiceProvider, 'DS'), steps('sessionHosts').identityAndAccounts.identityDomainName, '')]", - "sessionHostOuPath": "[if(contains(steps('sessionHosts').identityAndAccounts.identityServiceProvider, 'DS'), steps('sessionHosts').identityAndAccounts.ouPath, '')]", - "keyVaultResourceId": "[steps('sessionHosts').identityAndAccounts.keyVault.id]", - "domainJoinUserPrincipalName": "[if(contains(steps('sessionHosts').identityAndAccounts.identityServiceProvider, 'DS'), steps('sessionHosts').identityAndAccounts.domainJoinUserPrincipalName, '')]", - "subnetResourceId": "[steps('sessionHosts').network.subnet]", - "enableMonitoring": "[steps('sessionHosts').monitoring.enableMonitoring]", - "dataCollectionRuleId": "[if(steps('sessionHosts').monitoring.enableMonitoring, steps('sessionHosts').monitoring.dataCollectionRule.id, '')]", + "identityServiceProvider": "[steps('identity').identityServiceProvider]", + "createIntuneEnrollment": "[if(contains(steps('identity').identityServiceProvider, 'ID'), steps('identity').intuneEnrollment, false)]", + "identityDomainName": "[if(contains(steps('identity').identityServiceProvider, 'DS'), steps('identity').identityDomainName, '')]", + "sessionHostOuPath": "[if(contains(steps('identity').identityServiceProvider, 'DS'), steps('identity').ouPath, '')]", + "keyVaultResourceId": "[steps('identity').keyVault.id]", + "domainJoinUserPrincipalName": "[if(contains(steps('identity').identityServiceProvider, 'DS'), steps('identity').domainJoinUserPrincipalName, '')]", + "subnetResourceId": "[steps('networking').subnet]", + "enableMonitoring": "[steps('monitoring').enableMonitoring]", + "dataCollectionRuleId": "[if(steps('monitoring').enableMonitoring, steps('monitoring').dataCollectionRule.id, '')]", "configureFslogix": "[steps('fslogix').configureFslogix]", "fslogixStorageAccountResourceId": "[if(steps('fslogix').configureFslogix, steps('fslogix').storageAccount, '')]", "fslogixFileShareName": "[if(steps('fslogix').configureFslogix, steps('fslogix').fileShareName, '')]", diff --git a/workload/portal-ui/portal-ui-baseline.json b/workload/portal-ui/portal-ui-baseline.json index 3dc6ea018..db2d1f322 100644 --- a/workload/portal-ui/portal-ui-baseline.json +++ b/workload/portal-ui/portal-ui-baseline.json @@ -150,7 +150,6 @@ "name": "identityDomainInformation", "type": "Microsoft.Common.Section", "visible": true, - "label": "Domain to join", "elements": [ { "name": "identityServiceProvider", @@ -2877,20 +2876,12 @@ "avdVnetworkAddressPrefixes": "[if(equals(steps('network').createAvdVirtualNetwork, true), steps('network').virtualNetworkSize, '10.10.0.0/16')]", "vNetworkAvdSubnetAddressPrefix": "[if(equals(steps('network').createAvdVirtualNetwork, true), steps('network').virtualNetworkAvdSubnetSize, '10.10.1.0/24')]", "vNetworkAnfSubnetAddressPrefix": "[if(and(equals(steps('network').createAvdVirtualNetwork, true), equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')), steps('network').virtualNetworkAnfSubnetSize, '10.10.3.0/26')]", - - - "vNetworkPrivateEndpointSubnetAddressPrefix": "[if(and(equals(steps('network').createAvdVirtualNetwork, true), equals(steps('network').deployPrivateEndpointKeyvaultStorage, true)), steps('network').virtualNetworkPrivateEndpointSubnetSize, '10.10.2.0/27')]", "customDnsIps": "[if(equals(steps('network').createAvdVirtualNetwork, true), steps('network').virtualNetworkDns, '')]", "existingHubVnetResourceId": "[if(equals(steps('network').createAvdVirtualNetwork, true), steps('network').hubVirtualNetworkPeering.existingHubVirtualNetwork, '')]", "vNetworkGatewayOnHub": "[if(equals(steps('network').createAvdVirtualNetwork, true), steps('network').hubVirtualNetworkPeering.hubVirtualNetworkGateway, false)]", "existingVnetAvdSubnetResourceId": "[if(equals(steps('network').createAvdVirtualNetwork, false), steps('network').virtualNetworkAvdSubnetSelectorName, '')]", "existingVnetAnfSubnetResourceId": "[if(and(equals(steps('network').createAvdVirtualNetwork, false), equals(steps('storage').storageGeneralSettings.storageServiceSelector, 'ANF')), steps('network').virtualNetworkAnfSubnetSelectorName, '')]", - - - - - "existingVnetPrivateEndpointSubnetResourceId": "[if(equals(steps('network').createAvdVirtualNetwork, false), steps('network').virtualNetworkPrivateEndpointSubnetSelectorName, '')]", "avdDeploySessionHosts": "[steps('sessionHosts').deploySessionHosts]", "avdStartVmOnConnect": "[steps('managementPlane').managementPlaneHostPoolScaling.startVmOnConnect]", From c40c7727652b861271ce8e3143829218a9871f61 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Thu, 10 Apr 2025 09:51:10 -0500 Subject: [PATCH 49/55] updates --- workload/arm/deploy-baseline.json | 22544 +++++++++++----------------- 1 file changed, 8417 insertions(+), 14127 deletions(-) diff --git a/workload/arm/deploy-baseline.json b/workload/arm/deploy-baseline.json index befe571e0..ca323dc24 100644 --- a/workload/arm/deploy-baseline.json +++ b/workload/arm/deploy-baseline.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "18159930501355149539" + "templateHash": "6868748504185616259" }, "name": "AVD Accelerator - Baseline Deployment", "description": "AVD Accelerator - Deployment Baseline", @@ -266,18 +266,11 @@ "description": "Existing virtual network subnet for private endpoints. (Default: \"\")" } }, - "existingVnetAnfSubnetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Existing virtual network subnet for ANF. (Default: \"\")" - } - }, "existingHubVnetResourceId": { "type": "string", "defaultValue": "", "metadata": { - "description": "Existing hub virtual network for peering. (Default: \"\")" + "description": "Existing hub virtual network for perring. (Default: \"\")" } }, "avdVnetworkAddressPrefixes": { @@ -301,13 +294,6 @@ "description": "private endpoints virtual network subnet address prefix. (Default: 10.10.2.0/27)" } }, - "vNetworkAnfSubnetAddressPrefix": { - "type": "string", - "defaultValue": "10.10.3.0/26", - "metadata": { - "description": "ANF virtual network subnet address prefix. (Default: 10.10.3.0/26)" - } - }, "customDnsIps": { "type": "string", "defaultValue": "", @@ -378,24 +364,13 @@ "description": "Does the hub contains a virtual network gateway. (Default: false)" } }, - "createFslogixDeployment": { + "createAvdFslogixDeployment": { "type": "bool", "defaultValue": true, "metadata": { "description": "Deploy Fslogix setup. (Default: true)" } }, - "storageService": { - "type": "string", - "defaultValue": "AzureFiles", - "allowedValues": [ - "ANF", - "AzureFiles" - ], - "metadata": { - "description": "Type of storage service to deploy for FSLogix. (Default: AzureFiles)" - } - }, "createAppAttachDeployment": { "type": "bool", "defaultValue": false, @@ -405,16 +380,16 @@ }, "fslogixFileShareQuotaSize": { "type": "int", - "defaultValue": 100, + "defaultValue": 1, "metadata": { - "description": "Fslogix file share size in GB. (Default: 100)" + "description": "Fslogix file share size. (Default: 1)" } }, "appAttachFileShareQuotaSize": { "type": "int", - "defaultValue": 100, + "defaultValue": 1, "metadata": { - "description": "App Attach file share size in GB. (Default: 100)" + "description": "App Attach file share size. (Default: 1)" } }, "avdDeploySessionHosts": { @@ -490,14 +465,7 @@ "AvailabilityZones" ], "metadata": { - "description": "When set to AvailabilityZones, VMs are distributed across availability zones, when set to None, VMs are deployed at regional level." - } - }, - "zoneRedundantStorage": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "When true, Zone Redundant Storage (ZRS) is used, when set to false, Locally Redundant Storage (LRS) is used. (Default: false)" + "description": "When true VMs are distributed across availability zones, when set to false, VMs will be deployed at regional level." } }, "availabilityZones": { @@ -516,16 +484,22 @@ "description": "The Availability Zones to use for the session hosts." } }, + "zoneRedundantStorage": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "When true, Zone Redundant Storage (ZRS) is used, when set to false, Locally Redundant Storage (LRS) is used. (Default: false)" + } + }, "fslogixStoragePerformance": { "type": "string", "defaultValue": "Premium", "allowedValues": [ "Standard", - "Premium", - "Ultra" + "Premium" ], "metadata": { - "description": "SKU for FSLogix storage. Recommended tier is Premium for storage account and Standard for ANF. (Default: Premium)" + "description": "Storage account SKU for FSLogix storage. Recommended tier is Premium (Default: Premium)" } }, "appAttachStoragePerformance": { @@ -533,11 +507,10 @@ "defaultValue": "Premium", "allowedValues": [ "Standard", - "Premium", - "Ultra" + "Premium" ], "metadata": { - "description": "SKU for App Attach storage. RRecommended tier is Premium for storage account and Standard for ANF. (Default: Premium)" + "description": "Storage account SKU for App Attach storage. Recommended tier is Premium. (Default: Premium)" } }, "diskZeroTrust": { @@ -639,7 +612,7 @@ "type": "string", "defaultValue": "", "metadata": { - "description": "OU name for Azure Storage Account or Azure Netapp Files. It is recommended to create a new AD Organizational Unit (OU) in AD and disable password expiration policy on computer accounts or service logon accounts accordingly. (Default: \"\")" + "description": "OU name for Azure Storage Account. It is recommended to create a new AD Organizational Unit (OU) in AD and disable password expiration policy on computer accounts or service logon accounts accordingly. (Default: \"\")" } }, "avdUseCustomNaming": { @@ -721,14 +694,6 @@ "description": "private endpoints virtual network subnet custom name. (Default: snet-pe-app1-dev-use2-001)" } }, - "anfVnetworkSubnetCustomName": { - "type": "string", - "defaultValue": "snet-anf-app1-dev-use2-001", - "maxLength": 80, - "metadata": { - "description": "ANF virtual network subnet custom name. (Default: snet-anf-app1-dev-use2-001)" - } - }, "avdNetworksecurityGroupCustomName": { "type": "string", "defaultValue": "nsg-avd-app1-dev-use2-001", @@ -745,14 +710,6 @@ "description": "Private endpoint network security group custom name. (Default: nsg-pe-app1-dev-use2-001)" } }, - "anfNetworksecurityGroupCustomName": { - "type": "string", - "defaultValue": "nsg-anf-app1-dev-use2-001", - "maxLength": 80, - "metadata": { - "description": "ANF network security group custom name. (Default: nsg-anf-app1-dev-use2-001)" - } - }, "avdRouteTableCustomName": { "type": "string", "defaultValue": "route-avd-app1-dev-use2-001", @@ -849,13 +806,6 @@ "description": "AVD FSLogix and App Attach storage account prefix custom name. (Default: st)" } }, - "anfAccountCustomName": { - "type": "string", - "defaultValue": "anf-acc-app1-dev-use2-001", - "metadata": { - "description": "AVD FSLogix and App Attach storage account prefix custom name. (Default: anf-acc-app1-dev-use2-001)" - } - }, "fslogixFileShareCustomName": { "type": "string", "defaultValue": "fslogix-pc-app1-dev-use2-001", @@ -1355,10 +1305,85 @@ "timeZone": "Mountain Standard Time" } }, + "$fxv#1": { + "win10_22h2_g2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "windows-10", + "sku": "win10-22h2-avd-g2", + "version": "latest" + }, + "win10_22h2_office_g2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "office-365", + "sku": "win10-22h2-avd-m365-g2", + "version": "latest" + }, + "win11_22h2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "Windows-11", + "sku": "win11-22h2-avd", + "version": "latest" + }, + "win11_22h2_office": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "office-365", + "sku": "win11-22h2-avd-m365", + "version": "latest" + }, + "win11_23h2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "Windows-11", + "sku": "win11-23h2-avd", + "version": "latest" + }, + "win11_23h2_office": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "office-365", + "sku": "win11-23h2-avd-m365", + "version": "latest" + }, + "win11_24h2": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "Windows-11", + "sku": "win11-24h2-avd", + "version": "latest" + }, + "win11_24h2_office": { + "publisher": "MicrosoftWindowsDesktop", + "offer": "office-365", + "sku": "win11-24h2-avd-m365", + "version": "latest" + }, + "winServer_2022_Datacenter": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2022-datacenter-g2", + "version": "latest" + }, + "winServer_2022_Datacenter_smalldisk_g2": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2022-datacenter-smalldisk-g2", + "version": "latest" + }, + "winServer_2022_datacenter_core": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2022-datacenter-core-g2", + "version": "latest" + }, + "winServer_2022_Datacenter_core_smalldisk_g2": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2022-datacenter-core-smalldisk-g2", + "version": "latest" + } + }, "varDeploymentPrefixLowercase": "[toLower(parameters('deploymentPrefix'))]", "varAzureCloudName": "[environment().name]", "varDeploymentEnvironmentLowercase": "[toLower(parameters('deploymentEnvironment'))]", - "varDeploymentEnvironmentOneCharacter": "[if(equals(parameters('deploymentEnvironment'), 'Dev'), 'd', if(equals(parameters('deploymentEnvironment'), 'Test'), 't', if(equals(parameters('deploymentEnvironment'), 'Prod'), 'p', '')))]", + "varDeploymentEnvironmentComputeStorage": "[if(equals(parameters('deploymentEnvironment'), 'Dev'), 'd', if(equals(parameters('deploymentEnvironment'), 'Test'), 't', if(equals(parameters('deploymentEnvironment'), 'Prod'), 'p', '')))]", + "varNamingUniqueStringThreeChar": "[take(format('{0}', uniqueString(parameters('avdWorkloadSubsId'), variables('varDeploymentPrefixLowercase'), parameters('time'))), 3)]", "varNamingUniqueStringTwoChar": "[take(format('{0}', uniqueString(parameters('avdWorkloadSubsId'), variables('varDeploymentPrefixLowercase'), parameters('time'))), 2)]", "varSessionHostLocationAcronym": "[variables('varLocations')[variables('varSessionHostLocationLowercase')].acronym]", "varManagementPlaneLocationAcronym": "[variables('varLocations')[variables('varManagementPlaneLocationLowercase')].acronym]", @@ -1380,10 +1405,8 @@ "varRemoteVnetPeeringName": "[format('peer-{0}', variables('varVnetName'))]", "varVnetAvdSubnetName": "[if(parameters('avdUseCustomNaming'), parameters('avdVnetworkSubnetCustomName'), format('snet-avd-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", "varVnetPrivateEndpointSubnetName": "[if(parameters('avdUseCustomNaming'), parameters('privateEndpointVnetworkSubnetCustomName'), format('snet-pe-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", - "varVnetAnfSubnetName": "[if(parameters('avdUseCustomNaming'), parameters('anfVnetworkSubnetCustomName'), format('snet-anf-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", "varAvdNetworksecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('avdNetworksecurityGroupCustomName'), format('nsg-avd-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", "varPrivateEndpointNetworksecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('privateEndpointNetworksecurityGroupCustomName'), format('nsg-pe-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", - "varAnfNetworksecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('anfNetworksecurityGroupCustomName'), format('nsg-anf-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", "varAvdRouteTableName": "[if(parameters('avdUseCustomNaming'), parameters('avdRouteTableCustomName'), format('route-avd-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", "varPrivateEndpointRouteTableName": "[if(parameters('avdUseCustomNaming'), parameters('privateEndpointRouteTableCustomName'), format('route-pe-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", "varApplicationSecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('avdApplicationSecurityGroupCustomName'), format('asg-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", @@ -1407,15 +1430,26 @@ "varWrklKvName": "[if(parameters('avdUseCustomNaming'), format('{0}-{1}-{2}', parameters('avdWrklKvPrefixCustomName'), variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')), format('kv-sec-{0}-{1}', variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')))]", "varWrklKvPrivateEndpointName": "[format('pe-{0}-vault', variables('varWrklKvName'))]", "varWrklKeyVaultSku": "[if(or(equals(variables('varAzureCloudName'), 'AzureCloud'), equals(variables('varAzureCloudName'), 'AzureUSGovernment')), 'premium', if(equals(variables('varAzureCloudName'), 'AzureChinaCloud'), 'standard', null()))]", - "varSessionHostNamePrefix": "[if(parameters('avdUseCustomNaming'), parameters('avdSessionHostCustomNamePrefix'), format('vm{0}{1}{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentOneCharacter'), variables('varSessionHostLocationAcronym')))]", + "varSessionHostNamePrefix": "[if(parameters('avdUseCustomNaming'), parameters('avdSessionHostCustomNamePrefix'), format('vm{0}{1}{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentComputeStorage'), variables('varSessionHostLocationAcronym')))]", "varStorageManagedIdentityName": "[format('id-storage-{0}-001', variables('varComputeStorageResourcesNamingStandard'))]", + "varFslogixFileShareName": "[if(parameters('avdUseCustomNaming'), parameters('fslogixFileShareCustomName'), format('fslogix-pc-{0}-{1}-{2}-001', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentLowercase'), variables('varSessionHostLocationAcronym')))]", + "varAppAttachFileShareName": "[if(parameters('avdUseCustomNaming'), parameters('appAttachFileShareCustomName'), format('appa-{0}-{1}-{2}-001', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentLowercase'), variables('varSessionHostLocationAcronym')))]", + "varFslogixStorageName": "[if(parameters('avdUseCustomNaming'), format('{0}fsl{1}{2}{3}', parameters('storageAccountPrefixCustomName'), variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentComputeStorage'), variables('varNamingUniqueStringThreeChar')), format('stfsl{0}{1}{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentComputeStorage'), variables('varNamingUniqueStringThreeChar')))]", + "varFslogixStorageFqdn": "[if(parameters('createAvdFslogixDeployment'), format('{0}.file.{1}', variables('varFslogixStorageName'), environment().suffixes.storage), '')]", + "varAppAttachStorageFqdn": "[format('{0}.file.{1}', variables('varAppAttachStorageName'), environment().suffixes.storage)]", + "varAppAttachStorageName": "[if(parameters('avdUseCustomNaming'), format('{0}appa{1}{2}{3}', parameters('storageAccountPrefixCustomName'), variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentComputeStorage'), variables('varNamingUniqueStringThreeChar')), format('stappa{0}{1}{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentComputeStorage'), variables('varNamingUniqueStringThreeChar')))]", + "varManagementVmName": "[format('vmmgmt{0}{1}{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentComputeStorage'), variables('varSessionHostLocationAcronym'))]", "varAlaWorkspaceName": "[if(parameters('avdUseCustomNaming'), parameters('avdAlaWorkspaceCustomName'), format('log-avd-{0}-{1}', variables('varDeploymentEnvironmentLowercase'), variables('varManagementPlaneLocationAcronym')))]", "varDataCollectionRulesName": "[format('microsoft-avdi-{0}', variables('varSessionHostLocationLowercase'))]", "varZtKvName": "[if(parameters('avdUseCustomNaming'), format('{0}-{1}-{2}', parameters('ztKvPrefixCustomName'), variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')), format('kv-key-{0}-{1}', variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')))]", "varZtKvPrivateEndpointName": "[format('pe-{0}-vault', variables('varZtKvName'))]", - "varBaseScriptUri": "https://raw.githubusercontent.com/azure/avdaccelerator/anf-fslogix/workload/", + "varFslogixSharePath": "[if(parameters('createAvdFslogixDeployment'), format('\\\\{0}.file.{1}\\{2}', variables('varFslogixStorageName'), environment().suffixes.storage, variables('varFslogixFileShareName')), '')]", + "varBaseScriptUri": "https://raw.githubusercontent.com/azure/avdaccelerator/main/workload/", "varSessionHostConfigurationScriptUri": "[format('{0}scripts/Set-SessionHostConfiguration.ps1', variables('varBaseScriptUri'))]", "varSessionHostConfigurationScript": "Set-SessionHostConfiguration.ps1", + "varCreateStorageDeployment": "[if(or(parameters('createAvdFslogixDeployment'), equals(variables('varCreateAppAttachDeployment'), true())), true(), false())]", + "varFslogixStorageSku": "[if(parameters('zoneRedundantStorage'), format('{0}_ZRS', parameters('fslogixStoragePerformance')), format('{0}_LRS', parameters('fslogixStoragePerformance')))]", + "varAppAttachStorageSku": "[if(parameters('zoneRedundantStorage'), format('{0}_ZRS', parameters('appAttachStoragePerformance')), format('{0}_LRS', parameters('appAttachStoragePerformance')))]", "varMaxSessionHostsPerTemplate": 10, "varMaxSessionHostsDivisionValue": "[div(parameters('avdDeploySessionHostsCount'), variables('varMaxSessionHostsPerTemplate'))]", "varMaxSessionHostsDivisionRemainderValue": "[mod(parameters('avdDeploySessionHostsCount'), variables('varMaxSessionHostsPerTemplate'))]", @@ -1673,6 +1707,13 @@ } } ], + "varMarketPlaceGalleryWindows": "[variables('$fxv#1')]", + "varStorageAzureFilesDscAgentPackageLocation": "https://github.com/Azure/avdaccelerator/raw/main/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip", + "varStorageToDomainScriptUri": "[format('{0}scripts/Manual-DSC-Storage-Scripts.ps1', variables('varBaseScriptUri'))]", + "varStorageToDomainScript": "./Manual-DSC-Storage-Scripts.ps1", + "varOuStgPath": "[if(not(empty(parameters('storageOuPath'))), format('\"{0}\"', parameters('storageOuPath')), format('\"{0}\"', variables('varDefaultStorageOuPath')))]", + "varDefaultStorageOuPath": "[if(equals(parameters('avdIdentityServiceProvider'), 'EntraDS'), 'AADDC Computers', 'Computers')]", + "varStorageCustomOuPath": "[if(not(empty(parameters('storageOuPath'))), 'true', 'false')]", "varAllDnsServers": "[format('{0},168.63.129.16', parameters('customDnsIps'))]", "varDnsServers": "[if(empty(parameters('customDnsIps')), createArray(), split(variables('varAllDnsServers'), ','))]", "varCreateVnetPeering": "[if(not(empty(parameters('existingHubVnetResourceId'))), true(), false())]", @@ -1709,8 +1750,7 @@ } ], "varSecurityPrincipalId": "[if(not(empty(parameters('avdSecurityGroups'))), parameters('avdSecurityGroups')[0].objectId, '')]", - "varSecurityPrincipalName": "[if(not(empty(parameters('avdSecurityGroups'))), parameters('avdSecurityGroups')[0].displayName, '')]", - "varCreateStorageDeployment": "[if(or(parameters('createFslogixDeployment'), parameters('createAppAttachDeployment')), true(), false())]" + "varSecurityPrincipalName": "[if(not(empty(parameters('avdSecurityGroups'))), parameters('avdSecurityGroups')[0].displayName, '')]" }, "resources": [ { @@ -2132,7 +2172,7 @@ "dataCollectionRulesName": { "value": "[variables('varDataCollectionRulesName')]" }, - "storageObjectsRgName": "[if(variables('varCreateStorageDeployment'), createObject('value', variables('varStorageObjectsRgName')), createObject('value', ''))]", + "storageObjectsRgName": "[if(or(parameters('createAvdFslogixDeployment'), parameters('createAppAttachDeployment')), createObject('value', variables('varStorageObjectsRgName')), createObject('value', ''))]", "networkObjectsRgName": "[if(parameters('createAvdVnet'), createObject('value', variables('varNetworkObjectsRgName')), createObject('value', ''))]", "monitoringRgName": { "value": "[variables('varMonitoringRgName')]" @@ -4071,7 +4111,7 @@ ] }, { - "condition": "[or(or(or(or(parameters('createAvdVnet'), parameters('createPrivateDnsZones')), parameters('avdDeploySessionHosts')), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment'))]", + "condition": "[or(or(or(or(parameters('createAvdVnet'), parameters('createPrivateDnsZones')), parameters('avdDeploySessionHosts')), parameters('createAvdFslogixDeployment')), variables('varCreateAppAttachDeployment'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('Networking-{0}', parameters('time'))]", @@ -4085,7 +4125,7 @@ "createVnet": { "value": "[parameters('createAvdVnet')]" }, - "deployAsg": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', true()), createObject('value', false()))]", + "deployAsg": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createAvdFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', true()), createObject('value', false()))]", "existingAvdSubnetResourceId": { "value": "[parameters('existingVnetAvdSubnetResourceId')]" }, @@ -4102,9 +4142,6 @@ "avdNetworksecurityGroupName": { "value": "[variables('varAvdNetworksecurityGroupName')]" }, - "anfNetworksecurityGroupName": { - "value": "[variables('varAnfNetworksecurityGroupName')]" - }, "privateEndpointNetworksecurityGroupName": { "value": "[variables('varPrivateEndpointNetworksecurityGroupName')]" }, @@ -4132,9 +4169,6 @@ "vnetPrivateEndpointSubnetName": { "value": "[variables('varVnetPrivateEndpointSubnetName')]" }, - "vnetAnfSubnetName": { - "value": "[variables('varVnetAnfSubnetName')]" - }, "createVnetPeering": { "value": "[variables('varCreateVnetPeering')]" }, @@ -4145,7 +4179,6 @@ "value": "[variables('varDDosProtectionPlanName')]" }, "deployPrivateEndpointSubnet": "[if(or(parameters('deployPrivateEndpointKeyvaultStorage'), parameters('deployAvdPrivateLinkService')), createObject('value', true()), createObject('value', false()))]", - "deployAnfSubnet": "[if(equals(parameters('storageService'), 'ANF'), createObject('value', true()), createObject('value', false()))]", "deployAvdPrivateLinkService": { "value": "[parameters('deployAvdPrivateLinkService')]" }, @@ -4162,9 +4195,6 @@ "vnetPrivateEndpointSubnetAddressPrefix": { "value": "[parameters('vNetworkPrivateEndpointSubnetAddressPrefix')]" }, - "vnetAnfSubnetAddressPrefix": { - "value": "[parameters('vNetworkAnfSubnetAddressPrefix')]" - }, "workloadSubsId": { "value": "[parameters('avdWorkloadSubsId')]" }, @@ -4184,7 +4214,7 @@ "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "9241376745009248833" + "templateHash": "8051628348139083912" }, "name": "AVD LZA networking", "description": "This module deploys vNet, NSG, ASG, UDR, private DNs zones", @@ -4246,12 +4276,6 @@ "description": "Private endpoint Network Security Group Name" } }, - "anfNetworksecurityGroupName": { - "type": "string", - "metadata": { - "description": "ANF Network Security Group Name" - } - }, "applicationSecurityGroupName": { "type": "string", "metadata": { @@ -4318,12 +4342,6 @@ "description": "Optional. AVD Accelerator will deploy with private endpoints by default." } }, - "deployAnfSubnet": { - "type": "bool", - "metadata": { - "description": "Deploy with ANf subnet." - } - }, "deployAvdPrivateLinkService": { "type": "bool", "metadata": { @@ -4348,12 +4366,6 @@ "description": "Private endpoint subnet Name." } }, - "vnetAnfSubnetName": { - "type": "string", - "metadata": { - "description": "ANF subnet Name." - } - }, "vnetAvdSubnetAddressPrefix": { "type": "string", "metadata": { @@ -4366,12 +4378,6 @@ "description": "Private endpoint VNet subnet address prefix." } }, - "vnetAnfSubnetAddressPrefix": { - "type": "string", - "metadata": { - "description": "ANF VNet subnet address prefix." - } - }, "dnsServers": { "type": "array", "metadata": { @@ -5695,12 +5701,12 @@ } }, { - "condition": "[and(parameters('createVnet'), parameters('deployAnfSubnet'))]", + "condition": "[parameters('deployAsg')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('NSG-ANF-{0}', parameters('time'))]", + "name": "[format('ASG-{0}', parameters('time'))]", "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -5708,20 +5714,144 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('anfNetworksecurityGroupName')]" + "value": "[parameters('applicationSecurityGroupName')]" }, "location": { "value": "[parameters('location')]" }, "tags": { "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "6399800135303615704" + }, + "name": "Application Security Groups (ASG)", + "description": "This module deploys an Application Security Group (ASG).", + "owner": "Azure/module-maintainers" }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application Security Group." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } }, - "securityRules": { - "value": [] + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-applicationsecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "applicationSecurityGroup": { + "type": "Microsoft.Network/applicationSecurityGroups", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application security group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application security group." + }, + "value": "[resourceId('Microsoft.Network/applicationSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the application security group." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('applicationSecurityGroup', '2023-04-01', 'full').location]" + } } + } + } + }, + { + "condition": "[parameters('createVnet')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Route-Table-AVD-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('avdRouteTableName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "routes": "[if(variables('varCreateAvdStaticRoute'), createObject('value', variables('varStaticRoutes')), createObject('value', createArray()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -5731,102 +5861,64 @@ "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "9898059387129093740" + "templateHash": "17894283484101609343" }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG).", + "name": "Route Tables", + "description": "This module deploys a User Defined Route Table (UDR).", "owner": "Azure/module-maintainers" }, "definitions": { - "diagnosticSettingType": { + "routeType": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of diagnostic setting." + "description": "Required. Name of the route." } }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "properties": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "None", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The type of Azure hop the packet should be sent to." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination CIDR to which the route applies." + } + }, + "hasBgpOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." + } + }, + "nextHopIpAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "description": "Required. Properties of the route." } } } @@ -5838,7 +5930,7 @@ "name": { "type": "string", "metadata": { - "description": "Required. Name of the Network Security Group." + "description": "Required. Name given for the hub route table." } }, "location": { @@ -5848,31 +5940,24 @@ "description": "Optional. Location for all resources." } }, - "securityRules": { - "type": "array", - "defaultValue": [], + "routes": { + "$ref": "#/definitions/routeType", "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." + "description": "Optional. An array of routes to be established within the hub route table." } }, - "flushConnection": { + "disableBgpRoutePropagation": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Switch to disable BGP route propagation." } }, "tags": { "type": "object", "nullable": true, "metadata": { - "description": "Optional. Tags of the NSG resource." + "description": "Optional. Tags of the resource." } }, "enableTelemetry": { @@ -5888,7 +5973,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", "properties": { "mode": "Incremental", "template": { @@ -5904,400 +5989,175 @@ } } }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2023-11-01", + "routeTable": { + "type": "Microsoft.Network/routeTables", + "apiVersion": "2023-04-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(parameters('securityRules'))]", - "input": { - "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", - "properties": { - "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", - "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", - "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", - "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", - "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" - } - } - } - ], - "flushConnection": "[parameters('flushConnection')]" + "routes": "[parameters('routes')]", + "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the route table was deployed into." + }, + "value": "[resourceGroup().name]" }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + "name": { + "type": "string", + "metadata": { + "description": "The name of the route table." }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the route table." }, - "dependsOn": [ - "networkSecurityGroup" - ] + "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" }, - "networkSecurityGroup_securityRules": { - "copy": { - "name": "networkSecurityGroup_securityRules", - "count": "[length(parameters('securityRules'))]" + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { + "value": "[reference('routeTable', '2023-04-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Route-Table-PE-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('privateEndpointRouteTableName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "routes": { + "value": [] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "17894283484101609343" + }, + "name": "Route Tables", + "description": "This module deploys a User Defined Route Table (UDR).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "routeType": { + "type": "array", + "items": { + "type": "object", + "properties": { "name": { - "value": "[parameters('securityRules')[copyIndex()].name]" - }, - "networkSecurityGroupName": { - "value": "[parameters('name')]" - }, - "protocol": { - "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" - }, - "access": { - "value": "[parameters('securityRules')[copyIndex()].properties.access]" - }, - "priority": { - "value": "[parameters('securityRules')[copyIndex()].properties.priority]" - }, - "direction": { - "value": "[parameters('securityRules')[copyIndex()].properties.direction]" - }, - "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "714966927696814087" - }, - "name": "Network Security Group (NSG) Security Rules", - "description": "This module deploys a Network Security Group (NSG) Security Rule.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the security rule." - } - }, - "networkSecurityGroupName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." - } - }, - "access": { - "type": "string", - "defaultValue": "Deny", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Optional. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "maxLength": 140, - "metadata": { - "description": "Optional. A description for this rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The application security group specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "destinationPortRanges": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "metadata": { - "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The CIDR or source IP ranges." - } - }, - "sourceApplicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The application security group specified as source." - } - }, - "sourcePortRange": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "sourcePortRanges": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The source port ranges." - } + "type": "string", + "metadata": { + "description": "Required. Name of the route." } }, - "resources": [ - { - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-11-01", - "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", - "properties": { - "access": "[parameters('access')]", - "description": "[parameters('description')]", - "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", - "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", - "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", - "destinationPortRange": "[parameters('destinationPortRange')]", - "destinationPortRanges": "[parameters('destinationPortRanges')]", - "direction": "[parameters('direction')]", - "priority": "[parameters('priority')]", - "protocol": "[parameters('protocol')]", - "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", - "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", - "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", - "sourcePortRange": "[parameters('sourcePortRange')]", - "sourcePortRanges": "[parameters('sourcePortRanges')]" - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the security rule was deployed into." + "properties": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "None", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The type of Azure hop the packet should be sent to." + } }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the security rule." + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination CIDR to which the route applies." + } }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the security rule." + "hasBgpOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." + } }, - "value": "[parameters('name')]" + "nextHopIpAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "description": "Required. Properties of the route." } } } }, - "dependsOn": [ - "networkSecurityGroup" - ] + "nullable": true } }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the network security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the network security group." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" - }, + "parameters": { "name": { "type": "string", "metadata": { - "description": "The name of the network security group." - }, - "value": "[parameters('name')]" + "description": "Required. Name given for the hub route table." + } }, "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[parameters('deployAsg')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('ASG-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('applicationSecurityGroupName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "6399800135303615704" + "description": "Optional. Location for all resources." + } }, - "name": "Application Security Groups (ASG)", - "description": "This module deploys an Application Security Group (ASG).", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", + "routes": { + "$ref": "#/definitions/routeType", "metadata": { - "description": "Required. Name of the Application Security Group." + "description": "Optional. An array of routes to be established within the hub route table." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "disableBgpRoutePropagation": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. Switch to disable BGP route propagation." } }, "tags": { @@ -6320,7 +6180,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-applicationsecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", "properties": { "mode": "Incremental", "template": { @@ -6336,53 +6196,56 @@ } } }, - "applicationSecurityGroup": { - "type": "Microsoft.Network/applicationSecurityGroups", + "routeTable": { + "type": "Microsoft.Network/routeTables", "apiVersion": "2023-04-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "properties": {} + "properties": { + "routes": "[parameters('routes')]", + "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" + } } }, "outputs": { "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the application security group was deployed into." + "description": "The resource group the route table was deployed into." }, "value": "[resourceGroup().name]" }, - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the application security group." + "description": "The name of the route table." }, - "value": "[resourceId('Microsoft.Network/applicationSecurityGroups', parameters('name'))]" + "value": "[parameters('name')]" }, - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the application security group." + "description": "The resource ID of the route table." }, - "value": "[parameters('name')]" + "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('applicationSecurityGroup', '2023-04-01', 'full').location]" + "value": "[reference('routeTable', '2023-04-01', 'full').location]" } } } } }, { - "condition": "[parameters('createVnet')]", + "condition": "[parameters('deployDDoSNetworkProtection')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('Route-Table-AVD-{0}', parameters('time'))]", + "name": "[format('DDoS-Protection-Plan-{0}', parameters('time'))]", "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", "properties": { @@ -6392,15 +6255,11 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('avdRouteTableName')]" + "value": "[parameters('ddosProtectionPlanName')]" }, "location": { "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "routes": "[if(variables('varCreateAvdStaticRoute'), createObject('value', variables('varStaticRoutes')), createObject('value', createArray()))]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -6410,76 +6269,18 @@ "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "17894283484101609343" + "templateHash": "6678083091788427255" }, - "name": "Route Tables", - "description": "This module deploys a User Defined Route Table (UDR).", + "name": "DDoS Protection Plans", + "description": "This module deploys a DDoS Protection Plan.", "owner": "Azure/module-maintainers" }, - "definitions": { - "routeType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the route." - } - }, - "properties": { - "type": "object", - "properties": { - "nextHopType": { - "type": "string", - "allowedValues": [ - "Internet", - "None", - "VirtualAppliance", - "VirtualNetworkGateway", - "VnetLocal" - ], - "metadata": { - "description": "Required. The type of Azure hop the packet should be sent to." - } - }, - "addressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination CIDR to which the route applies." - } - }, - "hasBgpOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." - } - }, - "nextHopIpAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." - } - } - }, - "metadata": { - "description": "Required. Properties of the route." - } - } - } - }, - "nullable": true - } - }, "parameters": { "name": { "type": "string", + "minLength": 1, "metadata": { - "description": "Required. Name given for the hub route table." + "description": "Required. Name of the DDoS protection plan to assign the VNET to." } }, "location": { @@ -6489,19 +6290,6 @@ "description": "Optional. Location for all resources." } }, - "routes": { - "$ref": "#/definitions/routeType", - "metadata": { - "description": "Optional. An array of routes to be established within the hub route table." - } - }, - "disableBgpRoutePropagation": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Switch to disable BGP route propagation." - } - }, "tags": { "type": "object", "nullable": true, @@ -6522,7 +6310,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "name": "[format('46d3xbcp.res.network-ddosprotectionplan.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -6538,56 +6326,53 @@ } } }, - "routeTable": { - "type": "Microsoft.Network/routeTables", - "apiVersion": "2023-04-01", + "ddosProtectionPlan": { + "type": "Microsoft.Network/ddosProtectionPlans", + "apiVersion": "2023-11-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", - "properties": { - "routes": "[parameters('routes')]", - "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" - } + "properties": {} } }, "outputs": { "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the route table was deployed into." + "description": "The resource group the DDOS protection plan was deployed into." }, "value": "[resourceGroup().name]" }, - "name": { + "resourceId": { "type": "string", "metadata": { - "description": "The name of the route table." + "description": "The resource ID of the DDOS protection plan." }, - "value": "[parameters('name')]" + "value": "[resourceId('Microsoft.Network/ddosProtectionPlans', parameters('name'))]" }, - "resourceId": { + "name": { "type": "string", "metadata": { - "description": "The resource ID of the route table." + "description": "The name of the DDOS protection plan." }, - "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" + "value": "[parameters('name')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('routeTable', '2023-04-01', 'full').location]" + "value": "[reference('ddosProtectionPlan', '2023-11-01', 'full').location]" } } } } }, { - "condition": "[and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet'))]", + "condition": "[parameters('createVnet')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('Route-Table-PE-{0}', parameters('time'))]", + "name": "[format('vNet-{0}', parameters('time'))]", "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", "properties": { @@ -6597,16 +6382,25 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('privateEndpointRouteTableName')]" + "value": "[parameters('vnetName')]" }, "location": { "value": "[parameters('location')]" }, + "addressPrefixes": { + "value": "[array(parameters('vnetAddressPrefixes'))]" + }, + "dnsServers": { + "value": "[parameters('dnsServers')]" + }, + "peerings": "[if(parameters('createVnetPeering'), createObject('value', createArray(createObject('remoteVirtualNetworkId', parameters('existingHubVnetResourceId'), 'name', parameters('vnetPeeringName'), 'allowForwardedTraffic', true(), 'allowGatewayTransit', false(), 'allowVirtualNetworkAccess', true(), 'doNotVerifyRemoteGateways', true(), 'useRemoteGateways', if(parameters('vNetworkGatewayOnHub'), true(), false()), 'remotePeeringEnabled', true(), 'remotePeeringName', parameters('remoteVnetPeeringName'), 'remotePeeringAllowForwardedTraffic', true(), 'remotePeeringAllowGatewayTransit', if(parameters('vNetworkGatewayOnHub'), true(), false()), 'remotePeeringAllowVirtualNetworkAccess', true(), 'remotePeeringDoNotVerifyRemoteGateways', true(), 'remotePeeringUseRemoteGateways', false()))), createObject('value', createArray()))]", + "subnets": "[if(parameters('deployPrivateEndpointSubnet'), createObject('value', createArray(createObject('name', parameters('vnetAvdSubnetName'), 'addressPrefix', parameters('vnetAvdSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')), createObject('name', parameters('vnetPrivateEndpointSubnetName'), 'addressPrefix', parameters('vnetPrivateEndpointSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-Private-Endpoint-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-PE-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')))), createObject('value', createArray(createObject('name', parameters('vnetAvdSubnetName'), 'addressPrefix', parameters('vnetAvdSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage', 'locations', createArray(format('{0}', parameters('location')))), createObject('service', 'Microsoft.KeyVault', 'locations', createArray(format('{0}', parameters('location')))))))))]", + "ddosProtectionPlanResourceId": "[if(parameters('deployDDoSNetworkProtection'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('DDoS-Protection-Plan-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', ''))]", "tags": { "value": "[parameters('tags')]" }, - "routes": { - "value": [] + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" } }, "template": { @@ -6617,352 +6411,7 @@ "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "17894283484101609343" - }, - "name": "Route Tables", - "description": "This module deploys a User Defined Route Table (UDR).", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "routeType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the route." - } - }, - "properties": { - "type": "object", - "properties": { - "nextHopType": { - "type": "string", - "allowedValues": [ - "Internet", - "None", - "VirtualAppliance", - "VirtualNetworkGateway", - "VnetLocal" - ], - "metadata": { - "description": "Required. The type of Azure hop the packet should be sent to." - } - }, - "addressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination CIDR to which the route applies." - } - }, - "hasBgpOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." - } - }, - "nextHopIpAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." - } - } - }, - "metadata": { - "description": "Required. Properties of the route." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name given for the hub route table." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "routes": { - "$ref": "#/definitions/routeType", - "metadata": { - "description": "Optional. An array of routes to be established within the hub route table." - } - }, - "disableBgpRoutePropagation": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Switch to disable BGP route propagation." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "routeTable": { - "type": "Microsoft.Network/routeTables", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "routes": "[parameters('routes')]", - "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" - } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the route table was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the route table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the route table." - }, - "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('routeTable', '2023-04-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[parameters('deployDDoSNetworkProtection')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('DDoS-Protection-Plan-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('ddosProtectionPlanName')]" - }, - "location": { - "value": "[parameters('location')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "6678083091788427255" - }, - "name": "DDoS Protection Plans", - "description": "This module deploys a DDoS Protection Plan.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "minLength": 1, - "metadata": { - "description": "Required. Name of the DDoS protection plan to assign the VNET to." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-ddosprotectionplan.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "ddosProtectionPlan": { - "type": "Microsoft.Network/ddosProtectionPlans", - "apiVersion": "2023-11-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": {} - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the DDOS protection plan was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the DDOS protection plan." - }, - "value": "[resourceId('Microsoft.Network/ddosProtectionPlans', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the DDOS protection plan." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('ddosProtectionPlan', '2023-11-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[parameters('createVnet')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('vNet-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('vnetName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "addressPrefixes": { - "value": "[array(parameters('vnetAddressPrefixes'))]" - }, - "dnsServers": { - "value": "[parameters('dnsServers')]" - }, - "peerings": "[if(parameters('createVnetPeering'), createObject('value', createArray(createObject('remoteVirtualNetworkId', parameters('existingHubVnetResourceId'), 'name', parameters('vnetPeeringName'), 'allowForwardedTraffic', true(), 'allowGatewayTransit', false(), 'allowVirtualNetworkAccess', true(), 'doNotVerifyRemoteGateways', true(), 'useRemoteGateways', if(parameters('vNetworkGatewayOnHub'), true(), false()), 'remotePeeringEnabled', true(), 'remotePeeringName', parameters('remoteVnetPeeringName'), 'remotePeeringAllowForwardedTraffic', true(), 'remotePeeringAllowGatewayTransit', if(parameters('vNetworkGatewayOnHub'), true(), false()), 'remotePeeringAllowVirtualNetworkAccess', true(), 'remotePeeringDoNotVerifyRemoteGateways', true(), 'remotePeeringUseRemoteGateways', false()))), createObject('value', createArray()))]", - "subnets": { - "value": "[union(if(parameters('deployPrivateEndpointSubnet'), createArray(createObject('name', parameters('vnetAvdSubnetName'), 'addressPrefix', parameters('vnetAvdSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''))), createArray(createObject('name', parameters('vnetAvdSubnetName'), 'addressPrefix', parameters('vnetAvdSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage', 'locations', createArray(format('{0}', parameters('location')))), createObject('service', 'Microsoft.KeyVault', 'locations', createArray(format('{0}', parameters('location')))))))), if(parameters('deployAnfSubnet'), createArray(createObject('name', parameters('vnetAnfSubnetName'), 'addressPrefix', parameters('vnetAnfSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(and(parameters('createVnet'), parameters('deployAnfSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-ANF-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'delegations', createArray(createObject('name', 'delegation', 'properties', createObject('serviceName', 'Microsoft.NetApp/volumes'))))), createArray()), if(parameters('deployPrivateEndpointSubnet'), createArray(createObject('name', parameters('vnetPrivateEndpointSubnetName'), 'addressPrefix', parameters('vnetPrivateEndpointSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-Private-Endpoint-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-PE-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''))), createArray()))]" - }, - "ddosProtectionPlanResourceId": "[if(parameters('deployDDoSNetworkProtection'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('DDoS-Protection-Plan-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', ''))]", - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "18267772730058349233" + "templateHash": "18267772730058349233" }, "name": "Virtual Networks", "description": "This module deploys a Virtual Network (vNet).", @@ -7964,7 +7413,6 @@ }, "dependsOn": [ "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('DDoS-Protection-Plan-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-ANF-{0}', parameters('time')))]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time')))]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-Private-Endpoint-{0}', parameters('time')))]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time')))]", @@ -23402,11 +22850,10 @@ ] }, { - "condition": "[variables('varCreateStorageDeployment')]", + "condition": "[and(not(equals(parameters('avdIdentityServiceProvider'), 'EntraID')), or(parameters('createAvdFslogixDeployment'), variables('varCreateAppAttachDeployment')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('SMB-Storage-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('avdWorkloadSubsId'))]", + "name": "[format('Storage-MGMT-VM-{0}', parameters('time'))]", "location": "[deployment().location]", "properties": { "expressionEvaluationOptions": { @@ -23414,64 +22861,44 @@ }, "mode": "Incremental", "parameters": { - "deploymentPrefix": { - "value": "[variables('varDeploymentPrefixLowercase')]" - }, - "deploymentEnvironment": { - "value": "[variables('varDeploymentEnvironmentLowercase')]" - }, - "storageService": { - "value": "[parameters('storageService')]" - }, - "useCustomNaming": { - "value": "[parameters('avdUseCustomNaming')]" - }, - "storageAvailabilityZones": { - "value": "[parameters('zoneRedundantStorage')]" - }, - "domainJoinUserName": { - "value": "[parameters('avdDomainJoinUserName')]" - }, - "vmLocalUserName": { - "value": "[parameters('avdVmLocalUserName')]" - }, + "diskEncryptionSetResourceId": "[if(parameters('diskZeroTrust'), createObject('value', reference(subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time'))), '2022-09-01').outputs.ztDiskEncryptionSetResourceId.value), createObject('value', ''))]", "identityServiceProvider": { "value": "[parameters('avdIdentityServiceProvider')]" }, - "avdSessionHostsOuPath": { - "value": "[parameters('avdOuPath')]" + "managementVmName": { + "value": "[variables('varManagementVmName')]" }, - "storageOuPath": { - "value": "[parameters('storageOuPath')]" + "computeTimeZone": { + "value": "[variables('varTimeZoneSessionHosts')]" }, - "managementVmSize": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostsSize')), createObject('value', 'Standard_D2ads_v5'))]", - "createResourceTags": { - "value": "[parameters('createResourceTags')]" + "applicationSecurityGroupResourceId": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createAvdFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', format('{0}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.applicationSecurityGroupResourceId.value)), createObject('value', ''))]", + "domainJoinUserName": { + "value": "[parameters('avdDomainJoinUserName')]" }, - "deployPrivateEndpointKeyvaultStorage": { - "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" + "wrklKvName": { + "value": "[variables('varWrklKvName')]" }, - "dnsServers": { - "value": "[parameters('customDnsIps')]" + "serviceObjectsRgName": { + "value": "[variables('varServiceObjectsRgName')]" }, "identityDomainName": { "value": "[parameters('identityDomainName')]" }, - "storageObjectsRgName": { - "value": "[variables('varStorageObjectsRgName')]" + "ouPath": { + "value": "[createObject('osImage', variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')], 'osDiskType', 'Standard_LRS', 'mgmtVmSize', parameters('avdSessionHostsSize'), 'enableAcceleratedNetworking', false(), 'ouPath', parameters('avdOuPath'), 'subnetId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId'))).ouPath]" }, - "baseScriptUri": { - "value": "[variables('varBaseScriptUri')]" + "osDiskType": { + "value": "[createObject('osImage', variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')], 'osDiskType', 'Standard_LRS', 'mgmtVmSize', parameters('avdSessionHostsSize'), 'enableAcceleratedNetworking', false(), 'ouPath', parameters('avdOuPath'), 'subnetId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId'))).osDiskType]" }, - "securityPrincipalName": { - "value": "[variables('varSecurityPrincipalName')]" + "location": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostLocation')), createObject('value', parameters('avdManagementPlaneLocation')))]", + "mgmtVmSize": { + "value": "[createObject('osImage', variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')], 'osDiskType', 'Standard_LRS', 'mgmtVmSize', parameters('avdSessionHostsSize'), 'enableAcceleratedNetworking', false(), 'ouPath', parameters('avdOuPath'), 'subnetId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId'))).mgmtVmSize]" }, - "diskEncryptionSetResourceId": "[if(parameters('diskZeroTrust'), createObject('value', reference(subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time'))), '2022-09-01').outputs.ztDiskEncryptionSetResourceId.value), createObject('value', ''))]", - "sessionHostTimeZone": { - "value": "[variables('varTimeZoneSessionHosts')]" + "subnetId": { + "value": "[createObject('osImage', variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')], 'osDiskType', 'Standard_LRS', 'mgmtVmSize', parameters('avdSessionHostsSize'), 'enableAcceleratedNetworking', false(), 'ouPath', parameters('avdOuPath'), 'subnetId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId'))).subnetId]" }, - "createFslogixDeployment": { - "value": "[parameters('createFslogixDeployment')]" + "enableAcceleratedNetworking": { + "value": "[createObject('osImage', variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')], 'osDiskType', 'Standard_LRS', 'mgmtVmSize', parameters('avdSessionHostsSize'), 'enableAcceleratedNetworking', false(), 'ouPath', parameters('avdOuPath'), 'subnetId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId'))).enableAcceleratedNetworking]" }, "securityType": "[if(equals(parameters('securityType'), 'Standard'), createObject('value', ''), createObject('value', parameters('securityType')))]", "secureBootEnabled": { @@ -23480,70 +22907,20 @@ "vTpmEnabled": { "value": "[parameters('vTpmEnabled')]" }, + "vmLocalUserName": { + "value": "[parameters('avdVmLocalUserName')]" + }, + "workloadSubsId": { + "value": "[parameters('avdWorkloadSubsId')]" + }, "encryptionAtHost": { "value": "[parameters('diskZeroTrust')]" }, "storageManagedIdentityResourceId": "[if(and(variables('varCreateStorageDeployment'), not(equals(parameters('avdIdentityServiceProvider'), 'EntraID'))), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time'))), '2022-09-01').outputs.managedIdentityStorageResourceId.value), createObject('value', ''))]", - "applicationSecurityGroupResourceId": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', format('{0}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.applicationSecurityGroupResourceId.value)), createObject('value', ''))]", - "createAppAttachDeployment": { - "value": "[parameters('createAppAttachDeployment')]" - }, - "fslogixFileShareCustomName": { - "value": "[parameters('fslogixFileShareCustomName')]" - }, - "appAttachFileShareCustomName": { - "value": "[parameters('appAttachFileShareCustomName')]" - }, - "storageAccountPrefixCustomName": { - "value": "[parameters('storageAccountPrefixCustomName')]" - }, - "anfAccountCustomName": { - "value": "[parameters('anfAccountCustomName')]" - }, - "managedIdentityClientId": "[if(and(variables('varCreateStorageDeployment'), not(equals(parameters('avdIdentityServiceProvider'), 'EntraID'))), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time'))), '2022-09-01').outputs.managedIdentityStorageClientId.value), createObject('value', ''))]", - "privateDnsZoneFilesResourceId": "[if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.azureFilesDnsZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneFilesId')))]", - "serviceObjectsRgName": { - "value": "[variables('varServiceObjectsRgName')]" - }, - "alaWorkspaceResourceId": "[if(parameters('avdDeployMonitoring'), if(parameters('deployAlaWorkspace'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.avdAlaWorkspaceResourceId.value), createObject('value', parameters('alaExistingWorkspaceResourceId'))), createObject('value', ''))]", - "deploymentEnvironmentOneCharacter": { - "value": "[variables('varDeploymentEnvironmentOneCharacter')]" - }, - "computeStorageResourcesNamingStandard": { - "value": "[variables('varComputeStorageResourcesNamingStandard')]" - }, - "fslogixFileShareQuotaSize": { - "value": "[parameters('fslogixFileShareQuotaSize')]" - }, - "appAttachFileShareQuotaSize": { - "value": "[parameters('appAttachFileShareQuotaSize')]" - }, - "fslogixStoragePerformance": { - "value": "[parameters('fslogixStoragePerformance')]" - }, - "appAttachStoragePerformance": { - "value": "[parameters('appAttachStoragePerformance')]" + "osImage": { + "value": "[createObject('osImage', variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')], 'osDiskType', 'Standard_LRS', 'mgmtVmSize', parameters('avdSessionHostsSize'), 'enableAcceleratedNetworking', false(), 'ouPath', parameters('avdOuPath'), 'subnetId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId'))).osImage]" }, - "anfSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAnfSubnetName'))), createObject('value', parameters('existingVnetAnfSubnetResourceId')))]", - "vmsSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", - "privateEndpointSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", - "location": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostLocation')), createObject('value', parameters('avdManagementPlaneLocation')))]", - "locationAcronym": "[if(parameters('avdDeploySessionHosts'), createObject('value', variables('varSessionHostLocationAcronym')), createObject('value', parameters('avdManagementPlaneLocation')))]", - "managementVmOsImage": { - "value": "[parameters('managementVmOsImage')]" - }, - "keyVaultResourceId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" - }, - "customResourceTags": { - "value": "[variables('varCustomResourceTags')]" - }, - "defaultTags": { - "value": "[variables('varAvdDefaultTags')]" - }, - "identityDomainGuid": { - "value": "[parameters('identityDomainGuid')]" - } + "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", @@ -23552,505 +22929,206 @@ "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "17332805804383803852" + "templateHash": "14566103234609369037" } }, "parameters": { - "subId": { + "diskEncryptionSetResourceId": { "type": "string", - "defaultValue": "[subscription().subscriptionId]", "metadata": { - "description": "The subscription ID for the AVD workload." + "description": "AVD disk encryption set resource ID to enable server side encyption." } }, - "deploymentPrefix": { + "workloadSubsId": { "type": "string", "metadata": { - "description": "The deployment prefix in lowercase." + "description": "AVD workload subscription ID, multiple subscriptions scenario." } }, - "deploymentEnvironment": { + "computeTimeZone": { "type": "string", "metadata": { - "description": "The deployment environment in lowercase." + "description": "Virtual machine time zone." } }, - "location": { + "identityServiceProvider": { "type": "string", "metadata": { - "description": "The session host location acronym derived from the resource group location." + "description": "Required, The service providing domain services for Azure Virtual Desktop." } }, - "locationAcronym": { + "serviceObjectsRgName": { "type": "string", "metadata": { - "description": "The session host or AVD management plane location acronym For example, \"eus\" for East US." + "description": "Resource Group Name for Azure Files." } }, - "storageService": { + "subnetId": { "type": "string", "metadata": { - "description": "The storage service to use (AzureFiles or ANF)." + "description": "AVD subnet ID." } }, - "useCustomNaming": { + "enableAcceleratedNetworking": { "type": "bool", "metadata": { - "description": "Indicates whether to use custom naming for AVD." - } - }, - "computeStorageResourcesNamingStandard": { - "type": "string", - "metadata": { - "description": "The naming standard for compute storage resources coming from the main template." - } - }, - "fslogixFileShareCustomName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The custom name for the FSLogix file share." - } - }, - "appAttachFileShareCustomName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The custom name for the App Attach file share." - } - }, - "managementVmOsImage": { - "type": "string", - "metadata": { - "description": "The OS image for the management VM." - } - }, - "storageAccountPrefixCustomName": { - "type": "string", - "defaultValue": "st", - "metadata": { - "description": "AVD FSLogix and App Attach storage account prefix custom name." - } - }, - "anfAccountCustomName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The custom name for the ANF account." - } - }, - "deploymentEnvironmentOneCharacter": { - "type": "string", - "metadata": { - "description": "Deployment prefix one character." - } - }, - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Key Vault." - } - }, - "alaWorkspaceResourceId": { - "type": "string", - "metadata": { - "description": "The Azure Log Analytics workspace resource ID." - } - }, - "privateDnsZoneFilesResourceId": { - "type": "string", - "metadata": { - "description": "The private DNS zone files resource ID." - } - }, - "managedIdentityClientId": { - "type": "string", - "metadata": { - "description": "The client ID of the managed identity." - } - }, - "fslogixFileShareQuotaSize": { - "type": "int", - "metadata": { - "description": "The FSLogix file share quota size in GiBs." - } - }, - "appAttachFileShareQuotaSize": { - "type": "int", - "metadata": { - "description": "The App Attach file share quota size in GiBs." - } - }, - "fslogixStoragePerformance": { - "type": "string", - "metadata": { - "description": "The storage performance level for FSLogix." - } - }, - "appAttachStoragePerformance": { - "type": "string", - "metadata": { - "description": "The storage performance level for App Attach." - } - }, - "anfSubnetResourceId": { - "type": "string", - "metadata": { - "description": "Subnet resource ID for ANF volumes." - } - }, - "vmsSubnetResourceId": { - "type": "string", - "metadata": { - "description": "Subnet resource ID for VMs." + "description": "Enable accelerated networking on the session host VMs." } }, "securityType": { "type": "string", "metadata": { - "description": "The security type for the VM (e.g., TrustedLaunch, Standard)." - } - }, - "privateEndpointSubnetResourceId": { - "type": "string", - "metadata": { - "description": "Subnet resource ID for private endpoints." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the disk encryption set." - } - }, - "encryptionAtHost": { - "type": "bool", - "metadata": { - "description": "Indicates whether encryption at host is enabled for the VM." - } - }, - "storageManagedIdentityResourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the managed identity for storage." + "description": "Specifies the securityType of the virtual machine. Must be TrustedLaunch or ConfidentialVM enable UefiSettings." } }, "secureBootEnabled": { "type": "bool", "metadata": { - "description": "Indicates whether secure boot is enabled for the VM." + "description": "Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." } }, "vTpmEnabled": { "type": "bool", "metadata": { - "description": "Indicates whether vTPM is enabled for the VM." - } - }, - "sessionHostTimeZone": { - "type": "string", - "metadata": { - "description": "The time zone for the session host." + "description": "Specifies whether virtual TPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." } }, - "applicationSecurityGroupResourceId": { + "location": { "type": "string", "metadata": { - "description": "The resource ID of the application security group." + "description": "Location where to deploy compute services." } }, - "storageAvailabilityZones": { + "encryptionAtHost": { "type": "bool", "metadata": { - "description": "USe or not zone redundant storage." - } - }, - "dnsServers": { - "type": "string", - "metadata": { - "description": "The custom DNS IPs." + "description": "This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." } }, - "identityServiceProvider": { + "mgmtVmSize": { "type": "string", "metadata": { - "description": "The identity service provider (e.g., EntraDS)." + "description": "Session host VM size." } }, - "domainJoinUserName": { + "osDiskType": { "type": "string", "metadata": { - "description": "The domain join username." + "description": "OS disk type for session host." } }, - "vmLocalUserName": { - "type": "string", + "osImage": { + "type": "object", "metadata": { - "description": "The VM local username." + "description": "Market Place OS image" } }, - "serviceObjectsRgName": { + "storageManagedIdentityResourceId": { "type": "string", "metadata": { - "description": "The service objects resource group name." + "description": "Storage Managed Identity Resource ID." } }, - "storageObjectsRgName": { + "vmLocalUserName": { "type": "string", "metadata": { - "description": "The storage objects resource group name." + "description": "Local administrator username." } }, - "managementVmSize": { + "identityDomainName": { "type": "string", "metadata": { - "description": "The VM size for the management VM." + "description": "Identity domain name." } }, - "avdSessionHostsOuPath": { + "wrklKvName": { "type": "string", "metadata": { - "description": "The OU path for AVD session hosts." + "description": "Keyvault name to get credentials from." } }, - "storageOuPath": { + "domainJoinUserName": { "type": "string", - "defaultValue": "", - "metadata": { - "description": "The storage OU path." - } - }, - "customResourceTags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "The custom resource tags." - } - }, - "defaultTags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "The AVD default tags." - } - }, - "createResourceTags": { - "type": "bool", "metadata": { - "description": "Indicates whether to create resource tags." + "description": "AVD session host domain join credentials." } }, - "baseScriptUri": { + "ouPath": { "type": "string", "metadata": { - "description": "The base script URI." + "description": "OU path to join AVd VMs." } }, - "securityPrincipalName": { + "applicationSecurityGroupResourceId": { "type": "string", - "defaultValue": "", "metadata": { - "description": "The security principal name." + "description": "Application Security Group (ASG) for the session hosts." } }, - "identityDomainName": { - "type": "string", + "tags": { + "type": "object", "metadata": { - "description": "The identity domain name." + "description": "Tags to be applied to resources" } }, - "identityDomainGuid": { + "managementVmName": { "type": "string", - "defaultValue": "", - "metadata": { - "description": "The identity domain GUID." - } - }, - "deployPrivateEndpointKeyvaultStorage": { - "type": "bool", - "metadata": { - "description": "Indicates whether to deploy private endpoints for Key Vault and storage." - } - }, - "createFslogixDeployment": { - "type": "bool", "metadata": { - "description": "Indicates whether to create FSLogix deployment." - } - }, - "createAppAttachDeployment": { - "type": "bool", - "metadata": { - "description": "Indicates whether to create App Attach deployment." + "description": "Name for management virtual machine. for tools and to join Azure Files to domain." } }, "time": { "type": "string", "defaultValue": "[utcNow()]", "metadata": { - "description": "The deployment timestamp." + "description": "Do not modify, used to set unique value for resource deployment." } } }, "variables": { - "$fxv#0": { - "win10_22h2_g2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "windows-10", - "sku": "win10-22h2-avd-g2", - "version": "latest" - }, - "win10_22h2_office_g2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "office-365", - "sku": "win10-22h2-avd-m365-g2", - "version": "latest" - }, - "win11_22h2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "Windows-11", - "sku": "win11-22h2-avd", - "version": "latest" - }, - "win11_22h2_office": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "office-365", - "sku": "win11-22h2-avd-m365", - "version": "latest" - }, - "win11_23h2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "Windows-11", - "sku": "win11-23h2-avd", - "version": "latest" - }, - "win11_23h2_office": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "office-365", - "sku": "win11-23h2-avd-m365", - "version": "latest" - }, - "win11_24h2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "Windows-11", - "sku": "win11-24h2-avd", - "version": "latest" - }, - "win11_24h2_office": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "office-365", - "sku": "win11-24h2-avd-m365", - "version": "latest" - }, - "winServer_2022_Datacenter": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "2022-datacenter-g2", - "version": "latest" - }, - "winServer_2022_Datacenter_smalldisk_g2": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "2022-datacenter-smalldisk-g2", - "version": "latest" - }, - "winServer_2022_datacenter_core": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "2022-datacenter-core-g2", - "version": "latest" - }, - "winServer_2022_Datacenter_core_smalldisk_g2": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "2022-datacenter-core-smalldisk-g2", - "version": "latest" - } - }, - "varNamingUniqueStringThreeChar": "[take(format('{0}', uniqueString(parameters('subId'), parameters('deploymentPrefix'), parameters('time'))), 3)]", - "varAnfCapacityPoolSize": "[if(greater(add(if(parameters('createFslogixDeployment'), parameters('fslogixFileShareQuotaSize'), 0), if(parameters('createAppAttachDeployment'), parameters('appAttachFileShareQuotaSize'), 0)), 4096), add(if(parameters('createFslogixDeployment'), parameters('fslogixFileShareQuotaSize'), 0), if(parameters('createAppAttachDeployment'), parameters('appAttachFileShareQuotaSize'), 0)), 4096)]", - "varFslogixFileShareName": "[if(equals(parameters('storageService'), 'AzureFiles'), if(parameters('useCustomNaming'), parameters('fslogixFileShareCustomName'), format('fslogix-pc-{0}-{1}-{2}-001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('locationAcronym'))), if(equals(parameters('storageService'), 'ANF'), format('fsl{0}{1}{2}001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('locationAcronym')), ''))]", - "varAnfSmbServerNamePrefix": "[format('anf{0}{1}', parameters('deploymentPrefix'), parameters('deploymentEnvironment'))]", - "varAppAttachFileShareName": "[if(equals(parameters('storageService'), 'AzureFiles'), if(parameters('useCustomNaming'), parameters('appAttachFileShareCustomName'), format('appa-{0}-{1}-{2}-001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('locationAcronym'))), if(equals(parameters('storageService'), 'ANF'), format('appa{0}01', parameters('deploymentPrefix')), ''))]", - "varFslogixAnfVolume": "[if(parameters('createFslogixDeployment'), createArray(createObject('name', variables('varFslogixFileShareName'), 'coolAccess', false(), 'encryptionKeySource', 'Microsoft.NetApp', 'zones', createArray(), 'serviceLevel', parameters('fslogixStoragePerformance'), 'networkFeatures', 'Standard', 'usageThreshold', mul(parameters('fslogixFileShareQuotaSize'), 1073741824), 'protocolTypes', createArray('CIFS'), 'subnetResourceId', parameters('anfSubnetResourceId'), 'creationToken', variables('varFslogixFileShareName'), 'smbContinuouslyAvailable', true(), 'securityStyle', 'ntfs')), createArray())]", - "varAppAttchAnfVolume": "[if(parameters('createAppAttachDeployment'), createArray(createObject('name', variables('varAppAttachFileShareName'), 'coolAccess', false(), 'encryptionKeySource', 'Microsoft.NetApp', 'zones', createArray(), 'serviceLevel', parameters('appAttachStoragePerformance'), 'networkFeatures', 'Standard', 'usageThreshold', mul(parameters('appAttachFileShareQuotaSize'), 1073741824), 'protocolTypes', createArray('CIFS'), 'subnetResourceId', parameters('anfSubnetResourceId'), 'creationToken', variables('varAppAttachFileShareName'), 'smbContinuouslyAvailable', true(), 'securityStyle', 'ntfs')), createArray())]", - "varAnfVolumes": "[union(variables('varFslogixAnfVolume'), variables('varAppAttchAnfVolume'))]", - "varFslogixStorageName": "[if(parameters('useCustomNaming'), format('{0}fsl{1}{2}{3}', parameters('storageAccountPrefixCustomName'), parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')), format('stfsl{0}{1}{2}', parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')))]", - "varAnfAccountName": "[if(parameters('useCustomNaming'), parameters('anfAccountCustomName'), format('anf-acc-{0}-001', parameters('computeStorageResourcesNamingStandard')))]", - "varAnfCapacityPoolName": "[format('anf-cpool-{0}-001', parameters('computeStorageResourcesNamingStandard'))]", - "varFslogixStorageFqdn": "[if(parameters('createFslogixDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('{0}.file.{1}', variables('varFslogixStorageName'), environment().suffixes.storage), if(equals(parameters('storageService'), 'ANF'), format('{0}...{1}.netapp.azure.com', variables('varFslogixFileShareName'), parameters('location')), '')), '')]", - "varAppAttachStorageFqdn": "[if(parameters('createAppAttachDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('{0}.file.{1}', variables('varAppAttachStorageName'), environment().suffixes.storage), if(equals(parameters('storageService'), 'ANF'), format('{0}...{1}.netapp.azure.com', variables('varAppAttachFileShareName'), parameters('location')), '')), '')]", - "varAppAttachStorageName": "[if(parameters('useCustomNaming'), format('{0}appa{1}{2}{3}', parameters('storageAccountPrefixCustomName'), parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')), format('stappa{0}{1}{2}', parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')))]", - "varManagementVmName": "[format('vmmgmt{0}{1}{2}', parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), parameters('locationAcronym'))]", - "varFslogixStoragePerformance": "[if(equals(parameters('fslogixStoragePerformance'), 'Ultra'), 'Premium', parameters('fslogixStoragePerformance'))]", - "varAppAttachStoragePerformance": "[if(equals(parameters('appAttachStoragePerformance'), 'Ultra'), 'Premium', parameters('appAttachStoragePerformance'))]", - "varFslogixStorageSku": "[if(and(parameters('storageAvailabilityZones'), equals(parameters('storageService'), 'AzureFiles')), format('{0}_ZRS', variables('varFslogixStoragePerformance')), format('{0}_LRS', variables('varFslogixStoragePerformance')))]", - "varAppAttachStorageSku": "[if(parameters('storageAvailabilityZones'), format('{0}_ZRS', variables('varAppAttachStoragePerformance')), format('{0}_LRS', variables('varAppAttachStoragePerformance')))]", - "varStorageAzureFilesDscAgentPackageLocation": "https://github.com/Azure/avdaccelerator/raw/main/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip", - "varStorageToDomainScriptUri": "[format('{0}scripts/Manual-DSC-Storage-Scripts.ps1', parameters('baseScriptUri'))]", - "varStorageToDomainScript": "./Manual-DSC-Storage-Scripts.ps1", - "varOuStgPath": "[if(not(empty(parameters('storageOuPath'))), format('\"{0}\"', parameters('storageOuPath')), format('\"{0}\"', variables('varDefaultStorageOuPath')))]", - "varDefaultStorageOuPath": "[if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDC Computers', 'Computers')]", - "varStorageCustomOuPath": "[if(not(empty(parameters('storageOuPath'))), 'true', 'false')]", - "varMarketPlaceGalleryWindows": "[variables('$fxv#0')]" + "varManagedDisk": "[if(empty(parameters('diskEncryptionSetResourceId')), createObject('storageAccountType', parameters('osDiskType')), createObject('diskEncryptionSet', createObject('id', parameters('diskEncryptionSetResourceId')), 'storageAccountType', parameters('osDiskType')))]" }, "resources": [ { - "condition": "[and(not(equals(parameters('identityServiceProvider'), 'EntraID')), or(parameters('createFslogixDeployment'), parameters('createAppAttachDeployment')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('Storage-MGMT-VM-{0}', parameters('time'))]", - "location": "[deployment().location]", + "name": "[format('MGMT-VM-{0}', parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "diskEncryptionSetResourceId": { - "value": "[parameters('diskEncryptionSetResourceId')]" - }, - "identityServiceProvider": { - "value": "[parameters('identityServiceProvider')]" - }, - "vmName": { - "value": "[variables('varManagementVmName')]" - }, - "computeTimeZone": { - "value": "[parameters('sessionHostTimeZone')]" - }, - "applicationSecurityGroupResourceId": { - "value": "[parameters('applicationSecurityGroupResourceId')]" - }, - "domainJoinUserName": { - "value": "[parameters('domainJoinUserName')]" + "name": { + "value": "[parameters('managementVmName')]" }, - "keyVaultResourceId": { - "value": "[parameters('keyVaultResourceId')]" + "location": { + "value": "[parameters('location')]" }, - "serviceObjectsRgName": { - "value": "[parameters('serviceObjectsRgName')]" + "timeZone": { + "value": "[parameters('computeTimeZone')]" }, - "identityDomainName": { - "value": "[parameters('identityDomainName')]" + "managedIdentities": { + "value": { + "systemAssigned": false, + "userAssignedResourceIds": [ + "[parameters('storageManagedIdentityResourceId')]" + ] + } }, - "ouPath": { - "value": "[parameters('avdSessionHostsOuPath')]" + "encryptionAtHost": { + "value": "[parameters('encryptionAtHost')]" }, - "osDiskType": { - "value": "Standard_LRS" + "zone": { + "value": 0 }, - "location": { - "value": "[parameters('location')]" + "osType": { + "value": "Windows" }, "vmSize": { - "value": "[parameters('managementVmSize')]" - }, - "subnetResourceId": { - "value": "[parameters('vmsSubnetResourceId')]" - }, - "enableAcceleratedNetworking": { - "value": true + "value": "[parameters('mgmtVmSize')]" }, "securityType": { "value": "[parameters('securityType')]" @@ -24061,4840 +23139,912 @@ "vTpmEnabled": { "value": "[parameters('vTpmEnabled')]" }, - "vmLocalUserName": { + "imageReference": { + "value": "[parameters('osImage')]" + }, + "osDisk": { + "value": { + "createOption": "FromImage", + "deleteOption": "Delete", + "caching": "ReadWrite", + "managedDisk": "[variables('varManagedDisk')]" + } + }, + "adminUsername": { "value": "[parameters('vmLocalUserName')]" }, - "subId": { - "value": "[parameters('subId')]" + "adminPassword": { + "reference": { + "keyVault": { + "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.KeyVault/vaults', parameters('wrklKvName'))]" + }, + "secretName": "vmLocalUserPassword" + } }, - "encryptionAtHost": { - "value": "[parameters('encryptionAtHost')]" + "nicConfigurations": { + "value": [ + { + "name": "[format('nic-01-{0}', parameters('managementVmName'))]", + "deleteOption": "Delete", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "ipConfigurations": "[if(not(empty(parameters('applicationSecurityGroupResourceId'))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetId'), 'applicationSecurityGroups', createArray(createObject('id', parameters('applicationSecurityGroupResourceId'))))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetId'))))]" + } + ] + }, + "allowExtensionOperations": { + "value": true + }, + "extensionDomainJoinPassword": { + "reference": { + "keyVault": { + "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.KeyVault/vaults', parameters('wrklKvName'))]" + }, + "secretName": "domainJoinUserPassword" + } }, - "storageManagedIdentityResourceId": { - "value": "[parameters('storageManagedIdentityResourceId')]" + "extensionDomainJoinConfig": { + "value": { + "enabled": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), false(), true())]", + "settings": { + "name": "[parameters('identityDomainName')]", + "ouPath": "[if(not(empty(parameters('ouPath'))), parameters('ouPath'), null())]", + "user": "[parameters('domainJoinUserName')]", + "restart": "true", + "options": "3" + } + } }, - "osImage": { - "value": "[variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')]]" + "extensionAadJoinConfig": { + "value": { + "enabled": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), true(), false())]" + } }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]" + "tags": { + "value": "[parameters('tags')]" + } }, "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "8670712661433034722" + "templateHash": "13031055217657209142" }, - "name": "AVD LZA storage management VM", - "description": "This module deploys a management VM to join Azure Files to domain and for tools.", - "owner": "Azure/avdaccelerator" + "name": "Virtual Machines", + "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", + "owner": "Azure/module-maintainers" }, - "parameters": { - "diskEncryptionSetResourceId": { - "type": "string", - "metadata": { - "description": "AVD disk encryption set resource ID to enable server side encyption." - } - }, - "subId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "computeTimeZone": { - "type": "string", - "metadata": { - "description": "Virtual machine time zone." - } - }, - "identityServiceProvider": { - "type": "string", - "metadata": { - "description": "Required, The service providing domain services for Azure Virtual Desktop." - } - }, - "serviceObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group Name for Azure Files." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Subnet resource ID." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "metadata": { - "description": "Enable accelerated networking on the session host VMs." - } - }, - "securityType": { - "type": "string", - "metadata": { - "description": "Specifies the securityType of the virtual machine. Must be TrustedLaunch or ConfidentialVM enable UefiSettings." - } - }, - "secureBootEnabled": { - "type": "bool", - "metadata": { - "description": "Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "vTpmEnabled": { - "type": "bool", - "metadata": { - "description": "Specifies whether virtual TPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy compute services." - } - }, - "encryptionAtHost": { - "type": "bool", - "metadata": { - "description": "This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "Session host VM size." - } - }, - "osDiskType": { - "type": "string", - "metadata": { - "description": "OS disk type for session host." - } - }, - "osImage": { + "definitions": { + "managedIdentitiesType": { "type": "object", - "metadata": { - "description": "Market Place OS image" - } - }, - "storageManagedIdentityResourceId": { - "type": "string", - "metadata": { - "description": "Storage Managed Identity Resource ID." - } - }, - "vmLocalUserName": { - "type": "string", - "metadata": { - "description": "Local administrator username." - } - }, - "identityDomainName": { - "type": "string", - "metadata": { - "description": "Identity domain name." - } - }, - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Keyvault resource ID to get credentials from." - } - }, - "domainJoinUserName": { - "type": "string", - "metadata": { - "description": "AVD session host domain join credentials." - } - }, - "ouPath": { - "type": "string", - "metadata": { - "description": "OU path to join AVd VMs." - } - }, - "applicationSecurityGroupResourceId": { - "type": "string", - "metadata": { - "description": "Application Security Group (ASG) for the session hosts." - } + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true }, - "tags": { + "osDiskType": { "type": "object", - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "vmName": { - "type": "string", - "metadata": { - "description": "Name for management virtual machine. for tools and to join Azure Files to domain." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - } - }, - "variables": { - "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", - "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", - "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]", - "varManagedDisk": "[if(empty(parameters('diskEncryptionSetResourceId')), createObject('storageAccountType', parameters('osDiskType')), createObject('diskEncryptionSet', createObject('id', parameters('diskEncryptionSetResourceId')), 'storageAccountType', parameters('osDiskType')))]" - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('MGMT-VM-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." + } }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('vmName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "timeZone": { - "value": "[parameters('computeTimeZone')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": false, - "userAssignedResourceIds": [ - "[parameters('storageManagedIdentityResourceId')]" - ] - } - }, - "encryptionAtHost": { - "value": "[parameters('encryptionAtHost')]" - }, - "zone": { - "value": 0 - }, - "osType": { - "value": "Windows" - }, - "vmSize": { - "value": "[parameters('vmSize')]" - }, - "securityType": { - "value": "[parameters('securityType')]" - }, - "secureBootEnabled": { - "value": "[parameters('secureBootEnabled')]" - }, - "vTpmEnabled": { - "value": "[parameters('vTpmEnabled')]" - }, - "imageReference": { - "value": "[parameters('osImage')]" - }, - "osDisk": { - "value": { - "createOption": "FromImage", - "deleteOption": "Delete", - "caching": "ReadWrite", - "managedDisk": "[variables('varManagedDisk')]" + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." + } + }, + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." + } + }, + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } + }, + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "metadata": { + "description": "Required. Specifies the storage account type for the managed disk." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." + } } }, - "adminUsername": { - "value": "[parameters('vmLocalUserName')]" - }, - "adminPassword": { - "reference": { - "keyVault": { - "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))]" - }, - "secretName": "vmLocalUserPassword" + "metadata": { + "description": "Required. The managed disk parameters." + } + } + } + }, + "dataDisksType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The disk name." } }, - "nicConfigurations": { - "value": [ - { - "name": "[format('nic-01-{0}', parameters('vmName'))]", - "deleteOption": "Delete", - "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", - "ipConfigurations": "[if(not(empty(parameters('applicationSecurityGroupResourceId'))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetResourceId'), 'applicationSecurityGroups', createArray(createObject('id', parameters('applicationSecurityGroupResourceId'))))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetResourceId'))))]" - } - ] - }, - "allowExtensionOperations": { - "value": true + "lun": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the logical unit number of the data disk." + } }, - "extensionDomainJoinPassword": { - "reference": { - "keyVault": { - "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))]" - }, - "secretName": "domainJoinUserPassword" + "diskSizeGB": { + "type": "int", + "maxValue": 1023, + "metadata": { + "description": "Required. Specifies the size of an empty data disk in gigabytes." } }, - "extensionDomainJoinConfig": { - "value": { - "enabled": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), false(), true())]", - "settings": { - "name": "[parameters('identityDomainName')]", - "ouPath": "[if(not(empty(parameters('ouPath'))), parameters('ouPath'), null())]", - "user": "[parameters('domainJoinUserName')]", - "restart": "true", - "options": "3" - } + "createOption": { + "type": "string", + "allowedValues": [ + "Attach", + "Empty", + "FromImage" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies how the virtual machine should be created." } }, - "extensionAadJoinConfig": { - "value": { - "enabled": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), true(), false())]" + "deleteOption": { + "type": "string", + "allowedValues": [ + "Delete", + "Detach" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." } }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13031055217657209142" - }, - "name": "Virtual Machines", - "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", - "owner": "Azure/module-maintainers" + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the caching requirements." + } }, - "definitions": { - "managedIdentitiesType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } + "managedDisk": { + "type": "object", + "properties": { + "storageAccountType": { + "type": "string", + "allowedValues": [ + "PremiumV2_LRS", + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "metadata": { + "description": "Required. Specifies the storage account type for the managed disk." } }, - "nullable": true - }, - "osDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "metadata": { - "description": "Required. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." } } }, - "dataDisksType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "lun": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the logical unit number of the data disk." - } - }, - "diskSizeGB": { - "type": "int", - "maxValue": 1023, - "metadata": { - "description": "Required. Specifies the size of an empty data disk in gigabytes." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "metadata": { - "description": "Required. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." - } - }, - "computerName": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "Required. Specifies the size for the VMs." - } - }, - "encryptionAtHost": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "securityType": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the SecurityType of the virtual machine. It is set as TrustedLaunch to enable UefiSettings." - } - }, - "secureBootEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "vTpmEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "imageReference": { - "type": "object", - "metadata": { - "description": "Required. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image." - } - }, - "plan": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." - } - }, - "osDisk": { - "$ref": "#/definitions/osDiskType", - "metadata": { - "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "dataDisks": { - "$ref": "#/definitions/dataDisksType", - "metadata": { - "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "ultraSSDEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." - } - }, - "adminUsername": { - "type": "securestring", - "metadata": { - "description": "Required. Administrator username." - } - }, - "adminPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. When specifying a Windows Virtual Machine, this value should be passed." - } - }, - "customData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." - } - }, - "certificatesToBeInstalled": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." - } - }, - "priority": { - "type": "string", - "defaultValue": "Regular", - "allowedValues": [ - "Regular", - "Low", - "Spot" - ], - "metadata": { - "description": "Optional. Specifies the priority for the virtual machine." - } - }, - "enableEvictionPolicy": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy." - } - }, - "maxPriceForLowPriorityVm": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." - } - }, - "dedicatedHostId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." - } - }, - "licenseType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "RHEL_BYOS", - "SLES_BYOS", - "Windows_Client", - "Windows_Server", - "" - ], - "metadata": { - "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", - "metadata": { - "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." - } - }, - "bootDiagnostics": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." - } - }, - "bootDiagnosticStorageAccountName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." - } - }, - "bootDiagnosticStorageAccountUri": { - "type": "string", - "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", - "metadata": { - "description": "Optional. Storage account boot diagnostic base URI." - } - }, - "proximityPlacementGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a proximity placement group." - } - }, - "virtualMachineScaleSetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." - } - }, - "availabilitySetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." - } - }, - "zone": { - "type": "int", - "allowedValues": [ - 0, - 1, - 2, - 3 - ], - "metadata": { - "description": "Required. If set to 1, 2 or 3, the availability zone for all VMs is hardcoded to that value. If zero, then availability zones is not used. Cannot be used in combination with availability set nor scale set." - } - }, - "nicConfigurations": { - "type": "array", - "metadata": { - "description": "Required. Configures NICs and PIPs." - } - }, - "allowExtensionOperations": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." - } - }, - "extensionDomainJoinPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if name is specified. Password of the user specified in user parameter." - } - }, - "extensionDomainJoinConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAadJoinConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." - } - }, - "extensionAzureDiskEncryptionConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." - } - }, - "extensionDSCConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionCustomScriptConfig": { - "type": "object", - "defaultValue": { - "enabled": false, - "fileData": [] - }, - "metadata": { - "description": "Optional. The configuration for the [Custom Script] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionNvidiaGpuDriverWindows": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionCustomScriptProtectedSetting": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. An object that contains the extension specific protected settings." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "baseTime": { - "type": "string", - "defaultValue": "[utcNow('u')]", - "metadata": { - "description": "Generated. Do not provide a value! This date value is used to generate a registration token." - } - }, - "sasTokenValidityLength": { - "type": "string", - "defaultValue": "PT8H", - "metadata": { - "description": "Optional. SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." - } - }, - "osType": { - "type": "string", - "allowedValues": [ - "Windows", - "Linux" - ], - "metadata": { - "description": "Required. The chosen OS type." - } - }, - "provisionVMAgent": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." - } - }, - "enableAutomaticUpdates": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." - } - }, - "patchMode": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "AutomaticByPlatform", - "AutomaticByOS", - "Manual", - "ImageDefault", - "" - ], - "metadata": { - "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." - } - }, - "bypassPlatformSafetyChecksOnUserSchedule": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enables customer to schedule patching without accidental upgrades." - } - }, - "rebootSetting": { - "type": "string", - "defaultValue": "IfRequired", - "allowedValues": [ - "Always", - "IfRequired", - "Never", - "Unknown" - ], - "metadata": { - "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." - } - }, - "patchAssessmentMode": { - "type": "string", - "defaultValue": "ImageDefault", - "allowedValues": [ - "AutomaticByPlatform", - "ImageDefault" - ], - "metadata": { - "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." - } - }, - "timeZone": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." - } - }, - "additionalUnattendContent": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." - } - }, - "winRM": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object." - } - }, - "configurationProfile": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." - } - } - }, - "variables": { - "windowsConfiguration": { - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting'))), null())]", - "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", - "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), parameters('additionalUnattendContent'))]", - "winRM": "[if(not(empty(parameters('winRM'))), createObject('listeners', parameters('winRM')), null())]" - }, - "accountSasProperties": { - "signedServices": "b", - "signedPermission": "r", - "signedExpiry": "[dateTimeAdd(parameters('baseTime'), parameters('sasTokenValidityLength'))]", - "signedResourceTypes": "o", - "signedProtocol": "https" - }, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "vm": { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2023-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "zones": "[if(not(equals(parameters('zone'), 0)), array(string(parameters('zone'))), null())]", - "plan": "[if(not(empty(parameters('plan'))), parameters('plan'), null())]", - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "securityProfile": { - "encryptionAtHost": "[if(parameters('encryptionAtHost'), parameters('encryptionAtHost'), null())]", - "securityType": "[parameters('securityType')]", - "uefiSettings": "[if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null())]" - }, - "storageProfile": { - "copy": [ - { - "name": "dataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", - "input": { - "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", - "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))]", - "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createoption'), 'Empty')]", - "deleteOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete')]", - "caching": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly')]", - "managedDisk": { - "storageAccountType": "[coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.storageAccountType]", - "diskEncryptionSet": "[coalesce(tryGet(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'managedDisk'), 'diskEncryptionSet'), null())]" - } - } - } - ], - "imageReference": "[parameters('imageReference')]", - "osDisk": { - "name": "[coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name')))]", - "createOption": "[coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage')]", - "deleteOption": "[coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete')]", - "caching": "[coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly')]", - "managedDisk": { - "storageAccountType": "[parameters('osDisk').managedDisk.storageAccountType]", - "diskEncryptionSet": { - "id": "[tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')]" - } - } - } - }, - "additionalCapabilities": { - "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]" - }, - "osProfile": { - "computerName": "[parameters('computerName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]", - "customData": "[if(not(empty(parameters('customData'))), base64(parameters('customData')), null())]", - "windowsConfiguration": "[if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null())]", - "secrets": "[parameters('certificatesToBeInstalled')]", - "allowExtensionOperations": "[parameters('allowExtensionOperations')]" - }, - "networkProfile": { - "copy": [ - { - "name": "networkInterfaces", - "count": "[length(parameters('nicConfigurations'))]", - "input": { - "properties": { - "deleteOption": "[if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].deleteOption, 'Delete')]", - "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" - }, - "id": "[resourceId('Microsoft.Network/networkInterfaces', if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].name, format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].nicSuffix)))]" - } - } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", - "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" - } - }, - "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", - "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", - "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", - "priority": "[parameters('priority')]", - "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", - "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", - "host": "[if(not(empty(parameters('dedicatedHostId'))), createObject('id', parameters('dedicatedHostId')), null())]", - "licenseType": "[if(not(empty(parameters('licenseType'))), parameters('licenseType'), null())]" - }, - "dependsOn": [ - "vm_nic" - ] - }, - "vm_configurationProfileAssignment": { - "condition": "[not(empty(parameters('configurationProfile')))]", - "type": "Microsoft.Automanage/configurationProfileAssignments", - "apiVersion": "2022-05-04", - "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", - "name": "default", - "properties": { - "configurationProfile": "[parameters('configurationProfile')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_nic": { - "copy": { - "name": "vm_nic", - "count": "[length(parameters('nicConfigurations'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "networkInterfaceName": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'name'), createObject('value', parameters('nicConfigurations')[copyIndex()].name), createObject('value', format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex()].nicSuffix)))]", - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableIPForwarding": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableIPForwarding), createObject('value', false()))]", - "enableAcceleratedNetworking": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableAcceleratedNetworking), createObject('value', true()))]", - "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(parameters('nicConfigurations')[copyIndex()].dnsServers)), createObject('value', parameters('nicConfigurations')[copyIndex()].dnsServers), createObject('value', createArray())), createObject('value', createArray()))]", - "networkSecurityGroupResourceId": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('nicConfigurations')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", - "ipConfigurations": { - "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" - }, - "roleAssignments": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4081873631846149092" - } - }, - "definitions": { - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "networkInterfaceName": { - "type": "string" - }, - "virtualMachineName": { - "type": "string" - }, - "ipConfigurations": { - "type": "array" - }, - "location": { - "type": "string", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false - }, - "dnsServers": { - "type": "array", - "defaultValue": [] - }, - "enableTelemetry": { - "type": "bool", - "metadata": { - "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the Network Interface." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "resources": { - "networkInterface_publicIPAddresses": { - "copy": { - "name": "networkInterface_publicIPAddresses", - "count": "[length(parameters('ipConfigurations'))]" - }, - "condition": "[contains(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIpNameSuffix)]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "idleTimeoutInMinutes": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'idleTimeoutInMinutes')]" - }, - "ddosSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'ddosSettings')]" - }, - "dnsSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'dnsSettings')]" - }, - "publicIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressVersion'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAddressVersion), createObject('value', 'IPv4'))]", - "publicIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAllocationMethod'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAllocationMethod), createObject('value', 'Static'))]", - "publicIpPrefixResourceId": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPPrefixResourceId'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPPrefixResourceId), createObject('value', ''))]", - "roleAssignments": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'roleAssignments'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.roleAssignments), createObject('value', createArray()))]", - "skuName": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuName'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuName), createObject('value', 'Standard'))]", - "skuTier": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuTier'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuTier), createObject('value', 'Regional'))]", - "tags": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "zones": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.zones), createObject('value', createArray(1, 2, 3)))]", - "enableTelemetry": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "4718335757080871925" - }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "", - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "metadata": { - "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "metadata": { - "description": "Required. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - } - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "defaultValue": "Static", - "allowedValues": [ - "Dynamic", - "Static" - ], - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "zones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } - }, - "publicIPAddressVersion": { - "type": "string", - "defaultValue": "IPv4", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "metadata": { - "description": "Optional. IP address version." - } - }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Basic", - "Standard" - ], - "metadata": { - "description": "Optional. Name of a public IP address SKU." - } - }, - "skuTier": { - "type": "string", - "defaultValue": "Regional", - "allowedValues": [ - "Global", - "Regional" - ], - "metadata": { - "description": "Optional. Tier of a public IP address SKU." - } - }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "defaultValue": 4, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2023-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" - }, - "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", - "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": null - } - }, - "publicIpAddress_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_roleAssignments": { - "copy": { - "name": "publicIpAddress_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_diagnosticSettings": { - "copy": { - "name": "publicIpAddress_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the public IP address was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the public IP address." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the public IP address." - }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "ipAddress": { - "type": "string", - "metadata": { - "description": "The public IP address of the public IP address resource." - }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-NetworkInterface', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('networkInterfaceName')]" - }, - "ipConfigurations": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('ipConfigurations'))]", - "input": "[createObject('name', if(not(empty(parameters('ipConfigurations')[copyIndex('value')].name)), parameters('ipConfigurations')[copyIndex('value')].name, null()), 'primary', equals(copyIndex('value'), 0), 'privateIPAllocationMethod', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod, null()), null()), 'privateIPAddress', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('value')].privateIPAddress, null()), null()), 'publicIPAddressResourceId', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), resourceId('Microsoft.Network/publicIPAddresses', format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.publicIpNameSuffix)), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerBackendAddressPools, null()), 'applicationSecurityGroups', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('value')].applicationSecurityGroups, null()), 'applicationGatewayBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].applicationGatewayBackendAddressPools, null()), 'gatewayLoadBalancer', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('value')].gatewayLoadBalancer, null()), 'loadBalancerInboundNatRules', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerInboundNatRules, null()), 'privateIPAddressVersion', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('value')].privateIPAddressVersion, null()), 'virtualNetworkTaps', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('value')].virtualNetworkTaps, null()))]" - } - ] - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "dnsServers": "[if(not(empty(parameters('dnsServers'))), createObject('value', parameters('dnsServers')), createObject('value', createArray()))]", - "enableAcceleratedNetworking": { - "value": "[parameters('enableAcceleratedNetworking')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enableIPForwarding": { - "value": "[parameters('enableIPForwarding')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", - "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "1612343535299711142" - }, - "name": "Network Interface", - "description": "This module deploys a Network Interface.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the network interface." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If the network interface is accelerated networking enabled." - } - }, - "dnsServers": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "auxiliaryMode": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "Floating", - "MaxConnections", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "auxiliarySku": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "A1", - "A2", - "A4", - "A8", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "disableTcpStateTracking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "description": "Required. A list of IPConfigurations of the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.2.4', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "ipConfigurations", - "count": "[length(parameters('ipConfigurations'))]", - "input": { - "name": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].name, format('ipconfig0{0}', add(copyIndex('ipConfigurations'), 1)))]", - "properties": { - "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", - "privateIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod, null()), null())]", - "privateIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress, null()), null())]", - "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId, null())), createObject('id', parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId), null()), null())]", - "subnet": { - "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" - }, - "loadBalancerBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerBackendAddressPools, null())]", - "applicationSecurityGroups": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationSecurityGroups, null())]", - "applicationGatewayBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationGatewayBackendAddressPools, null())]", - "gatewayLoadBalancer": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].gatewayLoadBalancer, null())]", - "loadBalancerInboundNatRules": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerInboundNatRules, null())]", - "privateIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddressVersion, null())]", - "virtualNetworkTaps": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].virtualNetworkTaps, null())]" - } - } - } - ], - "auxiliaryMode": "[parameters('auxiliaryMode')]", - "auxiliarySku": "[parameters('auxiliarySku')]", - "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", - "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", - "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", - "enableIPForwarding": "[parameters('enableIPForwarding')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" - } - }, - "networkInterface_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_diagnosticSettings": { - "copy": { - "name": "networkInterface_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_roleAssignments": { - "copy": { - "name": "networkInterface_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "networkInterface" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed resource." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed resource." - }, - "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed resource." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkInterface', '2023-04-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "networkInterface_publicIPAddresses" - ] - } - } - } - } - }, - "vm_aadJoinExtension": { - "condition": "[parameters('extensionAadJoinConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "AADLogin" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.ActiveDirectory" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAadJoinConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.0'), createObject('value', '1.0')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAadJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAadJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": "[if(contains(parameters('extensionAadJoinConfig'), 'settings'), createObject('value', parameters('extensionAadJoinConfig').settings), createObject('value', createObject()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_domainJoinExtension": { - "condition": "[parameters('extensionDomainJoinConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "DomainJoin" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "JsonADDomainExtension" - }, - "typeHandlerVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDomainJoinConfig').typeHandlerVersion), createObject('value', '1.3'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDomainJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDomainJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": { - "value": "[parameters('extensionDomainJoinConfig').settings]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": { - "Password": "[parameters('extensionDomainJoinPassword')]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_aadJoinExtension" - ] - }, - "vm_desiredStateConfigurationExtension": { - "condition": "[parameters('extensionDSCConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "DesiredStateConfiguration" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Powershell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": "[if(contains(parameters('extensionDSCConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDSCConfig').typeHandlerVersion), createObject('value', '2.77'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDSCConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDSCConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": "[if(contains(parameters('extensionDSCConfig'), 'settings'), createObject('value', parameters('extensionDSCConfig').settings), createObject('value', createObject()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": "[if(contains(parameters('extensionDSCConfig'), 'protectedSettings'), createObject('value', parameters('extensionDSCConfig').protectedSettings), createObject('value', createObject()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_customScriptExtension": { - "condition": "[parameters('extensionCustomScriptConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "CustomScriptExtension" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionCustomScriptConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '1.10'), createObject('value', '2.1')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionCustomScriptConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionCustomScriptConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": { - "value": { - "copy": [ - { - "name": "fileUris", - "count": "[length(parameters('extensionCustomScriptConfig').fileData)]", - "input": "[if(contains(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')], 'storageAccountId'), format('{0}?{1}', parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri, listAccountSas(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].storageAccountId, '2019-04-01', variables('accountSasProperties')).accountSasToken), parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri)]" - } - ] - } - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": "[parameters('extensionCustomScriptProtectedSetting')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_desiredStateConfigurationExtension" - ] - }, - "vm_azureDiskEncryptionExtension": { - "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "AzureDiskEncryption" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.2'), createObject('value', '1.1')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "forceUpdateTag": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').forceUpdateTag), createObject('value', '1.0'))]", - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_nvidiaGpuDriverWindowsExtension": { - "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "NvidiaGpuDriverWindows" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.HpcCompute" - }, - "type": { - "value": "NvidiaGpuDriverWindows" - }, - "typeHandlerVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').typeHandlerVersion), createObject('value', '1.4'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').enableAutomaticUpgrade), createObject('value', false()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureDiskEncryptionExtension" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the VM." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the VM." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the VM was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[coalesce(tryGet(tryGet(reference('vm', '2023-09-01', 'full'), 'identity'), 'principalId'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('vm', '2023-09-01', 'full').location]" + "metadata": { + "description": "Required. The managed disk parameters." } } } - } + }, + "nullable": true } - ] - } - } - }, - { - "condition": "[and(equals(parameters('storageService'), 'ANF'), not(contains(parameters('identityServiceProvider'), 'EntraID')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-ANF-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "accountName": { - "value": "[variables('varAnfAccountName')]" - }, - "capacityPoolName": { - "value": "[variables('varAnfCapacityPoolName')]" - }, - "volumes": { - "value": "[variables('varAnfVolumes')]" - }, - "smbServerNamePrefix": { - "value": "[variables('varAnfSmbServerNamePrefix')]" - }, - "capacityPoolSize": { - "value": "[variables('varAnfCapacityPoolSize')]" - }, - "dnsServers": { - "value": "[parameters('dnsServers')]" - }, - "performance": { - "value": "[parameters('fslogixStoragePerformance')]" - }, - "createFslogixStorage": { - "value": "[parameters('createFslogixDeployment')]" - }, - "createAppAttachStorage": { - "value": "[parameters('createAppAttachDeployment')]" - }, - "storageOuPath": "[if(not(empty(parameters('storageOuPath'))), createObject('value', parameters('storageOuPath')), createObject('value', variables('varDefaultStorageOuPath')))]", - "domainJoinUserName": { - "value": "[parameters('domainJoinUserName')]" - }, - "keyVaultResourceId": { - "value": "[parameters('keyVaultResourceId')]" - }, - "identityDomainName": { - "value": "[parameters('identityDomainName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "storageObjectsRgName": { - "value": "[parameters('storageObjectsRgName')]" - }, - "subId": { - "value": "[parameters('subId')]" - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "6273873211710387488" - }, - "name": "AVD LZA storage", - "description": "This module deploys ANF account, capacity pool and volumes", - "owner": "Azure/avdaccelerator" }, "parameters": { - "subId": { + "name": { "type": "string", "metadata": { - "description": "Workload subscription ID" + "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." } }, - "storageObjectsRgName": { + "computerName": { "type": "string", + "defaultValue": "[parameters('name')]", "metadata": { - "description": "Resource Group Name where to deploy Azure NetApp Files." + "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." } }, - "accountName": { + "vmSize": { "type": "string", "metadata": { - "description": "ANF account name." + "description": "Required. Specifies the size for the VMs." + } + }, + "encryptionAtHost": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." } }, - "capacityPoolName": { + "securityType": { "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the SecurityType of the virtual machine. It is set as TrustedLaunch to enable UefiSettings." + } + }, + "secureBootEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Capacity pool volume name." + "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." } }, - "createFslogixStorage": { + "vTpmEnabled": { "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." + } + }, + "imageReference": { + "type": "object", + "metadata": { + "description": "Required. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image." + } + }, + "plan": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." + } + }, + "osDisk": { + "$ref": "#/definitions/osDiskType", + "metadata": { + "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." + } + }, + "dataDisks": { + "$ref": "#/definitions/dataDisksType", "metadata": { - "description": "Capacity pool volume name." + "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." } }, - "createAppAttachStorage": { + "ultraSSDEnabled": { "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." + } + }, + "adminUsername": { + "type": "securestring", + "metadata": { + "description": "Required. Administrator username." + } + }, + "adminPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. When specifying a Windows Virtual Machine, this value should be passed." + } + }, + "customData": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Capacity pool volume name." + "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." } }, - "volumes": { + "certificatesToBeInstalled": { "type": "array", + "defaultValue": [], "metadata": { - "description": "ANF volumes." + "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." } }, - "smbServerNamePrefix": { + "priority": { "type": "string", + "defaultValue": "Regular", + "allowedValues": [ + "Regular", + "Low", + "Spot" + ], "metadata": { - "description": "ANF SMB prefix." + "description": "Optional. Specifies the priority for the virtual machine." } }, - "dnsServers": { + "enableEvictionPolicy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy." + } + }, + "maxPriceForLowPriorityVm": { "type": "string", + "defaultValue": "", "metadata": { - "description": "DNS servers IPs." + "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." } }, - "location": { + "dedicatedHostId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Location where to deploy resources." + "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." } }, - "identityDomainName": { + "licenseType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "RHEL_BYOS", + "SLES_BYOS", + "Windows_Client", + "Windows_Server", + "" + ], + "metadata": { + "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." + } + }, + "bootDiagnostics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." + } + }, + "bootDiagnosticStorageAccountName": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Identity domain name." + "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." } }, - "storageOuPath": { + "bootDiagnosticStorageAccountUri": { "type": "string", + "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", "metadata": { - "description": "Organizational Unit (OU) storage path for domain join." + "description": "Optional. Storage account boot diagnostic base URI." } }, - "keyVaultResourceId": { + "proximityPlacementGroupResourceId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Keyvault resource ID to get credentials from." + "description": "Optional. Resource ID of a proximity placement group." } }, - "domainJoinUserName": { + "virtualMachineScaleSetResourceId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "AVD session host domain join credentials." + "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." } }, - "performance": { + "availabilitySetResourceId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "ANF performance tier." + "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." } }, - "capacityPoolSize": { + "zone": { "type": "int", - "defaultValue": 4, + "allowedValues": [ + 0, + 1, + 2, + 3 + ], "metadata": { - "description": "ANF capacity pool size in TiBs." + "description": "Required. If set to 1, 2 or 3, the availability zone for all VMs is hardcoded to that value. If zero, then availability zones is not used. Cannot be used in combination with availability set nor scale set." } }, - "tags": { + "nicConfigurations": { + "type": "array", + "metadata": { + "description": "Required. Configures NICs and PIPs." + } + }, + "allowExtensionOperations": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." + } + }, + "extensionDomainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. Required if name is specified. Password of the user specified in user parameter." + } + }, + "extensionDomainJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionAadJoinConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." + } + }, + "extensionAzureDiskEncryptionConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." + } + }, + "extensionDSCConfig": { + "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptConfig": { + "type": "object", + "defaultValue": { + "enabled": false, + "fileData": [] + }, + "metadata": { + "description": "Optional. The configuration for the [Custom Script] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionNvidiaGpuDriverWindows": { "type": "object", + "defaultValue": { + "enabled": false + }, + "metadata": { + "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." + } + }, + "extensionCustomScriptProtectedSetting": { + "type": "secureObject", "defaultValue": {}, "metadata": { - "description": "Tags to be applied to resources" + "description": "Optional. An object that contains the extension specific protected settings." } }, - "time": { + "location": { "type": "string", - "defaultValue": "[utcNow()]", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to generate a registration token." + } + }, + "sasTokenValidityLength": { + "type": "string", + "defaultValue": "PT8H", + "metadata": { + "description": "Optional. SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. The chosen OS type." + } + }, + "provisionVMAgent": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." + } + }, + "enableAutomaticUpdates": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." + } + }, + "patchMode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "AutomaticByPlatform", + "AutomaticByOS", + "Manual", + "ImageDefault", + "" + ], + "metadata": { + "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." + } + }, + "bypassPlatformSafetyChecksOnUserSchedule": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enables customer to schedule patching without accidental upgrades." + } + }, + "rebootSetting": { + "type": "string", + "defaultValue": "IfRequired", + "allowedValues": [ + "Always", + "IfRequired", + "Never", + "Unknown" + ], + "metadata": { + "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." + } + }, + "patchAssessmentMode": { + "type": "string", + "defaultValue": "ImageDefault", + "allowedValues": [ + "AutomaticByPlatform", + "ImageDefault" + ], + "metadata": { + "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." + } + }, + "timeZone": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." + } + }, + "additionalUnattendContent": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." + } + }, + "winRM": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object." + } + }, + "configurationProfile": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." } } }, "variables": { - "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", - "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", - "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]" + "windowsConfiguration": { + "provisionVMAgent": "[parameters('provisionVMAgent')]", + "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", + "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting'))), null())]", + "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", + "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), parameters('additionalUnattendContent'))]", + "winRM": "[if(not(empty(parameters('winRM'))), createObject('listeners', parameters('winRM')), null())]" + }, + "accountSasProperties": { + "signedServices": "b", + "signedPermission": "r", + "signedExpiry": "[dateTimeAdd(parameters('baseTime'), parameters('sasTokenValidityLength'))]", + "signedResourceTypes": "o", + "signedProtocol": "https" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" }, - "resources": [ - { + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-ANF-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subId'))]", - "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('accountName')]" - }, - "adName": { - "value": "[parameters('accountName')]" - }, - "domainName": { - "value": "[parameters('identityDomainName')]" - }, - "domainJoinUser": { - "value": "[parameters('domainJoinUserName')]" - }, - "domainJoinPassword": { - "reference": { - "keyVault": { - "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))]" - }, - "secretName": "domainJoinUserPassword" - } - }, - "domainJoinOU": { - "value": "[format('CN={0}', parameters('storageOuPath'))]" - }, - "dnsServers": { - "value": "[parameters('dnsServers')]" - }, - "smbServerNamePrefix": { - "value": "[parameters('smbServerNamePrefix')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "capacityPools": { - "value": [ - { - "name": "[parameters('capacityPoolName')]", - "serviceLevel": "[parameters('performance')]", - "size": "[mul(parameters('capacityPoolSize'), 1073741824)]", - "volumes": "[parameters('volumes')]" - } - ] - }, - "tags": { - "value": "[parameters('tags')]" + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } } + } + } + }, + "vm": { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "zones": "[if(not(equals(parameters('zone'), 0)), array(string(parameters('zone'))), null())]", + "plan": "[if(not(empty(parameters('plan'))), parameters('plan'), null())]", + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "943345456492784680" - }, - "name": "Azure NetApp Files", - "description": "This module deploys an Azure NetApp File." - }, - "definitions": { - "backupVaultType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backup vault." - } - }, - "backups": { - "type": "array", - "items": { - "$ref": "#/definitions/backupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of backups to create." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the backup vault." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a backup vault." - } - }, - "capacityPoolType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the capacity pool." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the pool volume." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags for the capcity pool." - } - }, - "serviceLevel": { - "type": "string", - "allowedValues": [ - "Premium", - "Standard", - "StandardZRS", - "Ultra" - ], - "nullable": true, - "metadata": { - "description": "Optional. The pool service level." - } - }, - "size": { - "type": "int", - "metadata": { - "description": "Required. Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104)." - } - }, - "qosType": { - "type": "string", - "allowedValues": [ - "Auto", - "Manual" - ], - "nullable": true, - "metadata": { - "description": "Optional. The qos type of the pool." - } - }, - "volumes": { - "type": "array", - "items": { - "$ref": "#/definitions/volumeType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of volumes to create in the capacity pool." - } - }, - "coolAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "encryptionType": { - "type": "string", - "allowedValues": [ - "Double", - "Single" - ], - "nullable": true, - "metadata": { - "description": "Optional. Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a capacity pool." - } - }, - "snapshotPolicyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the snapshot policy." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the snapshot policy." - } - }, - "dailySchedule": { - "$ref": "#/definitions/dailyScheduleType", - "nullable": true, - "metadata": { - "description": "Optional. Daily schedule for the snapshot policy." - } - }, - "hourlySchedule": { - "$ref": "#/definitions/hourlyScheduleType", - "nullable": true, - "metadata": { - "description": "Optional. Hourly schedule for the snapshot policy." - } - }, - "monthlySchedule": { - "$ref": "#/definitions/monthlyScheduleType", - "nullable": true, - "metadata": { - "description": "Optional. Monthly schedule for the snapshot policy." - } - }, - "weeklySchedule": { - "$ref": "#/definitions/weeklyScheduleType", - "nullable": true, - "metadata": { - "description": "Optional. Weekly schedule for the snapshot policy." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a snapshot policy." - } - }, - "backupPolicyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backup policy." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location of the backup policy." - } - }, - "dailyBackupsToKeep": { - "type": "int", - "nullable": true, - "minValue": 2, - "maxValue": 1019, - "metadata": { - "description": "Optional. The daily backups to keep." - } - }, - "monthlyBackupsToKeep": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The monthly backups to keep." - } - }, - "weeklyBackupsToKeep": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The weekly backups to keep." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether the backup policy is enabled." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a backup policy." - } - }, - "_1.backupType": { - "type": "object", - "properties": { - "backupPolicyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the backup policy to link." - } - }, - "policyEnforced": { - "type": "bool", - "metadata": { - "description": "Required. Enable to enforce the policy." - } - }, - "backupVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Backup Vault." - } - } - }, - "metadata": { - "description": "The type for the backup properties.", - "__bicep_imported_from!": { - "sourceTemplate": "capacity-pool/volume/main.bicep" - } - } - }, - "_1.dataProtectionType": { - "type": "object", - "properties": { - "replication": { - "$ref": "#/definitions/_1.replicationType", - "nullable": true, - "metadata": { - "description": "Optional. Replication properties." - } - }, - "backup": { - "$ref": "#/definitions/_1.backupType", - "nullable": true, - "metadata": { - "description": "Optional. Backup properties." - } - }, - "snapshot": { - "$ref": "#/definitions/_1.snapshotType", - "nullable": true, - "metadata": { - "description": "Optional. Snapshot properties." - } - } - }, - "metadata": { - "description": "The type for the data protection properties.", - "__bicep_imported_from!": { - "sourceTemplate": "capacity-pool/volume/main.bicep" - } - } - }, - "_1.exportPolicyType": { - "type": "object", - "properties": { - "rules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ruleIndex": { - "type": "int", - "metadata": { - "description": "Required. Order index." - } - }, - "allowedClients": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." - } - }, - "chownMode": { - "type": "string", - "allowedValues": [ - "Restricted", - "Unrestricted" - ], - "nullable": true, - "metadata": { - "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." - } - }, - "cifs": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Allows CIFS protocol." - } - }, - "hasRootAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Has root access to volume." - } - }, - "kerberos5ReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5 Read only access." - } - }, - "kerberos5ReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5 Read and write access." - } - }, - "kerberos5iReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5i Read only access." - } - }, - "kerberos5iReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5i Read and write access." - } - }, - "kerberos5pReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5p Read only access." - } - }, - "kerberos5pReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5p Read and write access." - } - }, - "nfsv3": { - "type": "bool", - "metadata": { - "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." - } - }, - "nfsv41": { - "type": "bool", - "metadata": { - "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." - } - }, - "unixReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Read only access." - } - }, - "unixReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Read and write access." - } - } - } - }, - "metadata": { - "description": "Required. The Export policy rules." - } - } - }, - "metadata": { - "description": "The type for export policy rules.", - "__bicep_imported_from!": { - "sourceTemplate": "capacity-pool/volume/main.bicep" - } - } - }, - "_1.replicationType": { - "type": "object", - "properties": { - "endpointType": { - "type": "string", - "allowedValues": [ - "dst", - "src" - ], - "metadata": { - "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." - } - }, - "remoteVolumeRegion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." - } - }, - "remoteVolumeResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." - } - }, - "replicationSchedule": { - "type": "string", - "allowedValues": [ - "_10minutely", - "daily", - "hourly" - ], - "metadata": { - "description": "Required. The replication schedule for the volume." - } - }, - "remotePath": { - "type": "object", - "properties": { - "externalHostName": { - "type": "string", - "metadata": { - "description": "Required. The Path to a ONTAP Host." - } - }, - "serverName": { - "type": "string", - "metadata": { - "description": "Required. The name of a server on the ONTAP Host." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of a volume on the server." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." - } - } - }, - "metadata": { - "description": "The type for the replication properties.", - "__bicep_imported_from!": { - "sourceTemplate": "capacity-pool/volume/main.bicep" - } - } - }, - "_1.snapshotType": { - "type": "object", - "properties": { - "snapshotPolicyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the snapshot policy to link." - } - } - }, - "metadata": { - "description": "The type for the snapshot properties.", - "__bicep_imported_from!": { - "sourceTemplate": "capacity-pool/volume/main.bicep" - } - } - }, - "backupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "label": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Label for backup." - } - }, - "snapshotName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of the volume to backup." - } - }, - "capacityPoolName": { - "type": "string", - "metadata": { - "description": "Required. The name of the capacity pool containing the volume." - } - } - }, - "metadata": { - "description": "The type for a backup.", - "__bicep_imported_from!": { - "sourceTemplate": "backup-vault/main.bicep" - } - } - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + "securityProfile": { + "encryptionAtHost": "[if(parameters('encryptionAtHost'), parameters('encryptionAtHost'), null())]", + "securityType": "[parameters('securityType')]", + "uefiSettings": "[if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null())]" + }, + "storageProfile": { + "copy": [ + { + "name": "dataDisks", + "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", + "input": { + "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", + "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))]", + "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createoption'), 'Empty')]", + "deleteOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete')]", + "caching": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly')]", + "managedDisk": { + "storageAccountType": "[coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.storageAccountType]", + "diskEncryptionSet": "[coalesce(tryGet(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'managedDisk'), 'diskEncryptionSet'), null())]" } } - }, - "dailyScheduleType": { - "type": "object", - "properties": { - "hour": { - "type": "int", - "minValue": 0, - "maxValue": 23, - "metadata": { - "description": "Required. The daily snapshot hour." - } - }, - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The daily snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, - "metadata": { - "description": "Required. Daily snapshot count to keep." - } - }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." - } - } - }, - "metadata": { - "description": "The type for a daily schedule for the snapshot policy.", - "__bicep_imported_from!": { - "sourceTemplate": "snapshot-policies/main.bicep" - } + } + ], + "imageReference": "[parameters('imageReference')]", + "osDisk": { + "name": "[coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name')))]", + "createOption": "[coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage')]", + "deleteOption": "[coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete')]", + "caching": "[coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly')]", + "managedDisk": { + "storageAccountType": "[parameters('osDisk').managedDisk.storageAccountType]", + "diskEncryptionSet": { + "id": "[tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')]" } - }, - "hourlyScheduleType": { - "type": "object", - "properties": { - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The hourly snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, - "metadata": { - "description": "Required. Hourly snapshot count to keep." - } + } + } + }, + "additionalCapabilities": { + "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]" + }, + "osProfile": { + "computerName": "[parameters('computerName')]", + "adminUsername": "[parameters('adminUsername')]", + "adminPassword": "[parameters('adminPassword')]", + "customData": "[if(not(empty(parameters('customData'))), base64(parameters('customData')), null())]", + "windowsConfiguration": "[if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null())]", + "secrets": "[parameters('certificatesToBeInstalled')]", + "allowExtensionOperations": "[parameters('allowExtensionOperations')]" + }, + "networkProfile": { + "copy": [ + { + "name": "networkInterfaces", + "count": "[length(parameters('nicConfigurations'))]", + "input": { + "properties": { + "deleteOption": "[if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].deleteOption, 'Delete')]", + "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." - } - } - }, - "metadata": { - "description": "The type for an hourly schedule for the snapshot policy.", - "__bicep_imported_from!": { - "sourceTemplate": "snapshot-policies/main.bicep" - } + "id": "[resourceId('Microsoft.Network/networkInterfaces', if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].name, format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].nicSuffix)))]" } - }, + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", + "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" + } + }, + "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", + "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", + "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", + "priority": "[parameters('priority')]", + "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", + "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", + "host": "[if(not(empty(parameters('dedicatedHostId'))), createObject('id', parameters('dedicatedHostId')), null())]", + "licenseType": "[if(not(empty(parameters('licenseType'))), parameters('licenseType'), null())]" + }, + "dependsOn": [ + "vm_nic" + ] + }, + "vm_configurationProfileAssignment": { + "condition": "[not(empty(parameters('configurationProfile')))]", + "type": "Microsoft.Automanage/configurationProfileAssignments", + "apiVersion": "2022-05-04", + "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", + "name": "default", + "properties": { + "configurationProfile": "[parameters('configurationProfile')]" + }, + "dependsOn": [ + "vm" + ] + }, + "vm_nic": { + "copy": { + "name": "vm_nic", + "count": "[length(parameters('nicConfigurations'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "networkInterfaceName": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'name'), createObject('value', parameters('nicConfigurations')[copyIndex()].name), createObject('value', format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex()].nicSuffix)))]", + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableIPForwarding": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableIPForwarding), createObject('value', false()))]", + "enableAcceleratedNetworking": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableAcceleratedNetworking), createObject('value', true()))]", + "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(parameters('nicConfigurations')[copyIndex()].dnsServers)), createObject('value', parameters('nicConfigurations')[copyIndex()].dnsServers), createObject('value', createArray())), createObject('value', createArray()))]", + "networkSecurityGroupResourceId": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('nicConfigurations')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", + "ipConfigurations": { + "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4081873631846149092" + } + }, + "definitions": { "lockType": { "type": "object", "properties": { @@ -28918,904 +24068,311 @@ } } }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" - } - } + "nullable": true }, - "managedIdentityOnlyUserAssignedType": { - "type": "object", - "properties": { - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if only user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" - } - } - }, - "monthlyScheduleType": { - "type": "object", - "properties": { - "daysOfMonth": { - "type": "string", - "metadata": { - "description": "Required. Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'." - } - }, - "hour": { - "type": "int", - "minValue": 0, - "maxValue": 23, - "metadata": { - "description": "Required. The monthly snapshot hour." - } - }, - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The monthly snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, - "metadata": { - "description": "Required. Monthly snapshot count to keep." - } - }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } } }, - "metadata": { - "description": "The type for a monthly schedule for the snapshot policy.", - "__bicep_imported_from!": { - "sourceTemplate": "snapshot-policies/main.bicep" - } - } + "nullable": true }, "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" - } - } - }, - "volumeType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the pool volume." - } - }, - "coolAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." - } - }, - "coolnessPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." - } - }, - "coolAccessRetrievalPolicy": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." - } - }, - "encryptionKeySource": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source of the encryption key." - } - }, - "keyVaultPrivateEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the key vault private endpoint." - } - }, - "dataProtection": { - "$ref": "#/definitions/_1.dataProtectionType", - "nullable": true, - "metadata": { - "description": "Optional. DataProtection type volumes include an object containing details of the replication." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the pool volume." - } - }, - "zones": { - "type": "array", - "items": { - "type": "int" + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } }, - "nullable": true, - "metadata": { - "description": "Optional. Zone where the volume will be placed." - } - }, - "serviceLevel": { - "type": "string", - "allowedValues": [ - "Premium", - "Standard", - "StandardZRS", - "Ultra" - ], - "nullable": true, - "metadata": { - "description": "Optional. The pool service level. Must match the one of the parent capacity pool." - } - }, - "networkFeatures": { - "type": "string", - "allowedValues": [ - "Basic", - "Basic_Standard", - "Standard", - "Standard_Basic" - ], - "nullable": true, - "metadata": { - "description": "Optional. Network feature for the volume." - } - }, - "creationToken": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." - } - }, - "usageThreshold": { - "type": "int", - "metadata": { - "description": "Required. Maximum storage quota allowed for a file system in bytes." - } - }, - "protocolTypes": { - "type": "array", - "items": { - "type": "string" + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } }, - "nullable": true, - "metadata": { - "description": "Optional. Set of protocol types." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." - } - }, - "exportPolicy": { - "$ref": "#/definitions/_1.exportPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Export policy rules." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "smbEncryption": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." - } - }, - "smbContinuouslyAvailable": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." - } - }, - "smbNonBrowsable": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." - } - }, - "kerberosEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Define if a volume is KerberosEnabled." - } - }, - "volumeType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The type of the volume. DataProtection volumes are used for replication." - } - } - }, - "metadata": { - "description": "The type for a volume in the capacity pool.", - "__bicep_imported_from!": { - "sourceTemplate": "capacity-pool/main.bicep" - } - } - }, - "weeklyScheduleType": { - "type": "object", - "properties": { - "day": { - "type": "string", - "allowedValues": [ - "Friday", - "Monday", - "Saturday", - "Sunday", - "Thursday", - "Tuesday", - "Wednesday" - ], - "metadata": { - "description": "Required. The weekly snapshot day." - } - }, - "hour": { - "type": "int", - "minValue": 0, - "maxValue": 23, - "metadata": { - "description": "Required. The weekly snapshot hour." - } - }, - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The weekly snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, - "metadata": { - "description": "Required. Weekly snapshot count to keep." - } - }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } } } }, - "metadata": { - "description": "The type for a weekly schedule for the snapshot policy.", - "__bicep_imported_from!": { - "sourceTemplate": "snapshot-policies/main.bicep" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the NetApp account." - } - }, - "adName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Name of the active directory host as part of Kerberos Realm used for Kerberos authentication." - } - }, - "aesEncryption": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable AES encryption on the SMB Server." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "domainName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Fully Qualified Active Directory DNS Domain Name (e.g. 'contoso.com')." - } + "nullable": true + } + }, + "parameters": { + "networkInterfaceName": { + "type": "string" }, - "domainJoinUser": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if domainName is specified. Username of Active Directory domain administrator, with permissions to create SMB server machine account in the AD domain." - } + "virtualMachineName": { + "type": "string" }, - "domainJoinPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if domainName is specified. Password of the user specified in domainJoinUser parameter." - } + "ipConfigurations": { + "type": "array" }, - "domainJoinOU": { + "location": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. Used only if domainName is specified. LDAP Path for the Organization Unit (OU) where SMB Server machine accounts will be created (i.e. 'OU=SecondLevel,OU=FirstLevel')." + "description": "Optional. Location for all resources." } }, - "dnsServers": { - "type": "string", - "defaultValue": "", + "tags": { + "type": "object", + "nullable": true, "metadata": { - "description": "Optional. Required if domainName is specified. Comma separated list of DNS server IP addresses (IPv4 only) required for the Active Directory (AD) domain join and SMB authentication operations to succeed." + "description": "Optional. Tags of the resource." } }, - "encryptDCConnections": { + "enableIPForwarding": { "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether encryption should be used for communication between SMB server and domain controller (DC). SMB3 only." - } - }, - "smbServerNamePrefix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if domainName is specified. NetBIOS name of the SMB server. A computer account with this prefix will be registered in the AD and used to mount volumes." - } - }, - "capacityPools": { - "type": "array", - "items": { - "$ref": "#/definitions/capacityPoolType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Capacity pools to create." - } + "defaultValue": false }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityOnlyUserAssignedType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false }, - "roleAssignments": { + "dnsServers": { "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "kdcIP": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Kerberos Key Distribution Center (KDC) as part of Kerberos Realm used for Kerberos authentication." - } - }, - "ldapOverTLS": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether to use TLS when NFS (with/without Kerberos) and SMB volumes communicate with an LDAP server. A server root CA certificate must be uploaded if enabled (serverRootCACertificate)." - } + "defaultValue": [] }, - "ldapSigning": { + "enableTelemetry": { "type": "bool", - "defaultValue": false, "metadata": { - "description": "Optional. Specifies whether or not the LDAP traffic needs to be signed." + "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." } }, - "location": { + "networkSecurityGroupResourceId": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "", "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. The network security group (NSG) to attach to the network interface." } }, "lock": { "$ref": "#/definitions/lockType", - "nullable": true, "metadata": { "description": "Optional. The lock settings of the service." } }, - "serverRootCACertificate": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. A server Root certificate is required of ldapOverTLS is enabled." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags for all resources." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "backupVault": { - "$ref": "#/definitions/backupVaultType", - "nullable": true, - "metadata": { - "description": "Optional. The netapp backup vault to create & configure." - } - }, - "snapshotPolicies": { - "type": "array", - "items": { - "$ref": "#/definitions/snapshotPolicyType" - }, - "nullable": true, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", "metadata": { - "description": "Optional. The snapshot policies to create." + "description": "Optional. The diagnostic settings of the Network Interface." } }, - "backupPolicies": { - "type": "array", - "items": { - "$ref": "#/definitions/backupPolicyType" - }, - "nullable": true, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", "metadata": { - "description": "Optional. The backup policies to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "activeDirectoryConnectionProperties": [ - { - "adName": "[if(not(empty(parameters('domainName'))), parameters('adName'), null())]", - "aesEncryption": "[if(not(empty(parameters('domainName'))), parameters('aesEncryption'), false())]", - "username": "[if(not(empty(parameters('domainName'))), parameters('domainJoinUser'), null())]", - "password": "[if(not(empty(parameters('domainName'))), parameters('domainJoinPassword'), null())]", - "domain": "[if(not(empty(parameters('domainName'))), parameters('domainName'), null())]", - "dns": "[if(not(empty(parameters('domainName'))), parameters('dnsServers'), null())]", - "encryptDCConnections": "[if(not(empty(parameters('domainName'))), parameters('encryptDCConnections'), false())]", - "kdcIP": "[if(not(empty(parameters('domainName'))), parameters('kdcIP'), null())]", - "ldapOverTLS": "[if(not(empty(parameters('domainName'))), parameters('ldapOverTLS'), false())]", - "ldapSigning": "[if(not(empty(parameters('domainName'))), parameters('ldapSigning'), false())]", - "serverRootCACertificate": "[if(not(empty(parameters('domainName'))), parameters('serverRootCACertificate'), null())]", - "smbServerName": "[if(not(empty(parameters('domainName'))), parameters('smbServerNamePrefix'), null())]", - "organizationalUnit": "[if(not(empty(parameters('domainJoinOU'))), parameters('domainJoinOU'), null())]" + "description": "Optional. Array of role assignments to create." } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None'), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.netapp-netappaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" - }, - "netAppAccount": { - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "location": "[parameters('location')]", - "properties": { - "activeDirectories": "[if(not(empty(parameters('domainName'))), variables('activeDirectoryConnectionProperties'), null())]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('identity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), createObject('userAssignedIdentity', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/')))), null()), 'keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('keyName', parameters('customerManagedKey').keyName, 'keyVaultResourceId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]), 'Microsoft.KeyVault/vaults', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))), 'keyVaultUri', reference('cMKKeyVault').vaultUri)), null())]" - }, - "dependsOn": [ - "cMKKeyVault" - ] - }, - "netAppAccount_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "netAppAccount_roleAssignments": { - "copy": { - "name": "netAppAccount_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "netAppAccount_backupPolicies": { + "networkInterface_publicIPAddresses": { "copy": { - "name": "netAppAccount_backupPolicies", - "count": "[length(coalesce(parameters('backupPolicies'), createArray()))]" + "name": "networkInterface_publicIPAddresses", + "count": "[length(parameters('ipConfigurations'))]" }, + "condition": "[contains(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-ANFAccount-backupPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "netAppAccountName": { - "value": "[parameters('name')]" - }, "name": { - "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'name')]" - }, - "dailyBackupsToKeep": { - "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'dailyBackupsToKeep')]" - }, - "monthlyBackupsToKeep": { - "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'monthlyBackupsToKeep')]" - }, - "weeklyBackupsToKeep": { - "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'weeklyBackupsToKeep')]" + "value": "[format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIpNameSuffix)]" }, - "enabled": { - "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'enabled')]" + "diagnosticSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings')]" }, "location": { - "value": "[coalesce(tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'location'), parameters('location'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "16432727764202874682" - }, - "name": "Azure NetApp Files Backup Policy", - "description": "This module deploys a Backup Policy for Azure NetApp File." - }, - "parameters": { - "netAppAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "backupPolicy", - "metadata": { - "description": "Optional. The name of the backup policy." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup policy." - } - }, - "dailyBackupsToKeep": { - "type": "int", - "defaultValue": 2, - "minValue": 2, - "maxValue": 1019, - "metadata": { - "description": "Optional. The daily backups to keep." - } - }, - "monthlyBackupsToKeep": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. The monthly backups to keep." - } - }, - "weeklyBackupsToKeep": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. The weekly backups to keep." - } - }, - "enabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether the backup policy is enabled." - } - } - }, - "resources": [ - { - "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "enabled": "[parameters('enabled')]", - "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", - "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]", - "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]" - } - } - ], - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource IDs of the backup Policy created within volume." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Backup Policy." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the Backup Policy was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "netAppAccount_snapshotPolicies": { - "copy": { - "name": "netAppAccount_snapshotPolicies", - "count": "[length(coalesce(parameters('snapshotPolicies'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-ANFAccount-snapshotPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'name')]" + "value": "[parameters('location')]" }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'location'), parameters('location'))]" + "lock": { + "value": "[parameters('lock')]" }, - "snapEnabled": { - "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'snapEnabled')]" + "idleTimeoutInMinutes": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'idleTimeoutInMinutes')]" }, - "dailySchedule": { - "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'dailySchedule')]" + "ddosSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'ddosSettings')]" }, - "hourlySchedule": { - "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'hourlySchedule')]" + "dnsSettings": { + "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'dnsSettings')]" }, - "monthlySchedule": { - "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'monthlySchedule')]" + "publicIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressVersion'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAddressVersion), createObject('value', 'IPv4'))]", + "publicIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAllocationMethod'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAllocationMethod), createObject('value', 'Static'))]", + "publicIpPrefixResourceId": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPPrefixResourceId'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPPrefixResourceId), createObject('value', ''))]", + "roleAssignments": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'roleAssignments'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.roleAssignments), createObject('value', createArray()))]", + "skuName": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuName'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuName), createObject('value', 'Standard'))]", + "skuTier": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuTier'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuTier), createObject('value', 'Regional'))]", + "tags": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" }, - "weeklySchedule": { - "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'weeklySchedule')]" + "zones": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.zones), createObject('value', createArray(1, 2, 3)))]", + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" } }, "template": { @@ -29825,663 +24382,650 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "15408772009434991440" + "version": "0.26.54.24096", + "templateHash": "4718335757080871925" }, - "name": "Azure NetApp Files Snapshot Policy", - "description": "This module deploys a Snapshot Policy for an Azure NetApp File." + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address.", + "owner": "Azure/module-maintainers" }, "definitions": { - "dailyScheduleType": { - "type": "object", - "properties": { - "hour": { - "type": "int", - "minValue": 0, - "maxValue": 23, - "metadata": { - "description": "Required. The daily snapshot hour." - } - }, - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The daily snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, - "metadata": { - "description": "Required. Daily snapshot count to keep." - } - }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } } } }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a daily schedule for the snapshot policy." - } + "nullable": true }, - "hourlyScheduleType": { + "lockType": { "type": "object", "properties": { - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The hourly snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, + "name": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. Hourly snapshot count to keep." + "description": "Optional. Specify the name of lock." } }, - "usedBytes": { - "type": "int", + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], "nullable": true, "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + "description": "Optional. Specify the type of lock." } } }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an hourly schedule for the snapshot policy." - } + "nullable": true }, - "weeklyScheduleType": { + "dnsSettingsType": { "type": "object", "properties": { - "day": { + "domainNameLabel": { "type": "string", - "allowedValues": [ - "Friday", - "Monday", - "Saturday", - "Sunday", - "Thursday", - "Tuesday", - "Wednesday" - ], "metadata": { - "description": "Required. The weekly snapshot day." - } - }, - "hour": { - "type": "int", - "minValue": 0, - "maxValue": 23, - "metadata": { - "description": "Required. The weekly snapshot hour." + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." } }, - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "", + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], "metadata": { - "description": "Required. The weekly snapshot minute." + "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." } }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, + "fqdn": { + "type": "string", + "nullable": true, "metadata": { - "description": "Required. Weekly snapshot count to keep." + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." } }, - "usedBytes": { - "type": "int", + "reverseFqdn": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." } } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a weekly schedule for the snapshot policy." } }, - "monthlyScheduleType": { + "ddosSettingsType": { "type": "object", "properties": { - "daysOfMonth": { - "type": "string", - "metadata": { - "description": "Required. Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'." - } - }, - "hour": { - "type": "int", - "minValue": 0, - "maxValue": 23, - "metadata": { - "description": "Required. The monthly snapshot hour." - } - }, - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, "metadata": { - "description": "Required. The monthly snapshot minute." + "description": "Required. The DDoS protection plan associated with the public IP address." } }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], "metadata": { - "description": "Required. Monthly snapshot count to keep." + "description": "Required. The DDoS protection policy customizations." } - }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." + } + } + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } } }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a monthly schedule for the snapshot policy." - } + "nullable": true } }, "parameters": { - "netAppAccountName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + "description": "Required. The name of the Public IP Address." } }, - "name": { + "publicIpPrefixResourceId": { "type": "string", - "defaultValue": "snapshotPolicy", + "nullable": true, "metadata": { - "description": "Optional. The name of the snapshot policy." + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." } }, - "location": { + "publicIPAllocationMethod": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], "metadata": { - "description": "Optional. The location of the snapshot policy." + "description": "Optional. The public IP address allocation method." } }, - "hourlySchedule": { - "$ref": "#/definitions/hourlyScheduleType", - "nullable": true, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], "metadata": { - "description": "Optional. Schedule for hourly snapshots." + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." } }, - "dailySchedule": { - "$ref": "#/definitions/dailyScheduleType", - "nullable": true, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], "metadata": { - "description": "Optional. Schedule for daily snapshots." + "description": "Optional. IP address version." } }, - "monthlySchedule": { - "$ref": "#/definitions/monthlyScheduleType", + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", "nullable": true, "metadata": { - "description": "Optional. Schedule for monthly snapshots." + "description": "Optional. The DNS settings of the public IP address." } }, - "weeklySchedule": { - "$ref": "#/definitions/weeklyScheduleType", - "nullable": true, + "lock": { + "$ref": "#/definitions/lockType", "metadata": { - "description": "Optional. Schedule for weekly snapshots." + "description": "Optional. The lock settings of the service." } }, - "snapEnabled": { - "type": "bool", - "defaultValue": false, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], "metadata": { - "description": "Optional. Indicates whether the snapshot policy is enabled." - } - } - }, - "resources": { - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "snapshotPolicies": { - "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "enabled": "[parameters('snapEnabled')]", - "dailySchedule": "[parameters('dailySchedule')]", - "hourlySchedule": "[parameters('hourlySchedule')]", - "monthlySchedule": "[parameters('monthlySchedule')]", - "weeklySchedule": "[parameters('weeklySchedule')]" + "description": "Optional. Name of a public IP address SKU." } - } - }, - "outputs": { - "resourceId": { + }, + "skuTier": { "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], "metadata": { - "description": "The resource IDs of the snapshot Policy created within volume." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), parameters('name'))]" + "description": "Optional. Tier of a public IP address SKU." + } }, - "name": { - "type": "string", + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, "metadata": { - "description": "The name of the Backup Policy." - }, - "value": "[parameters('name')]" + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } }, - "resourceGroupName": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "The name of the Resource Group the Snapshot was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "netAppAccount_backupVault": { - "condition": "[not(empty(parameters('backupVault')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-ANFAccount-BackupVault', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(parameters('backupVault'), 'name')]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('backupVault'), 'location'), parameters('location'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12673365749567452459" + "description": "Optional. Location for all resources." + } }, - "name": "Azure NetApp Files Volume Backup Vault", - "description": "This module deploys a NetApp Files Backup Vault." - }, - "definitions": { - "backupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "label": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Label for backup." - } - }, - "snapshotName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of the volume to backup." - } - }, - "capacityPoolName": { - "type": "string", - "metadata": { - "description": "Required. The name of the capacity pool containing the volume." - } - } - }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", "metadata": { - "__bicep_export!": true, - "description": "The type for a backup." + "description": "Optional. Array of role assignments to create." } - } - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "vault", + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The name of the backup vault." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, "metadata": { - "description": "Optional. Location of the backup vault." + "description": "Optional. The idle timeout of the public IP address." } }, - "netAppAccountName": { - "type": "string", + "tags": { + "type": "object", + "nullable": true, "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + "description": "Optional. Tags of the resource." } }, - "backups": { - "type": "array", - "items": { - "$ref": "#/definitions/backupType" - }, - "nullable": true, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", "metadata": { - "description": "Optional. The list of backups to create." + "description": "Optional. The diagnostic settings of the service." } } }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, "resources": { - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "backupVault": { - "type": "Microsoft.NetApp/netAppAccounts/backupVaults", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": {} - }, - "backupVault_backups": { - "copy": { - "name": "backupVault_backups", - "count": "[length(coalesce(parameters('backups'), createArray()))]" - }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-ANF-Backup-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('netAppAccountName')]" - }, - "backupVaultName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'name')]" - }, - "label": { - "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'label')]" - }, - "snapshotName": { - "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'snapshotName')]" - }, - "volumeName": { - "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].volumeName]" - }, - "capacityPoolName": { - "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].capacityPoolName]" - } - }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "2218257802133394577" - }, - "name": "Azure NetApp Files Volume Backup", - "description": "This module deploys a backup of a NetApp Files Volume." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "backup", - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "backupVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent backup vault. Required if the template is used in a standalone deployment." - } - }, - "netAppAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." - } - }, - "label": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Label for backup." - } - }, - "snapshotName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of the volume to backup." - } - }, - "capacityPoolName": { - "type": "string", - "metadata": { - "description": "Required. The name of the capacity pool containing the volume." - } + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } - }, - "resources": { - "netAppAccount::remoteCapacityPool::volume": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" - }, - "netAppAccount::backupVault": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/backupVaults", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupVaultName'))]" - }, - "netAppAccount::remoteCapacityPool": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" - }, - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "backup": { - "type": "Microsoft.NetApp/netAppAccounts/backupVaults/backups", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]", - "properties": { - "label": "[parameters('label')]", - "snapshotName": "[parameters('snapshotName')]", - "volumeResourceId": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" - } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": null + } + }, + "publicIpAddress_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null } }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the backup." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The Resource ID of the backup." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults/backups', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the backup was created in." - }, - "value": "[resourceGroup().name]" + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" } } - } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "backupVault" + "publicIpAddress" ] } }, "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the backup vault." + "description": "The name of the public IP address." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The Resource ID of the backup vault." + "description": "The resource ID of the public IP address." }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" }, - "resourceGroupName": { + "ipAddress": { "type": "string", "metadata": { - "description": "The name of the Resource Group the backup vault was created in." + "description": "The public IP address of the public IP address resource." }, - "value": "[resourceGroup().name]" + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('backupVault', '2024-07-01', 'full').location]" + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" } } } - }, - "dependsOn": [ - "netAppAccount" - ] + } }, - "netAppAccount_capacityPools": { - "copy": { - "name": "netAppAccount_capacityPools", - "count": "[length(coalesce(parameters('capacityPools'), createArray()))]" - }, + "networkInterface": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-ANFAccount-CapPool-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-NetworkInterface', deployment().name)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "netAppAccountName": { - "value": "[parameters('name')]" - }, "name": { - "value": "[coalesce(parameters('capacityPools'), createArray())[copyIndex()].name]" + "value": "[parameters('networkInterfaceName')]" }, - "size": { - "value": "[coalesce(parameters('capacityPools'), createArray())[copyIndex()].size]" + "ipConfigurations": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('ipConfigurations'))]", + "input": "[createObject('name', if(not(empty(parameters('ipConfigurations')[copyIndex('value')].name)), parameters('ipConfigurations')[copyIndex('value')].name, null()), 'primary', equals(copyIndex('value'), 0), 'privateIPAllocationMethod', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod, null()), null()), 'privateIPAddress', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('value')].privateIPAddress, null()), null()), 'publicIPAddressResourceId', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), resourceId('Microsoft.Network/publicIPAddresses', format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.publicIpNameSuffix)), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerBackendAddressPools, null()), 'applicationSecurityGroups', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('value')].applicationSecurityGroups, null()), 'applicationGatewayBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].applicationGatewayBackendAddressPools, null()), 'gatewayLoadBalancer', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('value')].gatewayLoadBalancer, null()), 'loadBalancerInboundNatRules', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerInboundNatRules, null()), 'privateIPAddressVersion', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('value')].privateIPAddressVersion, null()), 'virtualNetworkTaps', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('value')].virtualNetworkTaps, null()))]" + } + ] }, "location": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'location'), parameters('location'))]" + "value": "[parameters('location')]" }, - "serviceLevel": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'serviceLevel'), 'Standard')]" + "tags": { + "value": "[parameters('tags')]" }, - "qosType": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'qosType'), 'Auto')]" + "diagnosticSettings": { + "value": "[parameters('diagnosticSettings')]" }, - "volumes": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'volumes'), createArray())]" + "dnsServers": "[if(not(empty(parameters('dnsServers'))), createObject('value', parameters('dnsServers')), createObject('value', createArray()))]", + "enableAcceleratedNetworking": { + "value": "[parameters('enableAcceleratedNetworking')]" }, - "coolAccess": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'coolAccess'), false())]" + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "roleAssignments": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'roleAssignments'), createArray())]" + "enableIPForwarding": { + "value": "[parameters('enableIPForwarding')]" }, - "encryptionType": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'encryptionType'), 'Single')]" + "lock": { + "value": "[parameters('lock')]" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } + "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", + "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -30490,1495 +25034,480 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "8976617662375535030" + "version": "0.25.53.49325", + "templateHash": "1612343535299711142" }, - "name": "Azure NetApp Files Capacity Pools", - "description": "This module deploys an Azure NetApp Files Capacity Pool." + "name": "Network Interface", + "description": "This module deploys a Network Interface.", + "owner": "Azure/module-maintainers" }, "definitions": { - "volumeType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the pool volume." - } - }, - "coolAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." - } - }, - "coolnessPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." - } - }, - "coolAccessRetrievalPolicy": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." - } - }, - "encryptionKeySource": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source of the encryption key." - } - }, - "keyVaultPrivateEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the key vault private endpoint." - } - }, - "dataProtection": { - "$ref": "#/definitions/dataProtectionType", - "nullable": true, - "metadata": { - "description": "Optional. DataProtection type volumes include an object containing details of the replication." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the pool volume." - } - }, - "zones": { - "type": "array", - "items": { - "type": "int" + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } }, - "nullable": true, - "metadata": { - "description": "Optional. Zone where the volume will be placed." - } - }, - "serviceLevel": { - "type": "string", - "allowedValues": [ - "Premium", - "Standard", - "StandardZRS", - "Ultra" - ], - "nullable": true, - "metadata": { - "description": "Optional. The pool service level. Must match the one of the parent capacity pool." - } - }, - "networkFeatures": { - "type": "string", - "allowedValues": [ - "Basic", - "Basic_Standard", - "Standard", - "Standard_Basic" - ], - "nullable": true, - "metadata": { - "description": "Optional. Network feature for the volume." - } - }, - "creationToken": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." - } - }, - "usageThreshold": { - "type": "int", - "metadata": { - "description": "Required. Maximum storage quota allowed for a file system in bytes." - } - }, - "protocolTypes": { - "type": "array", - "items": { - "type": "string" + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } }, - "nullable": true, - "metadata": { - "description": "Optional. Set of protocol types." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." - } - }, - "exportPolicy": { - "$ref": "#/definitions/exportPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Export policy rules." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "smbEncryption": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." - } - }, - "smbContinuouslyAvailable": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." - } - }, - "smbNonBrowsable": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." - } - }, - "kerberosEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Define if a volume is KerberosEnabled." - } - }, - "volumeType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The type of the volume. DataProtection volumes are used for replication." + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } } } }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a volume in the capacity pool." - } + "nullable": true }, - "_1.backupType": { - "type": "object", - "properties": { - "backupPolicyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the backup policy to link." - } - }, - "policyEnforced": { - "type": "bool", - "metadata": { - "description": "Required. Enable to enforce the policy." - } - }, - "backupVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Backup Vault." + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "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\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } } } }, - "metadata": { - "description": "The type for the backup properties.", - "__bicep_imported_from!": { - "sourceTemplate": "volume/main.bicep" - } - } + "nullable": true }, - "_1.replicationType": { + "lockType": { "type": "object", "properties": { - "endpointType": { - "type": "string", - "allowedValues": [ - "dst", - "src" - ], - "metadata": { - "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." - } - }, - "remoteVolumeRegion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." - } - }, - "remoteVolumeResourceId": { + "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." + "description": "Optional. Specify the name of lock." } }, - "replicationSchedule": { + "kind": { "type": "string", "allowedValues": [ - "_10minutely", - "daily", - "hourly" + "CanNotDelete", + "None", + "ReadOnly" ], - "metadata": { - "description": "Required. The replication schedule for the volume." - } - }, - "remotePath": { - "type": "object", - "properties": { - "externalHostName": { - "type": "string", - "metadata": { - "description": "Required. The Path to a ONTAP Host." - } - }, - "serverName": { - "type": "string", - "metadata": { - "description": "Required. The name of a server on the ONTAP Host." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of a volume on the server." - } - } - }, "nullable": true, "metadata": { - "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." - } - } - }, - "metadata": { - "description": "The type for the replication properties.", - "__bicep_imported_from!": { - "sourceTemplate": "volume/main.bicep" - } - } - }, - "_1.snapshotType": { - "type": "object", - "properties": { - "snapshotPolicyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the snapshot policy to link." + "description": "Optional. Specify the type of lock." } } }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", "metadata": { - "description": "The type for the snapshot properties.", - "__bicep_imported_from!": { - "sourceTemplate": "volume/main.bicep" - } + "description": "Required. The name of the network interface." } }, - "dataProtectionType": { - "type": "object", - "properties": { - "replication": { - "$ref": "#/definitions/_1.replicationType", - "nullable": true, - "metadata": { - "description": "Optional. Replication properties." - } - }, - "backup": { - "$ref": "#/definitions/_1.backupType", - "nullable": true, - "metadata": { - "description": "Optional. Backup properties." - } - }, - "snapshot": { - "$ref": "#/definitions/_1.snapshotType", - "nullable": true, - "metadata": { - "description": "Optional. Snapshot properties." - } - } - }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "The type for the data protection properties.", - "__bicep_imported_from!": { - "sourceTemplate": "volume/main.bicep" - } + "description": "Optional. Location for all resources." } }, - "exportPolicyType": { + "tags": { "type": "object", - "properties": { - "rules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ruleIndex": { - "type": "int", - "metadata": { - "description": "Required. Order index." - } - }, - "allowedClients": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." - } - }, - "chownMode": { - "type": "string", - "allowedValues": [ - "Restricted", - "Unrestricted" - ], - "nullable": true, - "metadata": { - "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." - } - }, - "cifs": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Allows CIFS protocol." - } - }, - "hasRootAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Has root access to volume." - } - }, - "kerberos5ReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5 Read only access." - } - }, - "kerberos5ReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5 Read and write access." - } - }, - "kerberos5iReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5i Read only access." - } - }, - "kerberos5iReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5i Read and write access." - } - }, - "kerberos5pReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5p Read only access." - } - }, - "kerberos5pReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5p Read and write access." - } - }, - "nfsv3": { - "type": "bool", - "metadata": { - "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." - } - }, - "nfsv41": { - "type": "bool", - "metadata": { - "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." - } - }, - "unixReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Read only access." - } - }, - "unixReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Read and write access." - } - } - } - }, - "metadata": { - "description": "Required. The Export policy rules." - } - } - }, + "nullable": true, "metadata": { - "description": "The type for export policy rules.", - "__bicep_imported_from!": { - "sourceTemplate": "volume/main.bicep" - } + "description": "Optional. Resource tags." } }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" - } + "description": "Optional. Enable/Disable usage telemetry for module." } - } - }, - "parameters": { - "netAppAccountName": { - "type": "string", + }, + "enableIPForwarding": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." } }, - "name": { - "type": "string", + "enableAcceleratedNetworking": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. The name of the capacity pool." + "description": "Optional. If the network interface is accelerated networking enabled." } }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "dnsServers": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. Location of the pool volume." + "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." } }, - "tags": { - "type": "object", - "nullable": true, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Tags for all resources." + "description": "Optional. The network security group (NSG) to attach to the network interface." } }, - "serviceLevel": { + "auxiliaryMode": { "type": "string", - "defaultValue": "Standard", + "defaultValue": "None", "allowedValues": [ - "Premium", - "Standard", - "StandardZRS", - "Ultra" + "Floating", + "MaxConnections", + "None" ], "metadata": { - "description": "Optional. The pool service level." - } - }, - "size": { - "type": "int", - "metadata": { - "description": "Required. Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104)." + "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." } }, - "qosType": { + "auxiliarySku": { "type": "string", - "defaultValue": "Auto", + "defaultValue": "None", "allowedValues": [ - "Auto", - "Manual" + "A1", + "A2", + "A4", + "A8", + "None" ], "metadata": { - "description": "Optional. The qos type of the pool." + "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." + } + }, + "disableTcpStateTracking": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." } }, - "volumes": { + "ipConfigurations": { "type": "array", - "items": { - "$ref": "#/definitions/volumeType" - }, - "nullable": true, "metadata": { - "description": "Optional. List of volumes to create in the capacity pool." + "description": "Required. A list of IPConfigurations of the network interface." } }, - "coolAccess": { - "type": "bool", - "defaultValue": false, + "lock": { + "$ref": "#/definitions/lockType", "metadata": { - "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." + "description": "Optional. The lock settings of the service." } }, "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, + "$ref": "#/definitions/roleAssignmentType", "metadata": { "description": "Optional. Array of role assignments to create." } }, - "encryptionType": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Double", - "Single" - ], + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", "metadata": { - "description": "Optional. Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool." + "description": "Optional. The diagnostic settings of the service." } } }, "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } - }, - "resources": { - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "capacityPool": { - "type": "Microsoft.NetApp/netAppAccounts/capacityPools", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "serviceLevel": "[parameters('serviceLevel')]", - "size": "[parameters('size')]", - "qosType": "[parameters('qosType')]", - "coolAccess": "[parameters('coolAccess')]", - "encryptionType": "[parameters('encryptionType')]" - } - }, - "capacityPool_roleAssignments": { - "copy": { - "name": "capacityPool_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}/capacityPools/{1}', parameters('netAppAccountName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts/capacityPools', parameters('netAppAccountName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "capacityPool" - ] - }, - "capacityPool_volumes": { - "copy": { - "name": "capacityPool_volumes", - "count": "[length(coalesce(parameters('volumes'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Vol-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('netAppAccountName')]" - }, - "capacityPoolName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].name]" - }, - "location": { - "value": "[parameters('location')]" - }, - "serviceLevel": { - "value": "[parameters('serviceLevel')]" - }, - "creationToken": { - "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'creationToken'), coalesce(parameters('volumes'), createArray())[copyIndex()].name)]" - }, - "usageThreshold": { - "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].usageThreshold]" - }, - "protocolTypes": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'protocolTypes')]" - }, - "subnetResourceId": { - "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].subnetResourceId]" - }, - "exportPolicy": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'exportPolicy')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "networkFeatures": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'networkFeatures')]" - }, - "zones": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'zones')]" - }, - "coolAccess": { - "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolAccess'), false())]" - }, - "coolAccessRetrievalPolicy": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolAccessRetrievalPolicy')]" - }, - "coolnessPeriod": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolnessPeriod')]" - }, - "encryptionKeySource": { - "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'encryptionKeySource'), 'Microsoft.NetApp')]" - }, - "keyVaultPrivateEndpointResourceId": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'keyVaultPrivateEndpointResourceId')]" - }, - "dataProtection": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'dataProtection')]" - }, - "kerberosEnabled": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'kerberosEnabled')]" - }, - "smbContinuouslyAvailable": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbContinuouslyAvailable')]" - }, - "smbEncryption": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbEncryption')]" - }, - "smbNonBrowsable": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbNonBrowsable')]" - }, - "volumeType": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'volumeType')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "17068369293044189585" - }, - "name": "Azure NetApp Files Capacity Pool Volumes", - "description": "This module deploys an Azure NetApp Files Capacity Pool Volume." - }, - "definitions": { - "dataProtectionType": { - "type": "object", - "properties": { - "replication": { - "$ref": "#/definitions/replicationType", - "nullable": true, - "metadata": { - "description": "Optional. Replication properties." - } - }, - "backup": { - "$ref": "#/definitions/backupType", - "nullable": true, - "metadata": { - "description": "Optional. Backup properties." - } - }, - "snapshot": { - "$ref": "#/definitions/snapshotType", - "nullable": true, - "metadata": { - "description": "Optional. Snapshot properties." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the data protection properties." - } - }, - "replicationType": { - "type": "object", - "properties": { - "endpointType": { - "type": "string", - "allowedValues": [ - "dst", - "src" - ], - "metadata": { - "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." - } - }, - "remoteVolumeRegion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." - } - }, - "remoteVolumeResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." - } - }, - "replicationSchedule": { - "type": "string", - "allowedValues": [ - "_10minutely", - "daily", - "hourly" - ], - "metadata": { - "description": "Required. The replication schedule for the volume." - } - }, - "remotePath": { - "type": "object", - "properties": { - "externalHostName": { - "type": "string", - "metadata": { - "description": "Required. The Path to a ONTAP Host." - } - }, - "serverName": { - "type": "string", - "metadata": { - "description": "Required. The name of a server on the ONTAP Host." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of a volume on the server." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." - } - } - }, - "metadata": { - "description": "The type for the replication properties." - } - }, - "backupType": { - "type": "object", - "properties": { - "backupPolicyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the backup policy to link." - } - }, - "policyEnforced": { - "type": "bool", - "metadata": { - "description": "Required. Enable to enforce the policy." - } - }, - "backupVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Backup Vault." - } - } - }, - "metadata": { - "description": "The type for the backup properties." - } - }, - "snapshotType": { - "type": "object", - "properties": { - "snapshotPolicyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the snapshot policy to link." - } - } - }, - "metadata": { - "description": "The type for the snapshot properties." - } - }, - "exportPolicyType": { - "type": "object", - "properties": { - "rules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ruleIndex": { - "type": "int", - "metadata": { - "description": "Required. Order index." - } - }, - "allowedClients": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." - } - }, - "chownMode": { - "type": "string", - "allowedValues": [ - "Restricted", - "Unrestricted" - ], - "nullable": true, - "metadata": { - "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." - } - }, - "cifs": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Allows CIFS protocol." - } - }, - "hasRootAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Has root access to volume." - } - }, - "kerberos5ReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5 Read only access." - } - }, - "kerberos5ReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5 Read and write access." - } - }, - "kerberos5iReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5i Read only access." - } - }, - "kerberos5iReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5i Read and write access." - } - }, - "kerberos5pReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5p Read only access." - } - }, - "kerberos5pReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5p Read and write access." - } - }, - "nfsv3": { - "type": "bool", - "metadata": { - "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." - } - }, - "nfsv41": { - "type": "bool", - "metadata": { - "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." - } - }, - "unixReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Read only access." - } - }, - "unixReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Read and write access." - } - } - } - }, - "metadata": { - "description": "Required. The Export policy rules." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for export policy rules." - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" - } - } - } - }, - "parameters": { - "netAppAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." - } - }, - "capacityPoolName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent capacity pool. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the pool volume." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location of the pool volume." - } - }, - "coolAccess": { - "type": "bool", - "metadata": { - "description": "Required. If enabled (true) the pool can contain cool Access enabled volumes." - } - }, - "coolnessPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." - } - }, - "coolAccessRetrievalPolicy": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." - } - }, - "encryptionKeySource": { - "type": "string", - "metadata": { - "description": "Required. The source of the encryption key." - } - }, - "keyVaultPrivateEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the key vault private endpoint." - } - }, - "volumeType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The type of the volume. DataProtection volumes are used for replication." - } - }, - "zones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. Zone where the volume will be placed." - } - }, - "serviceLevel": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Premium", - "Standard", - "StandardZRS", - "Ultra" - ], - "metadata": { - "description": "Optional. The pool service level. Must match the one of the parent capacity pool." - } - }, - "networkFeatures": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Basic", - "Basic_Standard", - "Standard", - "Standard_Basic" - ], - "metadata": { - "description": "Optional. Network feature for the volume." - } - }, - "creationToken": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." - } - }, - "usageThreshold": { - "type": "int", - "metadata": { - "description": "Required. Maximum storage quota allowed for a file system in bytes." - } - }, - "protocolTypes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Set of protocol types." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." - } - }, - "exportPolicy": { - "$ref": "#/definitions/exportPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. The export policy rules." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "dataProtection": { - "$ref": "#/definitions/dataProtectionType", - "nullable": true, - "metadata": { - "description": "Optional. DataProtection type volumes include an object containing details of the replication." - } - }, - "smbEncryption": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." - } - }, - "smbContinuouslyAvailable": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." - } - }, - "smbNonBrowsable": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." - } - }, - "kerberosEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Define if a volume is KerberosEnabled." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "remoteCapacityPoolName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], '')]", - "remoteNetAppName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], '')]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "netAppAccount::capacityPool": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" - }, - "netAppAccount::backupVault": { - "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/backupVaults", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))]" - }, - "netAppAccount::backupPolicy": { - "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName'))]" - }, - "netAppAccount::snapshotPolicy": { - "condition": "[not(empty(tryGet(parameters('dataProtection'), 'snapshot')))]", - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))]" - }, - "remoteNetAppAccount::remoteCapacityPool::remoteVolume": { - "condition": "[and(and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName'))))), not(empty(tryGet(parameters('dataProtection'), 'replication'))))]", - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", - "apiVersion": "2024-07-01", - "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", - "name": "[format('{0}/{1}/{2}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/')))]" - }, - "remoteNetAppAccount::remoteCapacityPool": { - "condition": "[and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName')))))]", - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools", - "apiVersion": "2024-07-01", - "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", - "name": "[format('{0}/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10])]" - }, - "vnet::subnet": { - "existing": true, - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2024-03-01", - "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", - "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/')))]" - }, - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "keyVaultPrivateEndpoint": { - "condition": "[not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp'))]", - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-03-01", - "subscriptionId": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/'))]" - }, - "remoteNetAppAccount": { - "condition": "[and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName'))))]", - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", - "name": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8]]" - }, - "vnet": { - "existing": true, - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-03-01", - "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", - "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", - "name": "[split(parameters('subnetResourceId'), '/')[8]]" - }, - "volume": { - "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": "[shallowMerge(createArray(createObject('coolAccess', parameters('coolAccess'), 'coolAccessRetrievalPolicy', parameters('coolAccessRetrievalPolicy'), 'coolnessPeriod', parameters('coolnessPeriod'), 'encryptionKeySource', parameters('encryptionKeySource')), if(not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp')), createObject('keyVaultPrivateEndpointResourceId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2], split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]), 'Microsoft.Network/privateEndpoints', last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/')))), createObject()), if(not(empty(parameters('volumeType'))), createObject('volumeType', parameters('volumeType')), createObject()), createObject('dataProtection', if(not(empty(parameters('dataProtection'))), createObject('replication', if(not(empty(tryGet(parameters('dataProtection'), 'replication'))), createObject('endpointType', tryGet(parameters('dataProtection'), 'replication', 'endpointType'), 'remoteVolumeRegion', if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]), 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/'))), null()), 'remoteVolumeResourceId', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'replicationSchedule', tryGet(parameters('dataProtection'), 'replication', 'replicationSchedule'), 'remotePath', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remotePath')), createObject()), 'backup', if(not(empty(tryGet(parameters('dataProtection'), 'backup'))), createObject('backupPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName')), 'policyEnforced', coalesce(tryGet(parameters('dataProtection'), 'backup', 'policyEnforced'), false()), 'backupVaultId', resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))), createObject()), 'snapshot', if(not(empty(tryGet(parameters('dataProtection'), 'snapshot'))), createObject('snapshotPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))), createObject())), null()), 'networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('subnetResourceId'), '/')[2], split(parameters('subnetResourceId'), '/')[4]), 'Microsoft.Network/virtualNetworks/subnets', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/'))), 'exportPolicy', parameters('exportPolicy'), 'smbContinuouslyAvailable', parameters('smbContinuouslyAvailable'), 'smbEncryption', parameters('smbEncryption'), 'smbNonBrowsable', parameters('smbNonBrowsable'), 'kerberosEnabled', parameters('kerberosEnabled'))))]", - "zones": "[map(parameters('zones'), lambda('zone', format('{0}', lambdaVariables('zone'))))]" - }, - "volume_roleAssignments": { - "copy": { - "name": "volume_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}/capacityPools/{1}/volumes/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "volume" - ] - } - }, + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.2.4', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Volume." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The Resource ID of the Volume." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the Volume was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('volume', '2024-07-01', 'full').location]" + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" } } } + } + }, + "networkInterface": { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "ipConfigurations", + "count": "[length(parameters('ipConfigurations'))]", + "input": { + "name": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].name, format('ipconfig0{0}', add(copyIndex('ipConfigurations'), 1)))]", + "properties": { + "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", + "privateIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod, null()), null())]", + "privateIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress, null()), null())]", + "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId, null())), createObject('id', parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId), null()), null())]", + "subnet": { + "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" + }, + "loadBalancerBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerBackendAddressPools, null())]", + "applicationSecurityGroups": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationSecurityGroups, null())]", + "applicationGatewayBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationGatewayBackendAddressPools, null())]", + "gatewayLoadBalancer": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].gatewayLoadBalancer, null())]", + "loadBalancerInboundNatRules": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerInboundNatRules, null())]", + "privateIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddressVersion, null())]", + "virtualNetworkTaps": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].virtualNetworkTaps, null())]" + } + } + } + ], + "auxiliaryMode": "[parameters('auxiliaryMode')]", + "auxiliarySku": "[parameters('auxiliarySku')]", + "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", + "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", + "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", + "enableIPForwarding": "[parameters('enableIPForwarding')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" + } + }, + "networkInterface_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_diagnosticSettings": { + "copy": { + "name": "networkInterface_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkInterface" + ] + }, + "networkInterface_roleAssignments": { + "copy": { + "name": "networkInterface_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "capacityPool" + "networkInterface" ] } }, @@ -31986,21 +25515,21 @@ "name": { "type": "string", "metadata": { - "description": "The name of the Capacity Pool." + "description": "The name of the deployed resource." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the Capacity Pool." + "description": "The resource ID of the deployed resource." }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools', parameters('netAppAccountName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the Resource Group the Capacity Pool was created in." + "description": "The resource group of the deployed resource." }, "value": "[resourceGroup().name]" }, @@ -32009,377 +25538,1213 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('capacityPool', '2024-07-01', 'full').location]" - }, - "volumeResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the volume created in the capacity pool." - }, - "copy": { - "count": "[length(coalesce(parameters('volumes'), createArray()))]", - "input": "[reference(format('capacityPool_volumes[{0}]', copyIndex())).outputs.resourceId.value]" - } + "value": "[reference('networkInterface', '2023-04-01', 'full').location]" } } } }, - "dependsOn": [ - "netAppAccount", - "netAppAccount_backupPolicies", - "netAppAccount_backupVault", - "netAppAccount_snapshotPolicies" + "dependsOn": [ + "networkInterface_publicIPAddresses" + ] + } + } + } + } + }, + "vm_aadJoinExtension": { + "condition": "[parameters('extensionAadJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "AADLogin" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.ActiveDirectory" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", + "typeHandlerVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAadJoinConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.0'), createObject('value', '1.0')))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAadJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAadJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": "[if(contains(parameters('extensionAadJoinConfig'), 'settings'), createObject('value', parameters('extensionAadJoinConfig').settings), createObject('value', createObject()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] + }, + "vm_domainJoinExtension": { + "condition": "[parameters('extensionDomainJoinConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DomainJoin" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "JsonADDomainExtension" + }, + "typeHandlerVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDomainJoinConfig').typeHandlerVersion), createObject('value', '1.3'))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDomainJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDomainJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": { + "value": "[parameters('extensionDomainJoinConfig').settings]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": { + "Password": "[parameters('extensionDomainJoinPassword')]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_aadJoinExtension" + ] + }, + "vm_desiredStateConfigurationExtension": { + "condition": "[parameters('extensionDSCConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "DesiredStateConfiguration" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Powershell" + }, + "type": { + "value": "DSC" + }, + "typeHandlerVersion": "[if(contains(parameters('extensionDSCConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDSCConfig').typeHandlerVersion), createObject('value', '2.77'))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDSCConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDSCConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": "[if(contains(parameters('extensionDSCConfig'), 'settings'), createObject('value', parameters('extensionDSCConfig').settings), createObject('value', createObject()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": "[if(contains(parameters('extensionDSCConfig'), 'protectedSettings'), createObject('value', parameters('extensionDSCConfig').protectedSettings), createObject('value', createObject()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] + }, + "vm_customScriptExtension": { + "condition": "[parameters('extensionCustomScriptConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "CustomScriptExtension" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", + "typeHandlerVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionCustomScriptConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '1.10'), createObject('value', '2.1')))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionCustomScriptConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionCustomScriptConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "settings": { + "value": { + "copy": [ + { + "name": "fileUris", + "count": "[length(parameters('extensionCustomScriptConfig').fileData)]", + "input": "[if(contains(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')], 'storageAccountId'), format('{0}?{1}', parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri, listAccountSas(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].storageAccountId, '2019-04-01', variables('accountSasProperties')).accountSasToken), parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri)]" + } ] + } + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" + }, + "protectedSettings": { + "value": "[parameters('extensionCustomScriptProtectedSetting')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_desiredStateConfigurationExtension" + ] + }, + "vm_azureDiskEncryptionExtension": { + "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "AzureDiskEncryption" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Azure.Security" + }, + "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", + "typeHandlerVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.2'), createObject('value', '1.1')))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "forceUpdateTag": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').forceUpdateTag), createObject('value', '1.0'))]", + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" + }, + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" }, - "netAppAccount_backupVaultBackups": { - "condition": "[not(empty(tryGet(parameters('backupVault'), 'backups')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-ANFAccount-BackupVault-Backups', uniqueString(deployment().name, parameters('location')))]", + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(parameters('backupVault'), 'name')]" - }, - "backups": { - "value": "[tryGet(parameters('backupVault'), 'backups')]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('backupVault'), 'location'), parameters('location'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12673365749567452459" - }, - "name": "Azure NetApp Files Volume Backup Vault", - "description": "This module deploys a NetApp Files Backup Vault." - }, - "definitions": { - "backupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "label": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Label for backup." - } - }, - "snapshotName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of the volume to backup." - } - }, - "capacityPoolName": { - "type": "string", - "metadata": { - "description": "Required. The name of the capacity pool containing the volume." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a backup." - } - } - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "vault", - "metadata": { - "description": "Optional. The name of the backup vault." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location of the backup vault." - } - }, - "netAppAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." - } - }, - "backups": { - "type": "array", - "items": { - "$ref": "#/definitions/backupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of backups to create." - } - } - }, - "resources": { - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "backupVault": { - "type": "Microsoft.NetApp/netAppAccounts/backupVaults", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": {} - }, - "backupVault_backups": { - "copy": { - "name": "backupVault_backups", - "count": "[length(coalesce(parameters('backups'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-ANF-Backup-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('netAppAccountName')]" - }, - "backupVaultName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'name')]" - }, - "label": { - "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'label')]" - }, - "snapshotName": { - "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'snapshotName')]" - }, - "volumeName": { - "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].volumeName]" - }, - "capacityPoolName": { - "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].capacityPoolName]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "2218257802133394577" - }, - "name": "Azure NetApp Files Volume Backup", - "description": "This module deploys a backup of a NetApp Files Volume." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "backup", - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "backupVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent backup vault. Required if the template is used in a standalone deployment." - } - }, - "netAppAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." - } - }, - "label": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Label for backup." - } - }, - "snapshotName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of the volume to backup." - } - }, - "capacityPoolName": { - "type": "string", - "metadata": { - "description": "Required. The name of the capacity pool containing the volume." - } - } - }, - "resources": { - "netAppAccount::remoteCapacityPool::volume": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" - }, - "netAppAccount::backupVault": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/backupVaults", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupVaultName'))]" - }, - "netAppAccount::remoteCapacityPool": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" - }, - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "backup": { - "type": "Microsoft.NetApp/netAppAccounts/backupVaults/backups", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]", - "properties": { - "label": "[parameters('label')]", - "snapshotName": "[parameters('snapshotName')]", - "volumeResourceId": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the backup." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The Resource ID of the backup." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults/backups', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the backup was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "backupVault" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the backup vault." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The Resource ID of the backup vault." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the backup vault was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('backupVault', '2024-07-01', 'full').location]" - } - } - } + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." }, - "dependsOn": [ - "netAppAccount", - "netAppAccount_capacityPools" - ] + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm" + ] + }, + "vm_nvidiaGpuDriverWindowsExtension": { + "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualMachineName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "NvidiaGpuDriverWindows" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.HpcCompute" + }, + "type": { + "value": "NvidiaGpuDriverWindows" + }, + "typeHandlerVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').typeHandlerVersion), createObject('value', '1.4'))]", + "autoUpgradeMinorVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').autoUpgradeMinorVersion), createObject('value', true()))]", + "enableAutomaticUpgrade": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').enableAutomaticUpgrade), createObject('value', false()))]", + "supressFailures": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } } }, "outputs": { "name": { "type": "string", "metadata": { - "description": "The name of the NetApp account." + "description": "The name of the extension." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The Resource ID of the NetApp account." + "description": "The resource ID of the extension." }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts', parameters('name'))]" + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the Resource Group the NetApp account was created in." + "description": "The name of the Resource Group the extension was created in." }, "value": "[resourceGroup().name]" }, @@ -32388,430 +26753,1268 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('netAppAccount', '2024-07-01', 'full').location]" + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "vm", + "vm_azureDiskEncryptionExtension" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the VM." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the VM." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the VM was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('vm', '2023-09-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vm', '2023-09-01', 'full').location]" + } + } + } + } + } + ] + } + }, + "dependsOn": [ + "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]", + "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time')))]" + ] + }, + { + "condition": "[parameters('createAvdFslogixDeployment')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-FSLogix-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storagePurpose": { + "value": "fslogix" + }, + "vmLocalUserName": { + "value": "[parameters('avdVmLocalUserName')]" + }, + "fileShareName": { + "value": "[variables('varFslogixFileShareName')]" + }, + "fileShareMultichannel": "[if(equals(parameters('fslogixStoragePerformance'), 'Premium'), createObject('value', true()), createObject('value', false()))]", + "storageSku": { + "value": "[variables('varFslogixStorageSku')]" + }, + "fileShareQuotaSize": { + "value": "[parameters('fslogixFileShareQuotaSize')]" + }, + "storageAccountFqdn": { + "value": "[variables('varFslogixStorageFqdn')]" + }, + "storageAccountName": { + "value": "[variables('varFslogixStorageName')]" + }, + "storageToDomainScript": { + "value": "[variables('varStorageToDomainScript')]" + }, + "storageToDomainScriptUri": { + "value": "[variables('varStorageToDomainScriptUri')]" + }, + "identityServiceProvider": { + "value": "[parameters('avdIdentityServiceProvider')]" + }, + "dscAgentPackageLocation": { + "value": "[variables('varStorageAzureFilesDscAgentPackageLocation')]" + }, + "storageCustomOuPath": { + "value": "[variables('varStorageCustomOuPath')]" + }, + "managementVmName": { + "value": "[variables('varManagementVmName')]" + }, + "deployPrivateEndpoint": { + "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" + }, + "ouStgPath": { + "value": "[variables('varOuStgPath')]" + }, + "managedIdentityClientId": "[if(and(variables('varCreateStorageDeployment'), not(equals(parameters('avdIdentityServiceProvider'), 'EntraID'))), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time'))), '2022-09-01').outputs.managedIdentityStorageClientId.value), createObject('value', ''))]", + "securityPrincipalName": { + "value": "[variables('varSecurityPrincipalName')]" + }, + "domainJoinUserName": { + "value": "[parameters('avdDomainJoinUserName')]" + }, + "wrklKvName": { + "value": "[variables('varWrklKvName')]" + }, + "serviceObjectsRgName": { + "value": "[variables('varServiceObjectsRgName')]" + }, + "identityDomainName": { + "value": "[parameters('identityDomainName')]" + }, + "identityDomainGuid": { + "value": "[parameters('identityDomainGuid')]" + }, + "location": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostLocation')), createObject('value', parameters('avdManagementPlaneLocation')))]", + "storageObjectsRgName": { + "value": "[variables('varStorageObjectsRgName')]" + }, + "privateEndpointSubnetId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName'))), createObject('value', parameters('existingVnetPrivateEndpointSubnetResourceId')))]", + "vmsSubnetId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", + "vnetPrivateDnsZoneFilesId": "[if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.azureFilesDnsZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneFilesId')))]", + "workloadSubsId": { + "value": "[parameters('avdWorkloadSubsId')]" + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]", + "alaWorkspaceResourceId": "[if(parameters('avdDeployMonitoring'), if(parameters('deployAlaWorkspace'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.avdAlaWorkspaceResourceId.value), createObject('value', parameters('alaExistingWorkspaceResourceId'))), createObject('value', ''))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4402521403689705705" + }, + "name": "AVD LZA storage", + "description": "This module deploys storage account, azure files. domain join logic", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "workloadSubsId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "storageObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name for Azure Files." + } + }, + "identityServiceProvider": { + "type": "string", + "metadata": { + "description": "Required, The service providing domain services for Azure Virtual Desktop." + } + }, + "serviceObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name for management VM." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Storage account name." + } + }, + "fileShareName": { + "type": "string", + "metadata": { + "description": "Storage account file share name." + } + }, + "privateEndpointSubnetId": { + "type": "string", + "metadata": { + "description": "Private endpoint subnet ID." + } + }, + "vmsSubnetId": { + "type": "string", + "metadata": { + "description": "VMs subnet ID." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy resources." + } + }, + "fileShareMultichannel": { + "type": "bool", + "metadata": { + "description": "File share SMB multichannel." + } + }, + "identityDomainName": { + "type": "string", + "metadata": { + "description": "Identity domain name." + } + }, + "identityDomainGuid": { + "type": "string", + "metadata": { + "description": "AD domain GUID." + } + }, + "wrklKvName": { + "type": "string", + "metadata": { + "description": "Keyvault name to get credentials from." + } + }, + "domainJoinUserName": { + "type": "string", + "metadata": { + "description": "AVD session host domain join credentials." + } + }, + "vmLocalUserName": { + "type": "string", + "metadata": { + "description": "AVD session host local admin credentials." + } + }, + "storageSku": { + "type": "string", + "metadata": { + "description": "Azure Files storage account SKU." + } + }, + "fileShareQuotaSize": { + "type": "int", + "metadata": { + "description": "*Azure File share quota" + } + }, + "vnetPrivateDnsZoneFilesId": { + "type": "string", + "metadata": { + "description": "Use Azure private DNS zones for private endpoints." + } + }, + "storageToDomainScript": { + "type": "string", + "metadata": { + "description": "Script name for adding storage account to Active Directory." + } + }, + "storageToDomainScriptUri": { + "type": "string", + "metadata": { + "description": "URI for the script for adding the storage account to Active Directory." + } + }, + "tags": { + "type": "object", + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "managementVmName": { + "type": "string", + "metadata": { + "description": "Name for management virtual machine. for tools and to join Azure Files to domain." + } + }, + "deployPrivateEndpoint": { + "type": "bool", + "metadata": { + "description": "Optional. AVD Accelerator will deploy with private endpoints by default." + } + }, + "alaWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Log analytics workspace for diagnostic logs." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + }, + "storagePurpose": { + "type": "string", + "metadata": { + "description": "Sets purpose of the storage account." + } + }, + "dscAgentPackageLocation": { + "type": "string", + "metadata": { + "description": "Sets location of DSC Agent." + } + }, + "storageCustomOuPath": { + "type": "string", + "metadata": { + "description": "Custom OU path for storage." + } + }, + "ouStgPath": { + "type": "string", + "metadata": { + "description": "OU Storage Path" + } + }, + "managedIdentityClientId": { + "type": "string", + "metadata": { + "description": "Managed Identity Client ID" + } + }, + "securityPrincipalName": { + "type": "string", + "metadata": { + "description": "Identity name array to grant RBAC role to access AVD application group and NTFS permissions." + } + }, + "storageAccountFqdn": { + "type": "string", + "metadata": { + "description": "storage account FDQN." + } + } + }, + "variables": { + "varAzureCloudName": "[environment().name]", + "varWrklStoragePrivateEndpointName": "[format('pe-{0}-file', parameters('storageAccountName'))]", + "varSecurityPrincipalName": "[if(not(empty(parameters('securityPrincipalName'))), parameters('securityPrincipalName'), 'none')]", + "varAdminUserName": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('vmLocalUserName'), parameters('domainJoinUserName'))]", + "varStorageToDomainScriptArgs": "[format('-DscPath {0} -StorageAccountName {1} -StorageAccountRG {2} -StoragePurpose {3} -DomainName {4} -IdentityServiceProvider {5} -AzureCloudEnvironment {6} -SubscriptionId {7} -AdminUserName {8} -CustomOuPath {9} -OUName {10} -ShareName {11} -ClientId {12} -SecurityPrincipalName \"{13}\" -StorageAccountFqdn {14} ', parameters('dscAgentPackageLocation'), parameters('storageAccountName'), parameters('storageObjectsRgName'), parameters('storagePurpose'), parameters('identityDomainName'), parameters('identityServiceProvider'), variables('varAzureCloudName'), parameters('workloadSubsId'), variables('varAdminUserName'), parameters('storageCustomOuPath'), parameters('ouStgPath'), parameters('fileShareName'), parameters('managedIdentityClientId'), variables('varSecurityPrincipalName'), parameters('storageAccountFqdn'))]", + "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('storageAccountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": { + "value": "[parameters('storageSku')]" + }, + "allowBlobPublicAccess": { + "value": false + }, + "publicNetworkAccess": "[if(parameters('deployPrivateEndpoint'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "kind": "[if(or(equals(parameters('storageSku'), 'Premium_LRS'), equals(parameters('storageSku'), 'Premium_ZRS')), createObject('value', 'FileStorage'), createObject('value', 'StorageV2'))]", + "largeFileSharesState": "[if(or(equals(parameters('storageSku'), 'Standard_LRS'), equals(parameters('storageSku'), 'Standard_ZRS')), createObject('value', 'Enabled'), createObject('value', 'Disabled'))]", + "azureFilesIdentityBasedAuthentication": "[if(not(equals(parameters('identityServiceProvider'), 'EntraID')), createObject('value', createObject('directoryServiceOptions', if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDS', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), 'AADKERB', 'none')), 'activeDirectoryProperties', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), createObject('domainGuid', parameters('identityDomainGuid'), 'domainName', parameters('identityDomainName')), createObject()))), createObject('value', null()))]", + "accessTier": { + "value": "Hot" + }, + "networkAcls": "[if(parameters('deployPrivateEndpoint'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', parameters('vmsSubnetId'), 'action', 'Allow')), 'ipRules', createArray())))]", + "fileServices": { + "value": { + "shares": [ + { + "name": "[parameters('fileShareName')]", + "shareQuota": "[mul(parameters('fileShareQuotaSize'), 100)]" + } + ], + "protocolSettings": "[if(parameters('fileShareMultichannel'), createObject('smb', createObject('multichannel', createObject('enabled', parameters('fileShareMultichannel')))), createObject())]", + "diagnosticSettings": "[variables('varDiagnosticSettings')]" + } + }, + "privateEndpoints": "[if(parameters('deployPrivateEndpoint'), createObject('value', createArray(createObject('name', variables('varWrklStoragePrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointSubnetId'), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklStoragePrivateEndpointName')), 'service', 'file', 'privateDnsZoneGroupName', split(parameters('vnetPrivateDnsZoneFilesId'), '/')[8], 'privateDnsZoneResourceIds', createArray(parameters('vnetPrivateDnsZoneFilesId'))))), createObject('value', createArray()))]", + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "15994741654178645865" + }, + "name": "Storage Accounts", + "description": "This module deploys a Storage Account.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + } + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" }, - "capacityPoolResourceIds": { - "type": "array", - "items": { - "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Manual PrivateLink Service Connections." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, "properties": { - "resourceId": { - "type": "string" - }, - "volumeResourceIds": { - "type": "array", - "items": { - "type": "string" + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." } } - }, - "metadata": { - "description": "The resource IDs of the created capacity pools & their volumes." - }, - "copy": { - "count": "[length(coalesce(parameters('capacityPools'), createArray()))]", - "input": { - "resourceId": "[reference(format('netAppAccount_capacityPools[{0}]', copyIndex())).outputs.resourceId.value]", - "volumeResourceIds": "[reference(format('netAppAccount_capacityPools[{0}]', copyIndex())).outputs.volumeResourceIds.value]" - } } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." } } } - } - } - ], - "outputs": { - "anfFslogixVolumeResourceId": { - "type": "string", - "value": "[if(parameters('createFslogixStorage'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.capacityPoolResourceIds.value[0].volumeResourceIds[0], '')]" + }, + "nullable": true }, - "anfAppAttachVolumeResourceId": { - "type": "string", - "value": "[if(and(parameters('createAppAttachStorage'), parameters('createFslogixStorage')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.capacityPoolResourceIds.value[1].volumeResourceIds[1], if(and(parameters('createAppAttachStorage'), not(parameters('createFslogixStorage'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.capacityPoolResourceIds.value[0].volumeResourceIds[0], ''))]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]" - ] - }, - { - "condition": "[equals(parameters('storageService'), 'ANF')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Get-ANF-SMB-Server-FQDN-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppVolumeResourceId": "[if(and(parameters('createFslogixDeployment'), equals(parameters('storageService'), 'ANF')), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfFslogixVolumeResourceId.value), if(and(parameters('createAppAttachDeployment'), equals(parameters('storageService'), 'ANF')), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfAppAttachVolumeResourceId.value), createObject('value', '')))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "1092509597594508559" + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true }, - "name": "AVD LZA storage ANF volume SMB server FQDN", - "description": "This module returns the SMB server FQDN of an ANF volume.", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "netAppVolumeResourceId": { - "type": "string" - } - }, - "resources": [], - "outputs": { - "anfSmbServerFqdn": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('netAppVolumeResourceId'), '/')[2], split(parameters('netAppVolumeResourceId'), '/')[4]), 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', split(parameters('netAppVolumeResourceId'), '/')[8], split(parameters('netAppVolumeResourceId'), '/')[10], last(split(parameters('netAppVolumeResourceId'), '/'))), '2024-09-01').mountTargets[0].smbServerFqdn]" + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time')))]" - ] - }, - { - "condition": "[and(parameters('createFslogixDeployment'), not(equals(parameters('storageService'), 'ANF')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-FSLogix-ST-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storagePurpose": { - "value": "fslogix" - }, - "vmLocalUserName": { - "value": "[parameters('vmLocalUserName')]" - }, - "fileShareName": { - "value": "[variables('varFslogixFileShareName')]" - }, - "fileShareMultichannel": "[if(equals(variables('varFslogixStoragePerformance'), 'Premium'), createObject('value', true()), createObject('value', false()))]", - "storageSku": { - "value": "[variables('varFslogixStorageSku')]" - }, - "fileShareQuotaSize": { - "value": "[parameters('fslogixFileShareQuotaSize')]" - }, - "storageAccountFqdn": { - "value": "[variables('varFslogixStorageFqdn')]" - }, - "storageAccountName": { - "value": "[variables('varFslogixStorageName')]" - }, - "storageToDomainScript": { - "value": "[variables('varStorageToDomainScript')]" - }, - "storageToDomainScriptUri": { - "value": "[variables('varStorageToDomainScriptUri')]" - }, - "identityServiceProvider": { - "value": "[parameters('identityServiceProvider')]" - }, - "dscAgentPackageLocation": { - "value": "[variables('varStorageAzureFilesDscAgentPackageLocation')]" - }, - "storageCustomOuPath": { - "value": "[variables('varStorageCustomOuPath')]" - }, - "managementVmName": { - "value": "[variables('varManagementVmName')]" - }, - "deployPrivateEndpoint": { - "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" - }, - "keyVaultResourceId": { - "value": "[parameters('keyVaultResourceId')]" - }, - "storageOuPath": { - "value": "[variables('varOuStgPath')]" - }, - "managedIdentityClientId": { - "value": "[parameters('managedIdentityClientId')]" - }, - "securityPrincipalName": { - "value": "[parameters('securityPrincipalName')]" - }, - "domainJoinUserName": { - "value": "[parameters('domainJoinUserName')]" - }, - "serviceObjectsRgName": { - "value": "[parameters('serviceObjectsRgName')]" - }, - "identityDomainName": { - "value": "[parameters('identityDomainName')]" - }, - "identityDomainGuid": { - "value": "[parameters('identityDomainGuid')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "storageObjectsRgName": { - "value": "[parameters('storageObjectsRgName')]" - }, - "privateEndpointSubnetResourceId": { - "value": "[parameters('privateEndpointSubnetResourceId')]" - }, - "vmsSubnetResourceId": { - "value": "[parameters('vmsSubnetResourceId')]" - }, - "privateDnsZoneFilesResourceId": { - "value": "[parameters('privateDnsZoneFilesResourceId')]" - }, - "subId": { - "value": "[parameters('subId')]" - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]", - "alaWorkspaceResourceId": { - "value": "[parameters('alaWorkspaceResourceId')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4958601852198550361" - }, - "name": "AVD LZA storage", - "description": "This module deploys storage account, azure files. domain join logic", - "owner": "Azure/avdaccelerator" }, "parameters": { - "subId": { + "name": { "type": "string", + "maxLength": 24, "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." + "description": "Required. Name of the Storage Account. Must be lower-case." } }, - "storageObjectsRgName": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Resource Group Name for Azure Files." + "description": "Optional. Location for all resources." } }, - "identityServiceProvider": { - "type": "string", + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Required, The service providing domain services for Azure Virtual Desktop." + "description": "Optional. The managed identity definition for this resource." } }, - "serviceObjectsRgName": { + "kind": { "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], "metadata": { - "description": "Resource Group Name for management VM." + "description": "Optional. Type of Storage Account to create." } }, - "storageAccountName": { + "skuName": { "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS", + "Premium_ZRS", + "Standard_GZRS", + "Standard_RAGZRS" + ], "metadata": { - "description": "Storage account name." + "description": "Optional. Storage Account Sku Name." } }, - "fileShareName": { + "accessTier": { "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool" + ], "metadata": { - "description": "Storage account file share name." + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." } }, - "privateEndpointSubnetResourceId": { + "largeFileSharesState": { "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], "metadata": { - "description": "Private endpoint subnet ID." + "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." } }, - "vmsSubnetResourceId": { - "type": "string", + "azureFilesIdentityBasedAuthentication": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "VMs subnet ID." + "description": "Optional. Provides the identity based authentication settings for Azure Files." } }, - "location": { - "type": "string", + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Location where to deploy resources." + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." } }, - "fileShareMultichannel": { + "allowSharedKeyAccess": { "type": "bool", + "defaultValue": true, "metadata": { - "description": "File share SMB multichannel." + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." } }, - "identityDomainName": { - "type": "string", + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", "metadata": { - "description": "Identity domain name." + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } }, - "identityDomainGuid": { - "type": "string", + "managementPolicyRules": { + "type": "array", + "nullable": true, "metadata": { - "description": "AD domain GUID." + "description": "Optional. The Storage Account ManagementPolicies Rules." } }, - "keyVaultResourceId": { - "type": "string", + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, "metadata": { - "description": "Key Vault Resource ID." + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." } }, - "domainJoinUserName": { - "type": "string", + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "AVD session host domain join credentials." + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." } }, - "vmLocalUserName": { - "type": "string", + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "AVD session host local admin credentials." + "description": "Optional. Allow or disallow cross AAD tenant object replication." } }, - "storageSku": { + "customDomainName": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Azure Files storage account SKU." + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." } }, - "fileShareQuotaSize": { - "type": "int", + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "*Azure File share quota" + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." } }, - "privateDnsZoneFilesResourceId": { + "dnsEndpointType": { "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AzureDnsZone", + "Standard" + ], "metadata": { - "description": "Use Azure private DNS zones for private endpoints." + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." } }, - "storageToDomainScript": { - "type": "string", + "blobServices": { + "type": "object", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", "metadata": { - "description": "Script name for adding storage account to Active Directory." + "description": "Optional. Blob service and containers to deploy." } }, - "storageToDomainScriptUri": { - "type": "string", + "fileServices": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "URI for the script for adding the storage account to Active Directory." + "description": "Optional. File service and shares to deploy." } }, - "tags": { + "queueServices": { "type": "object", "defaultValue": {}, "metadata": { - "description": "Tags to be applied to resources" + "description": "Optional. Queue service and queues to create." } }, - "managementVmName": { - "type": "string", + "tableServices": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Name for management virtual machine. for tools and to join Azure Files to domain." + "description": "Optional. Table service and tables to create." } }, - "deployPrivateEndpoint": { + "allowBlobPublicAccess": { "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. AVD Accelerator will deploy with private endpoints by default." + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." } }, - "alaWorkspaceResourceId": { + "minimumTlsVersion": { "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_0", + "TLS1_1", + "TLS1_2" + ], "metadata": { - "description": "Log analytics workspace for diagnostic logs." + "description": "Optional. Set the minimum TLS version on request to storage." } }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", + "enableHierarchicalNamespace": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." } }, - "storagePurpose": { - "type": "string", + "enableSftp": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Sets purpose of the storage account." + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." } }, - "dscAgentPackageLocation": { - "type": "string", + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Sets location of DSC Agent." + "description": "Optional. Enables local users feature, if set to true." } }, - "storageCustomOuPath": { - "type": "string", + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Custom OU path for storage." + "description": "Optional. Enable/Disable usage telemetry for module." } }, - "storageOuPath": { + "allowedCopyScope": { "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AAD", + "PrivateLink" + ], "metadata": { - "description": "OU Storage Path" + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." } }, - "managedIdentityClientId": { + "publicNetworkAccess": { "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", "metadata": { - "description": "Managed Identity Client ID" + "description": "Optional. The customer managed key definition." } }, - "securityPrincipalName": { + "sasExpirationPeriod": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Identity name array to grant RBAC role to access AVD application group and NTFS permissions." + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." } }, - "storageAccountFqdn": { + "keyType": { "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], "metadata": { - "description": "storage account FDQN." + "description": "Optional. The keyType to use with Queue & Table services." } } }, "variables": { - "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", - "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", - "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]", - "varAzureCloudName": "[environment().name]", - "varWrklStoragePrivateEndpointName": "[format('pe-{0}-file', parameters('storageAccountName'))]", - "varSecurityPrincipalName": "[if(not(empty(parameters('securityPrincipalName'))), parameters('securityPrincipalName'), 'none')]", - "varAdminUserName": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('vmLocalUserName'), parameters('domainJoinUserName'))]", - "varStorageToDomainScriptArgs": "[format('-DscPath {0} -StorageAccountName {1} -StorageAccountRG {2} -StoragePurpose {3} -DomainName {4} -IdentityServiceProvider {5} -AzureCloudEnvironment {6} -SubscriptionId {7} -AdminUserName {8} -CustomOuPath {9} -OUName {10} -ShareName {11} -ClientId {12} -SecurityPrincipalName \"{13}\" -StorageAccountFqdn {14} ', parameters('dscAgentPackageLocation'), parameters('storageAccountName'), parameters('storageObjectsRgName'), parameters('storagePurpose'), parameters('identityDomainName'), parameters('identityServiceProvider'), variables('varAzureCloudName'), parameters('subId'), variables('varAdminUserName'), parameters('storageCustomOuPath'), parameters('storageOuPath'), parameters('fileShareName'), parameters('managedIdentityClientId'), variables('varSecurityPrincipalName'), parameters('storageAccountFqdn'))]", - "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]" + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" }, - "resources": [ - { + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", + "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", + "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", + "customDomain": { + "name": "[parameters('customDomainName')]", + "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" + }, + "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", + "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", + "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", + "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", + "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", + "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", + "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", + "isSftpEnabled": "[parameters('enableSftp')]", + "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", + "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", + "minimumTlsVersion": "[parameters('minimumTlsVersion')]", + "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", + "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_privateEndpoints": { + "copy": { + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subId'))]", - "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", + "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -32819,43 +28022,42 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('storageAccountName')]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" }, "location": { - "value": "[parameters('location')]" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" }, - "skuName": { - "value": "[parameters('storageSku')]" + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" }, - "allowBlobPublicAccess": { - "value": false + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" }, - "publicNetworkAccess": "[if(parameters('deployPrivateEndpoint'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "kind": "[if(or(equals(parameters('storageSku'), 'Premium_LRS'), equals(parameters('storageSku'), 'Premium_ZRS')), createObject('value', 'FileStorage'), createObject('value', 'StorageV2'))]", - "largeFileSharesState": "[if(or(equals(parameters('storageSku'), 'Standard_LRS'), equals(parameters('storageSku'), 'Standard_ZRS')), createObject('value', 'Enabled'), createObject('value', 'Disabled'))]", - "azureFilesIdentityBasedAuthentication": "[if(not(equals(parameters('identityServiceProvider'), 'EntraID')), createObject('value', createObject('directoryServiceOptions', if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDS', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), 'AADKERB', 'none')), 'activeDirectoryProperties', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), createObject('domainGuid', parameters('identityDomainGuid'), 'domainName', parameters('identityDomainName')), createObject()))), createObject('value', null()))]", - "accessTier": { - "value": "Hot" + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" }, - "networkAcls": "[if(parameters('deployPrivateEndpoint'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', parameters('vmsSubnetResourceId'), 'action', 'Allow')), 'ipRules', createArray())))]", - "fileServices": { - "value": { - "shares": [ - { - "name": "[parameters('fileShareName')]", - "shareQuota": "[parameters('fileShareQuotaSize')]" - } - ], - "protocolSettings": "[if(parameters('fileShareMultichannel'), createObject('smb', createObject('multichannel', createObject('enabled', parameters('fileShareMultichannel')))), createObject())]", - "diagnosticSettings": "[variables('varDiagnosticSettings')]" - } + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" }, - "privateEndpoints": "[if(parameters('deployPrivateEndpoint'), createObject('value', createArray(createObject('name', variables('varWrklStoragePrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklStoragePrivateEndpointName')), 'service', 'file', 'privateDnsZoneGroupName', split(parameters('privateDnsZoneFilesResourceId'), '/')[8], 'privateDnsZoneResourceIds', createArray(parameters('privateDnsZoneFilesResourceId'))))), createObject('value', createArray()))]", - "tags": { - "value": "[parameters('tags')]" + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" } }, "template": { @@ -32865,726 +28067,373 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "15994741654178645865" + "version": "0.25.53.49325", + "templateHash": "4120048060064073955" }, - "name": "Storage Accounts", - "description": "This module deploys a Storage Account.", + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", "owner": "Azure/module-maintainers" }, "definitions": { - "managedIdentitiesType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } - } - }, - "nullable": true - }, - "networkAclsType": { - "type": "object", - "properties": { - "resourceAccessRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "metadata": { - "description": "Required. The ID of the tenant in which the resource resides in." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." - } - }, - "bypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "AzureServices, Logging", - "AzureServices, Logging, Metrics", - "AzureServices, Metrics", - "Logging", - "Logging, Metrics", - "Metrics", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." - } - }, - "virtualNetworkRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the virtual network rules." - } - }, - "ipRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the IP ACL rules." - } - }, - "defaultAction": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the default action of allow or deny when no other rules match." - } - } - } - }, - "privateEndpointType": { + "roleAssignmentType": { "type": "array", "items": { "type": "object", "properties": { - "name": { + "roleDefinitionIdOrName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of the private endpoint." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "location": { + "principalId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The location to deploy the private endpoint to." + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." } }, - "service": { + "principalType": { "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, "metadata": { - "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + "description": "Optional. The principal type of the assigned principal ID." } }, - "subnetResourceId": { + "description": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Optional. The description of the role assignment." } }, - "privateDnsZoneGroupName": { + "condition": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + "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\"." } }, - "privateDnsZoneResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], "nullable": true, "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Version of the condition." } }, - "isManualConnection": { - "type": "bool", + "delegatedManagedIdentityResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." + "description": "Optional. The Resource Id of the delegated managed identity resource." } - }, - "manualConnectionRequestMessage": { + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string", - "nullable": true, - "maxLength": 140, "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + "description": "Required. The name of the resource that is unique within a resource group." } }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." - } + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Required. Properties of private endpoint IP configurations." } - }, - "customNetworkInterfaceName": { + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Required. The name of the private link service connection." } }, - "tags": { + "properties": { "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Required. Properties of private link service connection." } } } }, "nullable": true }, - "diagnosticSettingType": { + "privateLinkServiceConnectionsType": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of diagnostic setting." + "description": "Required. The name of the private link service connection." } }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "description": "Required. Properties of private link service connection." } - }, - "eventHubName": { + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Required. Fqdn that resolves to private endpoint IP address." } }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "description": "Required. A list of private IP addresses of the private endpoint." } - } - } - }, - "nullable": true - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. Name of the Storage Account. Must be lower-case." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "kind": { - "type": "string", - "defaultValue": "StorageV2", - "allowedValues": [ - "Storage", - "StorageV2", - "BlobStorage", - "FileStorage", - "BlockBlobStorage" - ], - "metadata": { - "description": "Optional. Type of Storage Account to create." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Standard_GRS", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS", - "Standard_RAGRS", - "Standard_ZRS", - "Premium_LRS", - "Premium_ZRS", - "Standard_GZRS", - "Standard_RAGZRS" - ], - "metadata": { - "description": "Optional. Storage Account Sku Name." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "Hot", - "allowedValues": [ - "Premium", - "Hot", - "Cool" - ], - "metadata": { - "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." - } - }, - "largeFileSharesState": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." - } - }, - "azureFilesIdentityBasedAuthentication": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Provides the identity based authentication settings for Azure Files." - } - }, - "defaultToOAuthAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." - } - }, - "allowSharedKeyAccess": { - "type": "bool", - "defaultValue": true, + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", "metadata": { - "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + "description": "Required. Name of the private endpoint resource to create." } }, - "privateEndpoints": { - "$ref": "#/definitions/privateEndpointType", + "subnetResourceId": { + "type": "string", "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "managementPolicyRules": { + "applicationSecurityGroupResourceIds": { "type": "array", "nullable": true, "metadata": { - "description": "Optional. The Storage Account ManagementPolicies Rules." - } - }, - "networkAcls": { - "$ref": "#/definitions/networkAclsType", - "nullable": true, - "metadata": { - "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." - } - }, - "requireInfrastructureEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." - } - }, - "allowCrossTenantReplication": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allow or disallow cross AAD tenant object replication." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "customDomainName": { + "customNetworkInterfaceName": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { - "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, - "customDomainUseSubDomainName": { - "type": "bool", - "defaultValue": false, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", "metadata": { - "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } }, - "dnsEndpointType": { + "privateDnsZoneGroupName": { "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "AzureDnsZone", - "Standard" - ], - "metadata": { - "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." - } - }, - "blobServices": { - "type": "object", - "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", - "metadata": { - "description": "Optional. Blob service and containers to deploy." - } - }, - "fileServices": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. File service and shares to deploy." - } - }, - "queueServices": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Queue service and queues to create." - } - }, - "tableServices": { - "type": "object", - "defaultValue": {}, + "nullable": true, "metadata": { - "description": "Optional. Table service and tables to create." + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." } }, - "allowBlobPublicAccess": { - "type": "bool", - "defaultValue": false, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, "metadata": { - "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." } }, - "minimumTlsVersion": { + "location": { "type": "string", - "defaultValue": "TLS1_2", - "allowedValues": [ - "TLS1_0", - "TLS1_1", - "TLS1_2" - ], - "metadata": { - "description": "Optional. Set the minimum TLS version on request to storage." - } - }, - "enableHierarchicalNamespace": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." - } - }, - "enableSftp": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." - } - }, - "isLocalUserEnabled": { - "type": "bool", - "defaultValue": false, + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Enables local users feature, if set to true." + "description": "Optional. Location for all Resources." } }, - "enableNfsV3": { - "type": "bool", - "defaultValue": false, + "lock": { + "$ref": "#/definitions/lockType", "metadata": { - "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + "description": "Optional. The lock settings of the service." } }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Array of role assignments to create." } }, "tags": { "type": "object", "nullable": true, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Custom DNS configurations." } }, - "allowedCopyScope": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "AAD", - "PrivateLink" - ], + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." } }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "Enabled", - "Disabled" - ], + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + "description": "Optional. A grouping of information about the connection to the remote resource." } }, - "supportsHttpsTrafficOnly": { + "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "sasExpirationPeriod": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The SAS expiration period. DD.HH:MM:SS." - } - }, - "keyType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Account", - "Service" - ], - "metadata": { - "description": "Optional. The keyType to use with Queue & Table services." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "variables": { - "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } }, "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" - }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -33600,105 +28449,73 @@ } } }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" - }, - "storageAccount": { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2022-09-01", + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", "name": "[parameters('name')]", "location": "[parameters('location')]", - "kind": "[parameters('kind')]", - "sku": { - "name": "[parameters('skuName')]" - }, - "identity": "[variables('identity')]", "tags": "[parameters('tags')]", - "properties": { - "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", - "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", - "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", - "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", - "customDomain": { - "name": "[parameters('customDomainName')]", - "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" - }, - "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", - "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", - "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", - "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", - "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", - "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", - "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", - "isSftpEnabled": "[parameters('enableSftp')]", - "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", - "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", - "minimumTlsVersion": "[parameters('minimumTlsVersion')]", - "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", - "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", - "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" - }, - "dependsOn": [ - "cMKKeyVault", - "cMKKeyVault::cMKKey" - ] - }, - "storageAccount_diagnosticSettings": { - "copy": { - "name": "storageAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" } } ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" }, "dependsOn": [ - "storageAccount" + "privateEndpoint" ] }, - "storageAccount_privateEndpoints": { + "privateEndpoint_roleAssignments": { "copy": { - "name": "storageAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -33706,654 +28523,422 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" - }, - "privateDnsZoneGroupName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" - }, - "privateDnsZoneResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "privateEndpointName": { + "value": "[parameters('name')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "4120048060064073955" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "ipConfigurationsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true - }, - "manualPrivateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "privateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" }, - "customDnsConfigType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - } - }, - "nullable": true - } + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" }, "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { + "privateEndpointName": { "type": "string", "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." } }, - "applicationSecurityGroupResourceIds": { + "privateDNSResourceIds": { "type": "array", - "nullable": true, + "minLength": 1, + "maxLength": 5, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." } }, - "customNetworkInterfaceName": { + "name": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "$ref": "#/definitions/ipConfigurationsType", + "defaultValue": "default", "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Optional. The name of the private DNS zone group." } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" } - }, - "location": { + } + ], + "outputs": { + "name": { "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "$ref": "#/definitions/customDnsConfigType", - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." - } + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" }, - "privateLinkServiceConnections": { - "$ref": "#/definitions/privateLinkServiceConnectionsType", + "resourceId": { + "type": "string", "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource." - } + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "resourceGroupName": { + "type": "string", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "5572402757180298542" + }, + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." } }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" } } }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" - }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", + "enabled": { + "type": "bool", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "11244630631275470040" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDNSResourceIds": { - "type": "array", - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", - "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" - } - } - } - ] - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } + "description": "Optional. Enable or disable the category explicitly. Default is `true`." } } - }, - "dependsOn": [ - "privateEndpoint" - ] + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." } }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" - }, - "groupId": { - "type": "string", - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." } } } }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Protocol settings for file service." + } + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "defaultValue": { + "enabled": true, + "days": 7 + }, + "metadata": { + "description": "Optional. The service properties for soft delete." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + } + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, "dependsOn": [ - "storageAccount" + "fileServices" ] }, - "storageAccount_fileServices": { - "condition": "[not(empty(parameters('fileServices')))]", + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", + "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -34361,19 +28946,28 @@ "mode": "Incremental", "parameters": { "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { "value": "[parameters('name')]" }, - "diagnosticSettings": { - "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" }, - "protocolSettings": { - "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" }, - "shareDeleteRetentionPolicy": { - "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" }, - "shares": { - "value": "[tryGet(parameters('fileServices'), 'shares')]" + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" } }, "template": { @@ -34384,127 +28978,73 @@ "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "5572402757180298542" + "templateHash": "2846593244669729605" }, - "name": "Storage Account File Share Services", - "description": "This module deploys a Storage Account File Share Service.", + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share.", "owner": "Azure/module-maintainers" }, "definitions": { - "diagnosticSettingType": { + "roleAssignmentType": { "type": "array", "items": { "type": "object", "properties": { - "name": { + "roleDefinitionIdOrName": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, + "principalId": { + "type": "string", "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." } }, - "logAnalyticsDestinationType": { + "principalType": { "type": "string", "allowedValues": [ - "AzureDiagnostics", - "Dedicated" + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" ], "nullable": true, "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The principal type of the assigned principal ID." } }, - "storageAccountResourceId": { + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The description of the role assignment." } }, - "eventHubAuthorizationRuleResourceId": { + "condition": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "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\"." } }, - "eventHubName": { + "conditionVersion": { "type": "string", + "allowedValues": [ + "2.0" + ], "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. Version of the condition." } }, - "marketplacePartnerResourceId": { + "delegatedManagedIdentityResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "description": "Optional. The Resource Id of the delegated managed identity resource." } } } @@ -34520,550 +29060,295 @@ "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "name": { + "fileServicesName": { "type": "string", "defaultValue": "default", "metadata": { - "description": "Optional. The name of the file service." + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." } }, - "protocolSettings": { - "type": "object", - "defaultValue": {}, + "name": { + "type": "string", "metadata": { - "description": "Optional. Protocol settings for file service." + "description": "Required. The name of the file share to create." } }, - "shareDeleteRetentionPolicy": { - "type": "object", - "defaultValue": { - "enabled": true, - "days": 7 - }, + "accessTier": { + "type": "string", + "defaultValue": "TransactionOptimized", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], "metadata": { - "description": "Optional. The service properties for soft delete." + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." } }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", + "shareQuota": { + "type": "int", + "defaultValue": 5120, "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." } }, - "shares": { - "type": "array", - "nullable": true, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", "metadata": { - "description": "Optional. File shares to create." + "description": "Optional. Array of role assignments to create." } } }, "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2023-04-01", "name": "[parameters('storageAccountName')]" }, - "fileServices": { - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", "properties": { - "protocolSettings": "[parameters('protocolSettings')]", - "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" } }, - "fileServices_diagnosticSettings": { - "copy": { - "name": "fileServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "fileServices" - ] - }, - "fileServices_shares": { - "copy": { - "name": "fileServices_shares", - "count": "[length(coalesce(parameters('shares'), createArray()))]" - }, + "fileShare_roleAssignments": { + "condition": "[not(empty(parameters('roleAssignments')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "fileServicesName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" - }, - "accessTier": { - "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" - }, - "enabledProtocols": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" - }, - "rootSquash": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" - }, - "shareQuota": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + "fileShareResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" }, "roleAssignments": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + "value": "[parameters('roleAssignments')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "2846593244669729605" - }, - "name": "Storage Account File Shares", - "description": "This module deploys a Storage Account File Share.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true + "templateHash": "11422901802944437310" } }, "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "fileServicesName": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share to create." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "TransactionOptimized", - "allowedValues": [ - "Premium", - "Hot", - "Cool", - "TransactionOptimized" - ], - "metadata": { - "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." - } - }, - "shareQuota": { - "type": "int", - "defaultValue": 5120, - "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." - } - }, - "enabledProtocols": { - "type": "string", - "defaultValue": "SMB", - "allowedValues": [ - "NFS", - "SMB" - ], + "roleAssignments": { + "type": "array", "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + "description": "Optional. Array of role assignments to create." } }, - "rootSquash": { + "fileShareResourceId": { "type": "string", - "defaultValue": "NoRootSquash", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Required. The resource id of the file share to assign the roles to." } } }, - "resources": { - "storageAccount::fileService": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" - }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-04-01", - "name": "[parameters('storageAccountName')]" - }, - "fileShare": { - "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2023-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", - "properties": { - "accessTier": "[parameters('accessTier')]", - "shareQuota": "[parameters('shareQuota')]", - "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", - "enabledProtocols": "[parameters('enabledProtocols')]" - } + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "description": "[[parameters('description')]", + "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] }, - "fileShare_roleAssignments": { - "condition": "[not(empty(parameters('roleAssignments')))]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": [ + { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", + "apiVersion": "2021-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", "properties": { + "mode": "Incremental", "expressionEvaluationOptions": { - "scope": "inner" + "scope": "Outer" }, - "mode": "Incremental", + "template": "[variables('$fxv#0')]", "parameters": { - "fileShareResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + "scope": { + "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "11422901802944437310" - } + "name": { + "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" }, - "parameters": { - "roleAssignments": { - "type": "array", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "fileShareResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the file share to assign the roles to." - } - } + "roleDefinitionId": { + "value": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]" }, - "variables": { - "$fxv#0": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "scope": { - "type": "string", - "metadata": { - "description": "Required. The scope to deploy the role assignment to." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The role definition Id to assign." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "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\"" - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "defaultValue": "2.0", - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[[parameters('scope')]", - "name": "[[parameters('name')]", - "properties": { - "roleDefinitionId": "[[parameters('roleDefinitionId')]", - "principalId": "[[parameters('principalId')]", - "description": "[[parameters('description')]", - "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", - "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" - } - } - ] - }, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + "principalId": { + "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "condition": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": { + "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" }, - "resources": [ - { - "copy": { - "name": "fileShare_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2021-04-01", - "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "mode": "Incremental", - "expressionEvaluationOptions": { - "scope": "Outer" - }, - "template": "[variables('$fxv#0')]", - "parameters": { - "scope": { - "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" - }, - "name": { - "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" - }, - "roleDefinitionId": { - "value": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]" - }, - "principalId": { - "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" - }, - "principalType": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" - }, - "description": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" - }, - "condition": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" - }, - "conditionVersion": { - "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" - }, - "delegatedManagedIdentityResourceId": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - } - } - } - } - ] + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } } - }, - "dependsOn": [ - "fileShare" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed file share." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed file share." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed file share." - }, - "value": "[resourceGroup().name]" + } } - } + ] } }, "dependsOn": [ - "fileServices", - "storageAccount" + "fileShare" ] } }, @@ -35071,717 +29356,1624 @@ "name": { "type": "string", "metadata": { - "description": "The name of the deployed file share service." + "description": "The name of the deployed file share." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed file share service." + "description": "The resource ID of the deployed file share." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed file share service." + "description": "The resource group of the deployed file share." }, "value": "[resourceGroup().name]" } } } }, - "dependsOn": [ - "storageAccount" - ] + "dependsOn": [ + "fileServices", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed storage account." + }, + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2022-09-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[not(equals(parameters('identityServiceProvider'), 'EntraID'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Add-{0}-Storage-Setup-{1}', parameters('storagePurpose'), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "virtualMachineName": { + "value": "[parameters('managementVmName')]" + }, + "file": { + "value": "[parameters('storageToDomainScript')]" + }, + "scriptArguments": { + "value": "[variables('varStorageToDomainScriptArgs')]" + }, + "adminUserPassword": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.KeyVault/vaults', parameters('wrklKvName'))), 'secretName', 'vmLocalUserPassword')), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.KeyVault/vaults', parameters('wrklKvName'))), 'secretName', 'domainJoinUserPassword')))]", + "baseScriptUri": { + "value": "[parameters('storageToDomainScriptUri')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "7337889415739790800" + }, + "name": "AVD LZA storage", + "description": "Configures domain join settings on storage account via VM custom script extension", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Virtual machine name." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy compute services." + } + }, + "baseScriptUri": { + "type": "string", + "metadata": { + "description": "Location for the AVD agent installation package." + } + }, + "file": { + "type": "string" + }, + "scriptArguments": { + "type": "string", + "metadata": { + "description": "Arguments for domain join script." + } + }, + "adminUserPassword": { + "type": "securestring", + "metadata": { + "description": "Domain join user password." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('VM-Ext-AVM-{0}', parameters('time'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "AzureFilesDomainJoin" + }, + "virtualMachineName": { + "value": "[parameters('virtualMachineName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publisher": { + "value": "Microsoft.Compute" + }, + "type": { + "value": "CustomScriptExtension" + }, + "typeHandlerVersion": { + "value": "1.10" + }, + "autoUpgradeMinorVersion": { + "value": true + }, + "enableAutomaticUpgrade": { + "value": false + }, + "settings": { + "value": {} + }, + "protectedSettings": { + "value": { + "fileUris": "[array(parameters('baseScriptUri'))]", + "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -File {0} {1} -AdminUserPassword {2} -verbose', parameters('file'), parameters('scriptArguments'), parameters('adminUserPassword'))]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "12041352154594223618" + }, + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location the extension is deployed to." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the extension handler publisher." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } + }, + "typeHandlerVersion": { + "type": "string", + "metadata": { + "description": "Required. Specifies the version of the script handler." + } + }, + "autoUpgradeMinorVersion": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } + } + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time')))]" + ] + } + ], + "outputs": { + "storageAccountResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))), '2022-09-01').outputs.resourceId.value]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]" + ] + }, + { + "condition": "[variables('varCreateAppAttachDeployment')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-AppA-{0}', parameters('time'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storagePurpose": { + "value": "AppAttach" + }, + "vmLocalUserName": { + "value": "[parameters('avdVmLocalUserName')]" + }, + "fileShareName": { + "value": "[variables('varAppAttachFileShareName')]" + }, + "fileShareMultichannel": "[if(equals(parameters('appAttachStoragePerformance'), 'Premium'), createObject('value', true()), createObject('value', false()))]", + "storageSku": { + "value": "[variables('varAppAttachStorageSku')]" + }, + "fileShareQuotaSize": { + "value": "[parameters('appAttachFileShareQuotaSize')]" + }, + "storageAccountFqdn": { + "value": "[variables('varAppAttachStorageFqdn')]" + }, + "storageAccountName": { + "value": "[variables('varAppAttachStorageName')]" + }, + "storageToDomainScript": { + "value": "[variables('varStorageToDomainScript')]" + }, + "storageToDomainScriptUri": { + "value": "[variables('varStorageToDomainScriptUri')]" + }, + "identityServiceProvider": { + "value": "[parameters('avdIdentityServiceProvider')]" + }, + "dscAgentPackageLocation": { + "value": "[variables('varStorageAzureFilesDscAgentPackageLocation')]" + }, + "storageCustomOuPath": { + "value": "[variables('varStorageCustomOuPath')]" + }, + "managementVmName": { + "value": "[variables('varManagementVmName')]" + }, + "deployPrivateEndpoint": { + "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" + }, + "ouStgPath": { + "value": "[variables('varOuStgPath')]" + }, + "managedIdentityClientId": "[if(and(variables('varCreateStorageDeployment'), not(equals(parameters('avdIdentityServiceProvider'), 'EntraID'))), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time'))), '2022-09-01').outputs.managedIdentityStorageClientId.value), createObject('value', ''))]", + "securityPrincipalName": { + "value": "[variables('varSecurityPrincipalName')]" + }, + "domainJoinUserName": { + "value": "[parameters('avdDomainJoinUserName')]" + }, + "wrklKvName": { + "value": "[variables('varWrklKvName')]" + }, + "serviceObjectsRgName": { + "value": "[variables('varServiceObjectsRgName')]" + }, + "identityDomainName": { + "value": "[parameters('identityDomainName')]" + }, + "identityDomainGuid": { + "value": "[parameters('identityDomainGuid')]" + }, + "location": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostLocation')), createObject('value', parameters('avdManagementPlaneLocation')))]", + "storageObjectsRgName": { + "value": "[variables('varStorageObjectsRgName')]" + }, + "privateEndpointSubnetId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName'))), createObject('value', parameters('existingVnetPrivateEndpointSubnetResourceId')))]", + "vmsSubnetId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", + "vnetPrivateDnsZoneFilesId": "[if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.azureFilesDnsZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneFilesId')))]", + "workloadSubsId": { + "value": "[parameters('avdWorkloadSubsId')]" + }, + "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]", + "alaWorkspaceResourceId": "[if(parameters('avdDeployMonitoring'), if(parameters('deployAlaWorkspace'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.avdAlaWorkspaceResourceId.value), createObject('value', parameters('alaExistingWorkspaceResourceId'))), createObject('value', ''))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "4402521403689705705" + }, + "name": "AVD LZA storage", + "description": "This module deploys storage account, azure files. domain join logic", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "workloadSubsId": { + "type": "string", + "metadata": { + "description": "AVD workload subscription ID, multiple subscriptions scenario." + } + }, + "storageObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name for Azure Files." + } + }, + "identityServiceProvider": { + "type": "string", + "metadata": { + "description": "Required, The service providing domain services for Azure Virtual Desktop." + } + }, + "serviceObjectsRgName": { + "type": "string", + "metadata": { + "description": "Resource Group Name for management VM." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Storage account name." + } + }, + "fileShareName": { + "type": "string", + "metadata": { + "description": "Storage account file share name." + } + }, + "privateEndpointSubnetId": { + "type": "string", + "metadata": { + "description": "Private endpoint subnet ID." + } + }, + "vmsSubnetId": { + "type": "string", + "metadata": { + "description": "VMs subnet ID." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy resources." + } + }, + "fileShareMultichannel": { + "type": "bool", + "metadata": { + "description": "File share SMB multichannel." + } + }, + "identityDomainName": { + "type": "string", + "metadata": { + "description": "Identity domain name." + } + }, + "identityDomainGuid": { + "type": "string", + "metadata": { + "description": "AD domain GUID." + } + }, + "wrklKvName": { + "type": "string", + "metadata": { + "description": "Keyvault name to get credentials from." + } + }, + "domainJoinUserName": { + "type": "string", + "metadata": { + "description": "AVD session host domain join credentials." + } + }, + "vmLocalUserName": { + "type": "string", + "metadata": { + "description": "AVD session host local admin credentials." + } + }, + "storageSku": { + "type": "string", + "metadata": { + "description": "Azure Files storage account SKU." + } + }, + "fileShareQuotaSize": { + "type": "int", + "metadata": { + "description": "*Azure File share quota" + } + }, + "vnetPrivateDnsZoneFilesId": { + "type": "string", + "metadata": { + "description": "Use Azure private DNS zones for private endpoints." + } + }, + "storageToDomainScript": { + "type": "string", + "metadata": { + "description": "Script name for adding storage account to Active Directory." + } + }, + "storageToDomainScriptUri": { + "type": "string", + "metadata": { + "description": "URI for the script for adding the storage account to Active Directory." + } + }, + "tags": { + "type": "object", + "metadata": { + "description": "Tags to be applied to resources" + } + }, + "managementVmName": { + "type": "string", + "metadata": { + "description": "Name for management virtual machine. for tools and to join Azure Files to domain." + } + }, + "deployPrivateEndpoint": { + "type": "bool", + "metadata": { + "description": "Optional. AVD Accelerator will deploy with private endpoints by default." + } + }, + "alaWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Log analytics workspace for diagnostic logs." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + }, + "storagePurpose": { + "type": "string", + "metadata": { + "description": "Sets purpose of the storage account." + } + }, + "dscAgentPackageLocation": { + "type": "string", + "metadata": { + "description": "Sets location of DSC Agent." + } + }, + "storageCustomOuPath": { + "type": "string", + "metadata": { + "description": "Custom OU path for storage." + } + }, + "ouStgPath": { + "type": "string", + "metadata": { + "description": "OU Storage Path" + } + }, + "managedIdentityClientId": { + "type": "string", + "metadata": { + "description": "Managed Identity Client ID" + } + }, + "securityPrincipalName": { + "type": "string", + "metadata": { + "description": "Identity name array to grant RBAC role to access AVD application group and NTFS permissions." + } + }, + "storageAccountFqdn": { + "type": "string", + "metadata": { + "description": "storage account FDQN." + } + } + }, + "variables": { + "varAzureCloudName": "[environment().name]", + "varWrklStoragePrivateEndpointName": "[format('pe-{0}-file', parameters('storageAccountName'))]", + "varSecurityPrincipalName": "[if(not(empty(parameters('securityPrincipalName'))), parameters('securityPrincipalName'), 'none')]", + "varAdminUserName": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('vmLocalUserName'), parameters('domainJoinUserName'))]", + "varStorageToDomainScriptArgs": "[format('-DscPath {0} -StorageAccountName {1} -StorageAccountRG {2} -StoragePurpose {3} -DomainName {4} -IdentityServiceProvider {5} -AzureCloudEnvironment {6} -SubscriptionId {7} -AdminUserName {8} -CustomOuPath {9} -OUName {10} -ShareName {11} -ClientId {12} -SecurityPrincipalName \"{13}\" -StorageAccountFqdn {14} ', parameters('dscAgentPackageLocation'), parameters('storageAccountName'), parameters('storageObjectsRgName'), parameters('storagePurpose'), parameters('identityDomainName'), parameters('identityServiceProvider'), variables('varAzureCloudName'), parameters('workloadSubsId'), variables('varAdminUserName'), parameters('storageCustomOuPath'), parameters('ouStgPath'), parameters('fileShareName'), parameters('managedIdentityClientId'), variables('varSecurityPrincipalName'), parameters('storageAccountFqdn'))]", + "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('storageAccountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": { + "value": "[parameters('storageSku')]" + }, + "allowBlobPublicAccess": { + "value": false + }, + "publicNetworkAccess": "[if(parameters('deployPrivateEndpoint'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", + "kind": "[if(or(equals(parameters('storageSku'), 'Premium_LRS'), equals(parameters('storageSku'), 'Premium_ZRS')), createObject('value', 'FileStorage'), createObject('value', 'StorageV2'))]", + "largeFileSharesState": "[if(or(equals(parameters('storageSku'), 'Standard_LRS'), equals(parameters('storageSku'), 'Standard_ZRS')), createObject('value', 'Enabled'), createObject('value', 'Disabled'))]", + "azureFilesIdentityBasedAuthentication": "[if(not(equals(parameters('identityServiceProvider'), 'EntraID')), createObject('value', createObject('directoryServiceOptions', if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDS', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), 'AADKERB', 'none')), 'activeDirectoryProperties', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), createObject('domainGuid', parameters('identityDomainGuid'), 'domainName', parameters('identityDomainName')), createObject()))), createObject('value', null()))]", + "accessTier": { + "value": "Hot" + }, + "networkAcls": "[if(parameters('deployPrivateEndpoint'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', parameters('vmsSubnetId'), 'action', 'Allow')), 'ipRules', createArray())))]", + "fileServices": { + "value": { + "shares": [ + { + "name": "[parameters('fileShareName')]", + "shareQuota": "[mul(parameters('fileShareQuotaSize'), 100)]" + } + ], + "protocolSettings": "[if(parameters('fileShareMultichannel'), createObject('smb', createObject('multichannel', createObject('enabled', parameters('fileShareMultichannel')))), createObject())]", + "diagnosticSettings": "[variables('varDiagnosticSettings')]" + } + }, + "privateEndpoints": "[if(parameters('deployPrivateEndpoint'), createObject('value', createArray(createObject('name', variables('varWrklStoragePrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointSubnetId'), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklStoragePrivateEndpointName')), 'service', 'file', 'privateDnsZoneGroupName', split(parameters('vnetPrivateDnsZoneFilesId'), '/')[8], 'privateDnsZoneResourceIds', createArray(parameters('vnetPrivateDnsZoneFilesId'))))), createObject('value', createArray()))]", + "tags": { + "value": "[parameters('tags')]" + }, + "diagnosticSettings": { + "value": "[variables('varDiagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "15994741654178645865" + }, + "name": "Storage Accounts", + "description": "This module deploys a Storage Account.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + } + } } }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed storage account." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed storage account." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed storage account." - }, - "value": "[resourceGroup().name]" - }, - "primaryBlobEndpoint": { - "type": "string", - "metadata": { - "description": "The primary blob endpoint reference if blob services are deployed." - }, - "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('storageAccount', '2022-09-01', 'full').location]" - } + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." } } } }, - { - "condition": "[not(equals(parameters('identityServiceProvider'), 'EntraID'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Add-{0}-Storage-Setup-{1}', parameters('storagePurpose'), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } }, - "virtualMachineName": { - "value": "[parameters('managementVmName')]" + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } }, - "file": { - "value": "[parameters('storageToDomainScript')]" + "service": { + "type": "string", + "metadata": { + "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + } }, - "scriptArguments": { - "value": "[variables('varStorageToDomainScriptArgs')]" + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } }, - "adminUserPassword": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'vmLocalUserPassword')), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'domainJoinUserPassword')))]", - "baseScriptUri": { - "value": "[parameters('storageToDomainScriptUri')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "7337889415739790800" - }, - "name": "AVD LZA storage", - "description": "Configures domain join settings on storage account via VM custom script extension", - "owner": "Azure/avdaccelerator" + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + } }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Virtual machine name." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy compute services." - } - }, - "baseScriptUri": { - "type": "string", - "metadata": { - "description": "Location for the AVD agent installation package." - } - }, - "file": { + "privateDnsZoneResourceIds": { + "type": "array", + "items": { "type": "string" }, - "scriptArguments": { - "type": "string", - "metadata": { - "description": "Arguments for domain join script." - } - }, - "adminUserPassword": { - "type": "securestring", - "metadata": { - "description": "Domain join user password." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." } }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('VM-Ext-AVM-{0}', parameters('time'))]", + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Manual PrivateLink Service Connections." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "AzureFilesDomainJoin" - }, - "virtualMachineName": { - "value": "[parameters('virtualMachineName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "CustomScriptExtension" - }, - "typeHandlerVersion": { - "value": "1.10" - }, - "autoUpgradeMinorVersion": { - "value": true - }, - "enableAutomaticUpgrade": { - "value": false - }, - "settings": { - "value": {} + "ipAddresses": { + "type": "array", + "items": { + "type": "string" }, - "protectedSettings": { - "value": { - "fileUris": "[array(parameters('baseScriptUri'))]", - "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -File {0} {1} -AdminUserPassword {2} -verbose', parameters('file'), parameters('scriptArguments'), parameters('adminUserPassword'))]" - } + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { "type": "string", "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." } }, - "typeHandlerVersion": { + "memberName": { "type": "string", "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." } }, - "forceUpdateTag": { + "privateIPAddress": { "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" + "description": "Required. A private ip address obtained from the private endpoint's subnet." } } }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." } } } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." } - ] + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } } }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time')))]" - ] - } - ], - "outputs": { - "storageAccountResourceId": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))), '2022-09-01').outputs.resourceId.value]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]" - ] - }, - { - "condition": "[and(parameters('createFslogixDeployment'), not(equals(parameters('storageService'), 'ANF')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-AppA-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storagePurpose": { - "value": "AppAttach" - }, - "vmLocalUserName": { - "value": "[parameters('vmLocalUserName')]" - }, - "fileShareName": { - "value": "[variables('varAppAttachFileShareName')]" - }, - "fileShareMultichannel": "[if(equals(variables('varAppAttachStoragePerformance'), 'Premium'), createObject('value', true()), createObject('value', false()))]", - "storageSku": { - "value": "[variables('varAppAttachStorageSku')]" - }, - "fileShareQuotaSize": { - "value": "[parameters('appAttachFileShareQuotaSize')]" - }, - "storageAccountFqdn": { - "value": "[variables('varAppAttachStorageFqdn')]" - }, - "storageAccountName": { - "value": "[variables('varAppAttachStorageName')]" - }, - "storageToDomainScript": { - "value": "[variables('varStorageToDomainScript')]" - }, - "storageToDomainScriptUri": { - "value": "[variables('varStorageToDomainScriptUri')]" - }, - "identityServiceProvider": { - "value": "[parameters('identityServiceProvider')]" - }, - "dscAgentPackageLocation": { - "value": "[variables('varStorageAzureFilesDscAgentPackageLocation')]" - }, - "storageCustomOuPath": { - "value": "[variables('varStorageCustomOuPath')]" - }, - "managementVmName": { - "value": "[variables('varManagementVmName')]" - }, - "deployPrivateEndpoint": { - "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" - }, - "storageOuPath": { - "value": "[variables('varOuStgPath')]" - }, - "managedIdentityClientId": { - "value": "[parameters('managedIdentityClientId')]" - }, - "securityPrincipalName": { - "value": "[parameters('securityPrincipalName')]" - }, - "domainJoinUserName": { - "value": "[parameters('domainJoinUserName')]" - }, - "keyVaultResourceId": { - "value": "[parameters('keyVaultResourceId')]" - }, - "serviceObjectsRgName": { - "value": "[parameters('serviceObjectsRgName')]" - }, - "identityDomainName": { - "value": "[parameters('identityDomainName')]" - }, - "identityDomainGuid": { - "value": "[parameters('identityDomainGuid')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "storageObjectsRgName": { - "value": "[parameters('storageObjectsRgName')]" - }, - "privateEndpointSubnetResourceId": { - "value": "[parameters('privateEndpointSubnetResourceId')]" - }, - "vmsSubnetResourceId": { - "value": "[parameters('vmsSubnetResourceId')]" - }, - "privateDnsZoneFilesResourceId": { - "value": "[parameters('privateDnsZoneFilesResourceId')]" - }, - "subId": { - "value": "[parameters('subId')]" - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]", - "alaWorkspaceResourceId": { - "value": "[parameters('alaWorkspaceResourceId')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4958601852198550361" + "nullable": true }, - "name": "AVD LZA storage", - "description": "This module deploys storage account, azure files. domain join logic", - "owner": "Azure/avdaccelerator" + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + } }, "parameters": { - "subId": { + "name": { "type": "string", + "maxLength": 24, "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." + "description": "Required. Name of the Storage Account. Must be lower-case." } }, - "storageObjectsRgName": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Resource Group Name for Azure Files." + "description": "Optional. Location for all resources." } }, - "identityServiceProvider": { - "type": "string", + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", "metadata": { - "description": "Required, The service providing domain services for Azure Virtual Desktop." + "description": "Optional. The managed identity definition for this resource." } }, - "serviceObjectsRgName": { + "kind": { "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], "metadata": { - "description": "Resource Group Name for management VM." + "description": "Optional. Type of Storage Account to create." } }, - "storageAccountName": { + "skuName": { "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS", + "Premium_ZRS", + "Standard_GZRS", + "Standard_RAGZRS" + ], "metadata": { - "description": "Storage account name." + "description": "Optional. Storage Account Sku Name." } }, - "fileShareName": { + "accessTier": { "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool" + ], "metadata": { - "description": "Storage account file share name." + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." } }, - "privateEndpointSubnetResourceId": { + "largeFileSharesState": { "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], "metadata": { - "description": "Private endpoint subnet ID." + "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." } }, - "vmsSubnetResourceId": { - "type": "string", + "azureFilesIdentityBasedAuthentication": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "VMs subnet ID." + "description": "Optional. Provides the identity based authentication settings for Azure Files." } }, - "location": { - "type": "string", + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Location where to deploy resources." + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." } }, - "fileShareMultichannel": { + "allowSharedKeyAccess": { "type": "bool", + "defaultValue": true, "metadata": { - "description": "File share SMB multichannel." + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." } }, - "identityDomainName": { - "type": "string", + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", "metadata": { - "description": "Identity domain name." + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." } }, - "identityDomainGuid": { - "type": "string", + "managementPolicyRules": { + "type": "array", + "nullable": true, "metadata": { - "description": "AD domain GUID." + "description": "Optional. The Storage Account ManagementPolicies Rules." } }, - "keyVaultResourceId": { - "type": "string", + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, "metadata": { - "description": "Key Vault Resource ID." + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." } }, - "domainJoinUserName": { - "type": "string", + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "AVD session host domain join credentials." + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." } }, - "vmLocalUserName": { - "type": "string", + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "AVD session host local admin credentials." + "description": "Optional. Allow or disallow cross AAD tenant object replication." } }, - "storageSku": { + "customDomainName": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Azure Files storage account SKU." + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." } }, - "fileShareQuotaSize": { - "type": "int", + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "*Azure File share quota" + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." } }, - "privateDnsZoneFilesResourceId": { + "dnsEndpointType": { "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AzureDnsZone", + "Standard" + ], "metadata": { - "description": "Use Azure private DNS zones for private endpoints." + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." } }, - "storageToDomainScript": { - "type": "string", + "blobServices": { + "type": "object", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", "metadata": { - "description": "Script name for adding storage account to Active Directory." + "description": "Optional. Blob service and containers to deploy." } }, - "storageToDomainScriptUri": { - "type": "string", + "fileServices": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "URI for the script for adding the storage account to Active Directory." + "description": "Optional. File service and shares to deploy." } }, - "tags": { + "queueServices": { "type": "object", "defaultValue": {}, "metadata": { - "description": "Tags to be applied to resources" + "description": "Optional. Queue service and queues to create." } }, - "managementVmName": { - "type": "string", + "tableServices": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Name for management virtual machine. for tools and to join Azure Files to domain." + "description": "Optional. Table service and tables to create." } }, - "deployPrivateEndpoint": { + "allowBlobPublicAccess": { "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. AVD Accelerator will deploy with private endpoints by default." + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." } }, - "alaWorkspaceResourceId": { + "minimumTlsVersion": { "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_0", + "TLS1_1", + "TLS1_2" + ], "metadata": { - "description": "Log analytics workspace for diagnostic logs." + "description": "Optional. Set the minimum TLS version on request to storage." } }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", + "enableHierarchicalNamespace": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." } }, - "storagePurpose": { - "type": "string", + "enableSftp": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Sets purpose of the storage account." + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." } }, - "dscAgentPackageLocation": { - "type": "string", + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Sets location of DSC Agent." + "description": "Optional. Enables local users feature, if set to true." } }, - "storageCustomOuPath": { - "type": "string", + "enableNfsV3": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Custom OU path for storage." + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." } }, - "storageOuPath": { + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "allowedCopyScope": { "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AAD", + "PrivateLink" + ], "metadata": { - "description": "OU Storage Path" + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." } }, - "managedIdentityClientId": { + "publicNetworkAccess": { "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Managed Identity Client ID" + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." } }, - "securityPrincipalName": { + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Identity name array to grant RBAC role to access AVD application group and NTFS permissions." + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." } }, - "storageAccountFqdn": { + "keyType": { "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], "metadata": { - "description": "storage account FDQN." + "description": "Optional. The keyType to use with Queue & Table services." } } }, "variables": { - "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", - "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", - "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]", - "varAzureCloudName": "[environment().name]", - "varWrklStoragePrivateEndpointName": "[format('pe-{0}-file', parameters('storageAccountName'))]", - "varSecurityPrincipalName": "[if(not(empty(parameters('securityPrincipalName'))), parameters('securityPrincipalName'), 'none')]", - "varAdminUserName": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('vmLocalUserName'), parameters('domainJoinUserName'))]", - "varStorageToDomainScriptArgs": "[format('-DscPath {0} -StorageAccountName {1} -StorageAccountRG {2} -StoragePurpose {3} -DomainName {4} -IdentityServiceProvider {5} -AzureCloudEnvironment {6} -SubscriptionId {7} -AdminUserName {8} -CustomOuPath {9} -OUName {10} -ShareName {11} -ClientId {12} -SecurityPrincipalName \"{13}\" -StorageAccountFqdn {14} ', parameters('dscAgentPackageLocation'), parameters('storageAccountName'), parameters('storageObjectsRgName'), parameters('storagePurpose'), parameters('identityDomainName'), parameters('identityServiceProvider'), variables('varAzureCloudName'), parameters('subId'), variables('varAdminUserName'), parameters('storageCustomOuPath'), parameters('storageOuPath'), parameters('fileShareName'), parameters('managedIdentityClientId'), variables('varSecurityPrincipalName'), parameters('storageAccountFqdn'))]", - "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]" + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" }, - "resources": [ - { + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", + "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", + "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", + "customDomain": { + "name": "[parameters('customDomainName')]", + "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" + }, + "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", + "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", + "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", + "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", + "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", + "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", + "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", + "isSftpEnabled": "[parameters('enableSftp')]", + "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", + "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", + "minimumTlsVersion": "[parameters('minimumTlsVersion')]", + "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", + "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKKeyVault::cMKKey" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_privateEndpoints": { + "copy": { + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subId'))]", - "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", + "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -35789,772 +30981,418 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('storageAccountName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "skuName": { - "value": "[parameters('storageSku')]" - }, - "allowBlobPublicAccess": { - "value": false - }, - "publicNetworkAccess": "[if(parameters('deployPrivateEndpoint'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "kind": "[if(or(equals(parameters('storageSku'), 'Premium_LRS'), equals(parameters('storageSku'), 'Premium_ZRS')), createObject('value', 'FileStorage'), createObject('value', 'StorageV2'))]", - "largeFileSharesState": "[if(or(equals(parameters('storageSku'), 'Standard_LRS'), equals(parameters('storageSku'), 'Standard_ZRS')), createObject('value', 'Enabled'), createObject('value', 'Disabled'))]", - "azureFilesIdentityBasedAuthentication": "[if(not(equals(parameters('identityServiceProvider'), 'EntraID')), createObject('value', createObject('directoryServiceOptions', if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDS', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), 'AADKERB', 'none')), 'activeDirectoryProperties', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), createObject('domainGuid', parameters('identityDomainGuid'), 'domainName', parameters('identityDomainName')), createObject()))), createObject('value', null()))]", - "accessTier": { - "value": "Hot" + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" }, - "networkAcls": "[if(parameters('deployPrivateEndpoint'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', parameters('vmsSubnetResourceId'), 'action', 'Allow')), 'ipRules', createArray())))]", - "fileServices": { - "value": { - "shares": [ - { - "name": "[parameters('fileShareName')]", - "shareQuota": "[parameters('fileShareQuotaSize')]" - } - ], - "protocolSettings": "[if(parameters('fileShareMultichannel'), createObject('smb', createObject('multichannel', createObject('enabled', parameters('fileShareMultichannel')))), createObject())]", - "diagnosticSettings": "[variables('varDiagnosticSettings')]" - } + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" }, - "privateEndpoints": "[if(parameters('deployPrivateEndpoint'), createObject('value', createArray(createObject('name', variables('varWrklStoragePrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklStoragePrivateEndpointName')), 'service', 'file', 'privateDnsZoneGroupName', split(parameters('privateDnsZoneFilesResourceId'), '/')[8], 'privateDnsZoneResourceIds', createArray(parameters('privateDnsZoneFilesResourceId'))))), createObject('value', createArray()))]", - "tags": { - "value": "[parameters('tags')]" + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "15994741654178645865" - }, - "name": "Storage Accounts", - "description": "This module deploys a Storage Account.", - "owner": "Azure/module-maintainers" + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" }, - "definitions": { - "managedIdentitiesType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } - } - }, - "nullable": true - }, - "networkAclsType": { - "type": "object", - "properties": { - "resourceAccessRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "metadata": { - "description": "Required. The ID of the tenant in which the resource resides in." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." - } - }, - "bypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "AzureServices, Logging", - "AzureServices, Logging, Metrics", - "AzureServices, Metrics", - "Logging", - "Logging, Metrics", - "Metrics", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." - } - }, - "virtualNetworkRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the virtual network rules." - } - }, - "ipRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the IP ACL rules." - } - }, - "defaultAction": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the default action of allow or deny when no other rules match." - } - } - } + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "4120048060064073955" }, - "privateEndpointType": { + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { "type": "array", "items": { "type": "object", "properties": { - "name": { + "roleDefinitionIdOrName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of the private endpoint." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "location": { + "principalId": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The location to deploy the private endpoint to." + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." } }, - "service": { + "principalType": { "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, "metadata": { - "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + "description": "Optional. The principal type of the assigned principal ID." } }, - "subnetResourceId": { + "description": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + "description": "Optional. The description of the role assignment." } }, - "privateDnsZoneGroupName": { + "condition": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + "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\"." } }, - "privateDnsZoneResourceIds": { - "type": "array", - "items": { - "type": "string" - }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], "nullable": true, "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. Version of the condition." } }, - "isManualConnection": { - "type": "bool", + "delegatedManagedIdentityResourceId": { + "type": "string", "nullable": true, "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." + "description": "Optional. The Resource Id of the delegated managed identity resource." } - }, - "manualConnectionRequestMessage": { + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string", - "nullable": true, - "maxLength": 140, "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + "description": "Required. The name of the resource that is unique within a resource group." } }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." - } + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." } } }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + "description": "Required. Properties of private endpoint IP configurations." } - }, - "customNetworkInterfaceName": { + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "Required. The name of the private link service connection." } }, - "tags": { + "properties": { "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Required. Properties of private link service connection." } } } }, "nullable": true }, - "diagnosticSettingType": { + "privateLinkServiceConnectionsType": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of diagnostic setting." + "description": "Required. The name of the private link service connection." } }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." } } }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "description": "Required. Properties of private link service connection." } - }, - "eventHubName": { + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Required. Fqdn that resolves to private endpoint IP address." } }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "description": "Required. A list of private IP addresses of the private endpoint." } } } }, "nullable": true - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." - } - } - }, - "nullable": true } }, "parameters": { "name": { "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. Name of the Storage Account. Must be lower-case." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "kind": { - "type": "string", - "defaultValue": "StorageV2", - "allowedValues": [ - "Storage", - "StorageV2", - "BlobStorage", - "FileStorage", - "BlockBlobStorage" - ], - "metadata": { - "description": "Optional. Type of Storage Account to create." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Standard_GRS", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS", - "Standard_RAGRS", - "Standard_ZRS", - "Premium_LRS", - "Premium_ZRS", - "Standard_GZRS", - "Standard_RAGZRS" - ], - "metadata": { - "description": "Optional. Storage Account Sku Name." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "Hot", - "allowedValues": [ - "Premium", - "Hot", - "Cool" - ], "metadata": { - "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + "description": "Required. Name of the private endpoint resource to create." } }, - "largeFileSharesState": { + "subnetResourceId": { "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." - } - }, - "azureFilesIdentityBasedAuthentication": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Provides the identity based authentication settings for Azure Files." - } - }, - "defaultToOAuthAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." - } - }, - "allowSharedKeyAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." - } - }, - "privateEndpoints": { - "$ref": "#/definitions/privateEndpointType", "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "managementPolicyRules": { + "applicationSecurityGroupResourceIds": { "type": "array", "nullable": true, "metadata": { - "description": "Optional. The Storage Account ManagementPolicies Rules." - } - }, - "networkAcls": { - "$ref": "#/definitions/networkAclsType", - "nullable": true, - "metadata": { - "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." - } - }, - "requireInfrastructureEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." - } - }, - "allowCrossTenantReplication": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allow or disallow cross AAD tenant object replication." - } - }, - "customDomainName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." - } - }, - "customDomainUseSubDomainName": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." - } - }, - "dnsEndpointType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "AzureDnsZone", - "Standard" - ], - "metadata": { - "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." - } - }, - "blobServices": { - "type": "object", - "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", - "metadata": { - "description": "Optional. Blob service and containers to deploy." - } - }, - "fileServices": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. File service and shares to deploy." - } - }, - "queueServices": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Queue service and queues to create." - } - }, - "tableServices": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Table service and tables to create." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "allowBlobPublicAccess": { - "type": "bool", - "defaultValue": false, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, - "minimumTlsVersion": { - "type": "string", - "defaultValue": "TLS1_2", - "allowedValues": [ - "TLS1_0", - "TLS1_1", - "TLS1_2" - ], + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", "metadata": { - "description": "Optional. Set the minimum TLS version on request to storage." + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } }, - "enableHierarchicalNamespace": { - "type": "bool", - "defaultValue": false, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." } }, - "enableSftp": { - "type": "bool", - "defaultValue": false, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, "metadata": { - "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." } }, - "isLocalUserEnabled": { - "type": "bool", - "defaultValue": false, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Enables local users feature, if set to true." + "description": "Optional. Location for all Resources." } }, - "enableNfsV3": { - "type": "bool", - "defaultValue": false, + "lock": { + "$ref": "#/definitions/lockType", "metadata": { - "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + "description": "Optional. The lock settings of the service." } }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. Array of role assignments to create." } }, "tags": { "type": "object", "nullable": true, "metadata": { - "description": "Optional. Tags of the resource." + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Optional. Custom DNS configurations." } }, - "allowedCopyScope": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "AAD", - "PrivateLink" - ], + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." } }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "Enabled", - "Disabled" - ], + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + "description": "Optional. A grouping of information about the connection to the remote resource." } }, - "supportsHttpsTrafficOnly": { + "enableTelemetry": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "sasExpirationPeriod": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The SAS expiration period. DD.HH:MM:SS." - } - }, - "keyType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Account", - "Service" - ], - "metadata": { - "description": "Optional. The keyType to use with Queue & Table services." + "description": "Optional. Enable/Disable usage telemetry for module." } } }, "variables": { - "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } }, "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" - }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -36570,760 +31408,496 @@ } } }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" - }, - "storageAccount": { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2022-09-01", + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", "name": "[parameters('name')]", "location": "[parameters('location')]", - "kind": "[parameters('kind')]", - "sku": { - "name": "[parameters('skuName')]" - }, - "identity": "[variables('identity')]", "tags": "[parameters('tags')]", - "properties": { - "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", - "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", - "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", - "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", - "customDomain": { - "name": "[parameters('customDomainName')]", - "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" - }, - "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", - "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", - "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", - "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", - "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", - "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", - "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", - "isSftpEnabled": "[parameters('enableSftp')]", - "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", - "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", - "minimumTlsVersion": "[parameters('minimumTlsVersion')]", - "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", - "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", - "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" - }, - "dependsOn": [ - "cMKKeyVault", - "cMKKeyVault::cMKKey" - ] - }, - "storageAccount_diagnosticSettings": { - "copy": { - "name": "storageAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { "copy": [ { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" } } ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" }, "dependsOn": [ - "storageAccount" + "privateEndpoint" ] }, - "storageAccount_privateEndpoints": { + "privateEndpoint_roleAssignments": { "copy": { - "name": "storageAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", "properties": { "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" - }, - "privateDnsZoneGroupName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" - }, - "privateDnsZoneResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "4120048060064073955" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "ipConfigurationsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true - }, - "manualPrivateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "privateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "customDnsConfigType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "$ref": "#/definitions/ipConfigurationsType", - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" }, - "privateDnsZoneGroupName": { + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." } }, - "privateDnsZoneResourceIds": { + "privateDNSResourceIds": { "type": "array", - "nullable": true, + "minLength": 1, + "maxLength": 5, "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." } }, - "location": { + "name": { "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", + "defaultValue": "default", "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. The name of the private DNS zone group." } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } } - }, - "customDnsConfigs": { - "$ref": "#/definitions/customDnsConfigType", - "metadata": { - "description": "Optional. Custom DNS configurations." + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" } - }, - "manualPrivateLinkServiceConnections": { - "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + } + ], + "outputs": { + "name": { + "type": "string", "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." - } + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" }, - "privateLinkServiceConnections": { - "$ref": "#/definitions/privateLinkServiceConnectionsType", + "resourceId": { + "type": "string", "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource." - } + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "resourceGroupName": { + "type": "string", "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "5572402757180298542" + }, + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." } }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" } } }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" - }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." } }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", + "enabled": { + "type": "bool", + "nullable": true, "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "11244630631275470040" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDNSResourceIds": { - "type": "array", - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", - "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" - } - } - } - ] - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } + "description": "Optional. Enable or disable the category explicitly. Default is `true`." } } - }, - "dependsOn": [ - "privateEndpoint" - ] + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Protocol settings for file service." + } + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "defaultValue": { + "enabled": true, + "days": 7 + }, + "metadata": { + "description": "Optional. The service properties for soft delete." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + } + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null } }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" - }, - "groupId": { - "type": "string", - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" } } - } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, "dependsOn": [ - "storageAccount" + "fileServices" ] }, - "storageAccount_fileServices": { - "condition": "[not(empty(parameters('fileServices')))]", + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", + "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -37331,19 +31905,28 @@ "mode": "Incremental", "parameters": { "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { "value": "[parameters('name')]" }, - "diagnosticSettings": { - "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" }, - "protocolSettings": { - "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" }, - "shareDeleteRetentionPolicy": { - "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" }, - "shares": { - "value": "[tryGet(parameters('fileServices'), 'shares')]" + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" } }, "template": { @@ -37354,127 +31937,73 @@ "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "5572402757180298542" + "templateHash": "2846593244669729605" }, - "name": "Storage Account File Share Services", - "description": "This module deploys a Storage Account File Share Service.", + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share.", "owner": "Azure/module-maintainers" }, "definitions": { - "diagnosticSettingType": { + "roleAssignmentType": { "type": "array", "items": { "type": "object", "properties": { - "name": { + "roleDefinitionIdOrName": { "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." } }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, + "principalId": { + "type": "string", "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." } }, - "logAnalyticsDestinationType": { + "principalType": { "type": "string", "allowedValues": [ - "AzureDiagnostics", - "Dedicated" + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" ], "nullable": true, "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The principal type of the assigned principal ID." } }, - "storageAccountResourceId": { + "description": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. The description of the role assignment." } }, - "eventHubAuthorizationRuleResourceId": { + "condition": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + "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\"." } }, - "eventHubName": { + "conditionVersion": { "type": "string", + "allowedValues": [ + "2.0" + ], "nullable": true, "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + "description": "Optional. Version of the condition." } }, - "marketplacePartnerResourceId": { + "delegatedManagedIdentityResourceId": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + "description": "Optional. The Resource Id of the delegated managed identity resource." } } } @@ -37490,550 +32019,295 @@ "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, - "name": { + "fileServicesName": { "type": "string", "defaultValue": "default", "metadata": { - "description": "Optional. The name of the file service." + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." } }, - "protocolSettings": { - "type": "object", - "defaultValue": {}, + "name": { + "type": "string", "metadata": { - "description": "Optional. Protocol settings for file service." + "description": "Required. The name of the file share to create." } }, - "shareDeleteRetentionPolicy": { - "type": "object", - "defaultValue": { - "enabled": true, - "days": 7 - }, + "accessTier": { + "type": "string", + "defaultValue": "TransactionOptimized", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], "metadata": { - "description": "Optional. The service properties for soft delete." + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." } }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", + "shareQuota": { + "type": "int", + "defaultValue": 5120, "metadata": { - "description": "Optional. The diagnostic settings of the service." + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." } }, - "shares": { - "type": "array", - "nullable": true, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", "metadata": { - "description": "Optional. File shares to create." + "description": "Optional. Array of role assignments to create." } } }, "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" + }, "storageAccount": { "existing": true, "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2023-04-01", "name": "[parameters('storageAccountName')]" }, - "fileServices": { - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", "properties": { - "protocolSettings": "[parameters('protocolSettings')]", - "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" } }, - "fileServices_diagnosticSettings": { - "copy": { - "name": "fileServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "fileServices" - ] - }, - "fileServices_shares": { - "copy": { - "name": "fileServices_shares", - "count": "[length(coalesce(parameters('shares'), createArray()))]" - }, + "fileShare_roleAssignments": { + "condition": "[not(empty(parameters('roleAssignments')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "fileServicesName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" - }, - "accessTier": { - "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" - }, - "enabledProtocols": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" - }, - "rootSquash": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" - }, - "shareQuota": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + "fileShareResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" }, "roleAssignments": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + "value": "[parameters('roleAssignments')]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "2846593244669729605" - }, - "name": "Storage Account File Shares", - "description": "This module deploys a Storage Account File Share.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true + "templateHash": "11422901802944437310" } }, "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "fileServicesName": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share to create." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "TransactionOptimized", - "allowedValues": [ - "Premium", - "Hot", - "Cool", - "TransactionOptimized" - ], - "metadata": { - "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." - } - }, - "shareQuota": { - "type": "int", - "defaultValue": 5120, - "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." - } - }, - "enabledProtocols": { - "type": "string", - "defaultValue": "SMB", - "allowedValues": [ - "NFS", - "SMB" - ], + "roleAssignments": { + "type": "array", "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + "description": "Optional. Array of role assignments to create." } }, - "rootSquash": { + "fileShareResourceId": { "type": "string", - "defaultValue": "NoRootSquash", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], - "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Required. The resource id of the file share to assign the roles to." } } }, - "resources": { - "storageAccount::fileService": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" - }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-04-01", - "name": "[parameters('storageAccountName')]" - }, - "fileShare": { - "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2023-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", - "properties": { - "accessTier": "[parameters('accessTier')]", - "shareQuota": "[parameters('shareQuota')]", - "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", - "enabledProtocols": "[parameters('enabledProtocols')]" - } + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "metadata": { + "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\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "description": "[[parameters('description')]", + "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] }, - "fileShare_roleAssignments": { - "condition": "[not(empty(parameters('roleAssignments')))]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": [ + { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", + "apiVersion": "2021-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", "properties": { + "mode": "Incremental", "expressionEvaluationOptions": { - "scope": "inner" + "scope": "Outer" }, - "mode": "Incremental", + "template": "[variables('$fxv#0')]", "parameters": { - "fileShareResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + "scope": { + "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "11422901802944437310" - } + "name": { + "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" }, - "parameters": { - "roleAssignments": { - "type": "array", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "fileShareResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the file share to assign the roles to." - } - } + "roleDefinitionId": { + "value": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]" }, - "variables": { - "$fxv#0": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "scope": { - "type": "string", - "metadata": { - "description": "Required. The scope to deploy the role assignment to." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The role definition Id to assign." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "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\"" - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "defaultValue": "2.0", - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[[parameters('scope')]", - "name": "[[parameters('name')]", - "properties": { - "roleDefinitionId": "[[parameters('roleDefinitionId')]", - "principalId": "[[parameters('principalId')]", - "description": "[[parameters('description')]", - "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", - "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" - } - } - ] - }, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + "principalId": { + "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" }, - "resources": [ - { - "copy": { - "name": "fileShare_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2021-04-01", - "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "mode": "Incremental", - "expressionEvaluationOptions": { - "scope": "Outer" - }, - "template": "[variables('$fxv#0')]", - "parameters": { - "scope": { - "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" - }, - "name": { - "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" - }, - "roleDefinitionId": { - "value": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]" - }, - "principalId": { - "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" - }, - "principalType": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" - }, - "description": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" - }, - "condition": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" - }, - "conditionVersion": { - "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" - }, - "delegatedManagedIdentityResourceId": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - } - } - } - } - ] + "principalType": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "condition": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": { + "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" + }, + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } } - }, - "dependsOn": [ - "fileShare" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed file share." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed file share." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed file share." - }, - "value": "[resourceGroup().name]" + } } - } + ] } }, "dependsOn": [ - "fileServices", - "storageAccount" + "fileShare" ] } }, @@ -38041,21 +32315,21 @@ "name": { "type": "string", "metadata": { - "description": "The name of the deployed file share service." + "description": "The name of the deployed file share." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the deployed file share service." + "description": "The resource ID of the deployed file share." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group of the deployed file share service." + "description": "The resource group of the deployed file share." }, "value": "[resourceGroup().name]" } @@ -38063,394 +32337,401 @@ } }, "dependsOn": [ + "fileServices", "storageAccount" ] } }, "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed storage account." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" - }, "name": { "type": "string", "metadata": { - "description": "The name of the deployed storage account." + "description": "The name of the deployed file share service." }, "value": "[parameters('name')]" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed storage account." - }, - "value": "[resourceGroup().name]" - }, - "primaryBlobEndpoint": { - "type": "string", - "metadata": { - "description": "The primary blob endpoint reference if blob services are deployed." - }, - "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" - }, - "systemAssignedMIPrincipalId": { + "resourceId": { "type": "string", "metadata": { - "description": "The principal ID of the system assigned identity." + "description": "The resource ID of the deployed file share service." }, - "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" }, - "location": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "The location the resource was deployed into." + "description": "The resource group of the deployed file share service." }, - "value": "[reference('storageAccount', '2022-09-01', 'full').location]" + "value": "[resourceGroup().name]" } } } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed storage account." + }, + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2022-09-01', 'full').location]" + } + } + } + } + }, + { + "condition": "[not(equals(parameters('identityServiceProvider'), 'EntraID'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Add-{0}-Storage-Setup-{1}', parameters('storagePurpose'), parameters('time'))]", + "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", + "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "virtualMachineName": { + "value": "[parameters('managementVmName')]" + }, + "file": { + "value": "[parameters('storageToDomainScript')]" + }, + "scriptArguments": { + "value": "[variables('varStorageToDomainScriptArgs')]" + }, + "adminUserPassword": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.KeyVault/vaults', parameters('wrklKvName'))), 'secretName', 'vmLocalUserPassword')), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.KeyVault/vaults', parameters('wrklKvName'))), 'secretName', 'domainJoinUserPassword')))]", + "baseScriptUri": { + "value": "[parameters('storageToDomainScriptUri')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.34.44.8038", + "templateHash": "7337889415739790800" + }, + "name": "AVD LZA storage", + "description": "Configures domain join settings on storage account via VM custom script extension", + "owner": "Azure/avdaccelerator" + }, + "parameters": { + "virtualMachineName": { + "type": "string", + "metadata": { + "description": "Virtual machine name." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location where to deploy compute services." + } + }, + "baseScriptUri": { + "type": "string", + "metadata": { + "description": "Location for the AVD agent installation package." + } + }, + "file": { + "type": "string" + }, + "scriptArguments": { + "type": "string", + "metadata": { + "description": "Arguments for domain join script." } }, + "adminUserPassword": { + "type": "securestring", + "metadata": { + "description": "Domain join user password." + } + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Do not modify, used to set unique value for resource deployment." + } + } + }, + "resources": [ { - "condition": "[not(equals(parameters('identityServiceProvider'), 'EntraID'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('Add-{0}-Storage-Setup-{1}', parameters('storagePurpose'), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", + "name": "[format('VM-Ext-AVM-{0}', parameters('time'))]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "name": { + "value": "AzureFilesDomainJoin" + }, + "virtualMachineName": { + "value": "[parameters('virtualMachineName')]" + }, "location": { "value": "[parameters('location')]" }, - "virtualMachineName": { - "value": "[parameters('managementVmName')]" + "publisher": { + "value": "Microsoft.Compute" }, - "file": { - "value": "[parameters('storageToDomainScript')]" + "type": { + "value": "CustomScriptExtension" }, - "scriptArguments": { - "value": "[variables('varStorageToDomainScriptArgs')]" + "typeHandlerVersion": { + "value": "1.10" + }, + "autoUpgradeMinorVersion": { + "value": true + }, + "enableAutomaticUpgrade": { + "value": false + }, + "settings": { + "value": {} }, - "adminUserPassword": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'vmLocalUserPassword')), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'domainJoinUserPassword')))]", - "baseScriptUri": { - "value": "[parameters('storageToDomainScriptUri')]" + "protectedSettings": { + "value": { + "fileUris": "[array(parameters('baseScriptUri'))]", + "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -File {0} {1} -AdminUserPassword {2} -verbose', parameters('file'), parameters('scriptArguments'), parameters('adminUserPassword'))]" + } } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "7337889415739790800" + "templateHash": "12041352154594223618" }, - "name": "AVD LZA storage", - "description": "Configures domain join settings on storage account via VM custom script extension", - "owner": "Azure/avdaccelerator" + "name": "Virtual Machine Extensions", + "description": "This module deploys a Virtual Machine Extension.", + "owner": "Azure/module-maintainers" }, "parameters": { "virtualMachineName": { "type": "string", "metadata": { - "description": "Virtual machine name." + "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the virtual machine extension." } }, "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Location where to deploy compute services." + "description": "Optional. The location the extension is deployed to." } }, - "baseScriptUri": { + "publisher": { "type": "string", "metadata": { - "description": "Location for the AVD agent installation package." + "description": "Required. The name of the extension handler publisher." } }, - "file": { - "type": "string" + "type": { + "type": "string", + "metadata": { + "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." + } }, - "scriptArguments": { + "typeHandlerVersion": { "type": "string", "metadata": { - "description": "Arguments for domain join script." + "description": "Required. Specifies the version of the script handler." } }, - "adminUserPassword": { - "type": "securestring", + "autoUpgradeMinorVersion": { + "type": "bool", "metadata": { - "description": "Domain join user password." + "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." } }, - "time": { + "forceUpdateTag": { "type": "string", - "defaultValue": "[utcNow()]", + "defaultValue": "", + "metadata": { + "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." + } + }, + "settings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific settings." + } + }, + "protectedSettings": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. Any object that contains the extension specific protected settings." + } + }, + "supressFailures": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." + } + }, + "enableAutomaticUpgrade": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." + } + }, + "tags": { + "type": "object", + "nullable": true, "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." + "description": "Optional. Tags of the resource." } } }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('VM-Ext-AVM-{0}', parameters('time'))]", + "resources": { + "virtualMachine": { + "existing": true, + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('virtualMachineName')]" + }, + "extension": { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-11-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "AzureFilesDomainJoin" - }, - "virtualMachineName": { - "value": "[parameters('virtualMachineName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "CustomScriptExtension" - }, - "typeHandlerVersion": { - "value": "1.10" - }, - "autoUpgradeMinorVersion": { - "value": true - }, - "enableAutomaticUpgrade": { - "value": false - }, - "settings": { - "value": {} - }, - "protectedSettings": { - "value": { - "fileUris": "[array(parameters('baseScriptUri'))]", - "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -File {0} {1} -AdminUserPassword {2} -verbose', parameters('file'), parameters('scriptArguments'), parameters('adminUserPassword'))]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } + "publisher": "[parameters('publisher')]", + "type": "[parameters('type')]", + "typeHandlerVersion": "[parameters('typeHandlerVersion')]", + "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", + "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", + "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", + "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", + "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", + "suppressFailures": "[parameters('supressFailures')]" } } - ] + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the extension was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('extension', '2022-11-01', 'full').location]" + } + } } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time')))]" - ] - } - ], - "outputs": { - "storageAccountResourceId": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))), '2022-09-01').outputs.resourceId.value]" + } } - } + ] } }, "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]" + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time')))]" ] } ], "outputs": { - "fslogixFileSharePath": { - "type": "string", - "value": "[if(parameters('createFslogixDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('\\\\{0}.file.{1}\\{2}', variables('varFslogixStorageName'), environment().suffixes.storage, variables('varFslogixFileShareName')), if(equals(parameters('storageService'), 'ANF'), format('\\\\{0}\\{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Get-ANF-SMB-Server-FQDN-{0}', parameters('time'))), '2022-09-01').outputs.anfSmbServerFqdn.value, last(split(reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfFslogixVolumeResourceId.value, '/'))), '')), '')]" - }, - "appAttachFileSharePath": { + "storageAccountResourceId": { "type": "string", - "value": "[if(parameters('createAppAttachDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('\\\\{0}.file.{1}\\{2}', variables('varAppAttachStorageName'), environment().suffixes.storage, variables('varAppAttachFileShareName')), if(equals(parameters('storageService'), 'ANF'), format('\\\\{0}\\{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Get-ANF-SMB-Server-FQDN-{0}', parameters('time'))), '2022-09-01').outputs.anfSmbServerFqdn.value, last(split(reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfAppAttachVolumeResourceId.value, '/'))), '')), '')]" - }, - "fslogixStorageAccountResourceId": { - "type": "string", - "value": "[if(and(parameters('createFslogixDeployment'), equals(parameters('storageService'), 'AzureFiles')), reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-FSLogix-ST-{0}', parameters('time'))), '2022-09-01').outputs.storageAccountResourceId.value, '')]" - }, - "appAttachStorageAccountResourceId": { - "type": "string", - "value": "[if(and(parameters('createAppAttachDeployment'), equals(parameters('storageService'), 'AzureFiles')), reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-AppA-{0}', parameters('time'))), '2022-09-01').outputs.storageAccountResourceId.value, '')]" + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))), '2022-09-01').outputs.resourceId.value]" } } } }, "dependsOn": [ "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-FSLogix-{0}', parameters('time')))]", "[subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]", "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]", "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]", - "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time')))]" + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]" ] }, { @@ -38471,7 +32752,7 @@ }, "mode": "Incremental", "parameters": { - "asgResourceId": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', format('{0}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.applicationSecurityGroupResourceId.value)), createObject('value', ''))]", + "asgResourceId": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createAvdFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', format('{0}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.applicationSecurityGroupResourceId.value)), createObject('value', ''))]", "availability": { "value": "[parameters('availability')]" }, @@ -38485,7 +32766,7 @@ "value": "[variables('varComputeObjectsRgName')]" }, "configureFslogix": { - "value": "[parameters('createFslogixDeployment')]" + "value": "[parameters('createAvdFslogixDeployment')]" }, "count": "[if(and(equals(range(1, variables('varSessionHostBatchCount'))[copyIndex()], variables('varSessionHostBatchCount')), greater(variables('varMaxSessionHostsDivisionRemainderValue'), 0)), createObject('value', variables('varMaxSessionHostsDivisionRemainderValue')), createObject('value', variables('varMaxSessionHostsPerTemplate')))]", "countIndex": "[if(equals(range(1, variables('varSessionHostBatchCount'))[copyIndex()], 1), createObject('value', parameters('avdSessionHostCountIndex')), createObject('value', add(mul(sub(range(1, variables('varSessionHostBatchCount'))[copyIndex()], 1), variables('varMaxSessionHostsPerTemplate')), parameters('avdSessionHostCountIndex'))))]", @@ -38518,8 +32799,10 @@ "encryptionAtHost": { "value": "[parameters('diskZeroTrust')]" }, - "fslogixSharePath": "[if(parameters('createFslogixDeployment'), createObject('value', reference(subscriptionResourceId(format('{0}', parameters('avdWorkloadSubsId')), 'Microsoft.Resources/deployments', format('SMB-Storage-{0}', parameters('time'))), '2022-09-01').outputs.fslogixFileSharePath.value), createObject('value', ''))]", - "fslogixStorageAccountResourceId": "[if(and(equals(parameters('avdIdentityServiceProvider'), 'EntraID'), parameters('createFslogixDeployment')), createObject('value', reference(subscriptionResourceId(format('{0}', parameters('avdWorkloadSubsId')), 'Microsoft.Resources/deployments', format('SMB-Storage-{0}', parameters('time'))), '2022-09-01').outputs.fslogixStorageAccountResourceId.value), createObject('value', ''))]", + "fslogixSharePath": { + "value": "[variables('varFslogixSharePath')]" + }, + "fslogixStorageAccountResourceId": "[if(equals(parameters('avdIdentityServiceProvider'), 'EntraID'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-FSLogix-{0}', parameters('time'))), '2022-09-01').outputs.storageAccountResourceId.value), createObject('value', ''))]", "hostPoolResourceId": { "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', format('AVD-MGMT-Plane-{0}', parameters('time'))), '2022-09-01').outputs.hostPoolResourceId.value]" }, @@ -38582,7 +32865,7 @@ "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "13361150904998745536" + "templateHash": "6712586817256654901" } }, "parameters": { @@ -43079,6 +37362,7 @@ "identityDomainName": { "value": "[parameters('identityDomainName')]" }, + "extendOsDisk": "[if(not(equals(parameters('customOsDiskSizeGB'), 0)), createObject('value', true()), createObject('value', false()))]", "identityServiceProvider": { "value": "[parameters('identityServiceProvider')]" }, @@ -43102,7 +37386,7 @@ "_generator": { "name": "bicep", "version": "0.34.44.8038", - "templateHash": "1149225665070592315" + "templateHash": "13664975487820917130" } }, "parameters": { @@ -43130,6 +37414,12 @@ "description": "Location where to deploy compute services." } }, + "extendOsDisk": { + "type": "bool", + "metadata": { + "description": "Specifies whether to extend the OS disk." + } + }, "baseScriptUri": { "type": "string", "metadata": { @@ -43218,7 +37508,7 @@ "fileUris": "[array(parameters('baseScriptUri'))]" }, "protectedSettings": { - "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -Command .\\{0} {1}', parameters('scriptName'), if(parameters('fslogix'), format('{0} {1}', format('-IdentityServiceProvider {0} -Fslogix {1} -HostPoolRegistrationToken \"{2}\" -AmdVmSize {3} -NvidiaVmSize {4}', parameters('identityServiceProvider'), parameters('fslogix'), listRegistrationTokens(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('hostPoolResourceId'), '/')[4]), 'Microsoft.DesktopVirtualization/hostPools', last(split(parameters('hostPoolResourceId'), '/'))), '2023-09-05').value[0].token, variables('varAmdVmSize'), variables('varNvidiaVmSize')), if(equals(parameters('identityServiceProvider'), 'EntraID'), format('{0} -FslogixStorageAccountKey \"{1}\"', variables('varBaseFSLogixScriptArguments'), listkeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('fslogixStorageAccountResourceId'), '/')[4]), 'Microsoft.Storage/storageAccounts', variables('fslogixStorageAccountName')), '2023-05-01').keys[0].value), if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), format('{0} -IdentityDomainName {1}', variables('varBaseFSLogixScriptArguments'), parameters('identityDomainName')), variables('varBaseFSLogixScriptArguments')))), format('-IdentityServiceProvider {0} -Fslogix {1} -HostPoolRegistrationToken \"{2}\" -AmdVmSize {3} -NvidiaVmSize {4}', parameters('identityServiceProvider'), parameters('fslogix'), listRegistrationTokens(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('hostPoolResourceId'), '/')[4]), 'Microsoft.DesktopVirtualization/hostPools', last(split(parameters('hostPoolResourceId'), '/'))), '2023-09-05').value[0].token, variables('varAmdVmSize'), variables('varNvidiaVmSize'))))]" + "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -Command .\\{0} {1}', parameters('scriptName'), if(parameters('fslogix'), format('{0} {1}', format('-ExtendOsDisk {0} -IdentityServiceProvider {1} -Fslogix {2} -HostPoolRegistrationToken \"{3}\" -AmdVmSize {4} -NvidiaVmSize {5}', parameters('extendOsDisk'), parameters('identityServiceProvider'), parameters('fslogix'), listRegistrationTokens(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('hostPoolResourceId'), '/')[4]), 'Microsoft.DesktopVirtualization/hostPools', last(split(parameters('hostPoolResourceId'), '/'))), '2023-09-05').value[0].token, variables('varAmdVmSize'), variables('varNvidiaVmSize')), if(equals(parameters('identityServiceProvider'), 'EntraID'), format('{0} -FslogixStorageAccountKey \"{1}\"', variables('varBaseFSLogixScriptArguments'), listkeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('fslogixStorageAccountResourceId'), '/')[4]), 'Microsoft.Storage/storageAccounts', variables('fslogixStorageAccountName')), '2023-05-01').keys[0].value), if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), format('{0} -IdentityDomainName {1}', variables('varBaseFSLogixScriptArguments'), parameters('identityDomainName')), variables('varBaseFSLogixScriptArguments')))), format('-ExtendOsDisk {0} -IdentityServiceProvider {1} -Fslogix {2} -HostPoolRegistrationToken \"{3}\" -AmdVmSize {4} -NvidiaVmSize {5}', parameters('extendOsDisk'), parameters('identityServiceProvider'), parameters('fslogix'), listRegistrationTokens(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('hostPoolResourceId'), '/')[4]), 'Microsoft.DesktopVirtualization/hostPools', last(split(parameters('hostPoolResourceId'), '/'))), '2023-09-05').value[0].token, variables('varAmdVmSize'), variables('varNvidiaVmSize'))))]" } } } @@ -43235,10 +37525,10 @@ }, "dependsOn": [ "baselineResourceGroups", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-FSLogix-{0}', parameters('time')))]", "[subscriptionResourceId('Microsoft.Resources/deployments', format('AVD-MGMT-Plane-{0}', parameters('time')))]", "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]", "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", - "[subscriptionResourceId(format('{0}', parameters('avdWorkloadSubsId')), 'Microsoft.Resources/deployments', format('SMB-Storage-{0}', parameters('time')))]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]", "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time')))]" ] From 15fe4dd19b3c623568d30f72b8856e60338aee9b Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Thu, 10 Apr 2025 09:55:38 -0500 Subject: [PATCH 50/55] updates --- workload/bicep/deploy-baseline.bicepparam | 1 - workload/bicep/deploy-baseline.json | 44083 -------------------- workload/bicep/deploy-custom-image.bicep | 1066 +- 3 files changed, 514 insertions(+), 44636 deletions(-) delete mode 100644 workload/bicep/deploy-baseline.bicepparam delete mode 100644 workload/bicep/deploy-baseline.json diff --git a/workload/bicep/deploy-baseline.bicepparam b/workload/bicep/deploy-baseline.bicepparam deleted file mode 100644 index ca77d9406..000000000 --- a/workload/bicep/deploy-baseline.bicepparam +++ /dev/null @@ -1 +0,0 @@ -using './deploy-baseline.bicep' diff --git a/workload/bicep/deploy-baseline.json b/workload/bicep/deploy-baseline.json deleted file mode 100644 index befe571e0..000000000 --- a/workload/bicep/deploy-baseline.json +++ /dev/null @@ -1,44083 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "18159930501355149539" - }, - "name": "AVD Accelerator - Baseline Deployment", - "description": "AVD Accelerator - Deployment Baseline", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "deploymentPrefix": { - "type": "string", - "defaultValue": "AVD1", - "minLength": 2, - "maxLength": 4, - "metadata": { - "description": "The name of the resource group to deploy. (Default: AVD1)" - } - }, - "deploymentEnvironment": { - "type": "string", - "defaultValue": "Dev", - "allowedValues": [ - "Dev", - "Test", - "Prod" - ], - "metadata": { - "description": "The name of the resource group to deploy. (Default: Dev)" - } - }, - "diskEncryptionKeyExpirationInDays": { - "type": "int", - "defaultValue": 60, - "minValue": 30, - "maxValue": 730, - "metadata": { - "description": "This value is used to set the expiration date on the disk encryption key. (Default: 60)" - } - }, - "avdSessionHostLocation": { - "type": "string", - "metadata": { - "description": "Required. Location where to deploy compute services." - } - }, - "avdManagementPlaneLocation": { - "type": "string", - "metadata": { - "description": "Required. Location where to deploy AVD management plane." - } - }, - "avdWorkloadSubsId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario. (Default: \"\")" - } - }, - "avdServicePrincipalObjectId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Azure Virtual Desktop Enterprise Application object ID (Enterprise app name: Azure Virtual Desktop) . (Default: \"\")" - } - }, - "avdArmServicePrincipalObjectId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Azure Virtual Desktop ARM Enterprise Application Object Id (Enterprise app name: Azure Virtual Desktop ARM Provider). Required for the deployment of App Attach File Share with EntraID identity provider. (Default: \"\")" - } - }, - "avdVmLocalUserName": { - "type": "string", - "metadata": { - "description": "AVD session host local username." - } - }, - "avdVmLocalUserPassword": { - "type": "securestring", - "metadata": { - "description": "AVD session host local password." - } - }, - "avdIdentityServiceProvider": { - "type": "string", - "defaultValue": "ADDS", - "allowedValues": [ - "ADDS", - "EntraDS", - "EntraID", - "EntraIDKerberos" - ], - "metadata": { - "description": "Required, The service providing domain services for Azure Virtual Desktop. (Default: ADDS)" - } - }, - "createIntuneEnrollment": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Required, Enroll session hosts on Intune. (Default: false)" - } - }, - "avdSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Identity ID(s) to grant RBAC role to access AVD application group and NTFS permissions. (Default: [])" - } - }, - "identityDomainName": { - "type": "string", - "defaultValue": "none", - "metadata": { - "description": "FQDN of on-premises AD domain, used for FSLogix storage configuration and NTFS setup. (Default: \"none\")" - } - }, - "identityDomainGuid": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "GUID of on-premises AD domain, used for FSLogix storage configuration and NTFS setup. (Default: \"\")" - } - }, - "avdDomainJoinUserName": { - "type": "string", - "defaultValue": "none", - "metadata": { - "description": "AVD session host domain join user principal name. (Default: \"none\")" - } - }, - "avdDomainJoinUserPassword": { - "type": "securestring", - "defaultValue": "none", - "metadata": { - "description": "AVD session host domain join password. (Default: \"none\")" - } - }, - "avdOuPath": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "OU path to join AVd VMs. (Default: \"\")" - } - }, - "avdHostPoolType": { - "type": "string", - "defaultValue": "Pooled", - "allowedValues": [ - "Personal", - "Pooled" - ], - "metadata": { - "description": "AVD host pool type. (Default: Pooled)" - } - }, - "hostPoolPreferredAppGroupType": { - "type": "string", - "defaultValue": "Desktop", - "allowedValues": [ - "Desktop", - "RemoteApp" - ], - "metadata": { - "description": "Optional. The type of preferred application group type, default to Desktop Application Group." - } - }, - "hostPoolPublicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Disabled", - "Enabled", - "EnabledForClientsOnly", - "EnabledForSessionHostsOnly" - ], - "metadata": { - "description": "Enables or Disables public network access on the host pool. (Default: Enabled.)" - } - }, - "workspacePublicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Default to Enabled. Enables or Disables public network access on the workspace." - } - }, - "avdPersonalAssignType": { - "type": "string", - "defaultValue": "Automatic", - "allowedValues": [ - "Automatic", - "Direct" - ], - "metadata": { - "description": "AVD host pool type. (Default: Automatic)" - } - }, - "avdHostPoolLoadBalancerType": { - "type": "string", - "defaultValue": "BreadthFirst", - "allowedValues": [ - "BreadthFirst", - "DepthFirst" - ], - "metadata": { - "description": "AVD host pool load balacing type. (Default: BreadthFirst)" - } - }, - "hostPoolMaxSessions": { - "type": "int", - "defaultValue": 8, - "metadata": { - "description": "AVD host pool maximum number of user sessions per session host. (Default: 8)" - } - }, - "avdStartVmOnConnect": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "AVD host pool start VM on Connect. (Default: true)" - } - }, - "avdHostPoolRdpProperties": { - "type": "string", - "defaultValue": "audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2", - "metadata": { - "description": "AVD host pool Custom RDP properties. (Default: audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2)" - } - }, - "avdDeployScalingPlan": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "AVD deploy scaling plan. (Default: true)" - } - }, - "createAvdVnet": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Create new virtual network. (Default: true)" - } - }, - "existingVnetAvdSubnetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Existing virtual network subnet for AVD. (Default: \"\")" - } - }, - "existingVnetPrivateEndpointSubnetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Existing virtual network subnet for private endpoints. (Default: \"\")" - } - }, - "existingVnetAnfSubnetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Existing virtual network subnet for ANF. (Default: \"\")" - } - }, - "existingHubVnetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Existing hub virtual network for peering. (Default: \"\")" - } - }, - "avdVnetworkAddressPrefixes": { - "type": "string", - "defaultValue": "10.10.0.0/16", - "metadata": { - "description": "AVD virtual network address prefixes. (Default: 10.10.0.0/16)" - } - }, - "vNetworkAvdSubnetAddressPrefix": { - "type": "string", - "defaultValue": "10.10.1.0/24", - "metadata": { - "description": "AVD virtual network subnet address prefix. (Default: 10.10.1.0/24)" - } - }, - "vNetworkPrivateEndpointSubnetAddressPrefix": { - "type": "string", - "defaultValue": "10.10.2.0/27", - "metadata": { - "description": "private endpoints virtual network subnet address prefix. (Default: 10.10.2.0/27)" - } - }, - "vNetworkAnfSubnetAddressPrefix": { - "type": "string", - "defaultValue": "10.10.3.0/26", - "metadata": { - "description": "ANF virtual network subnet address prefix. (Default: 10.10.3.0/26)" - } - }, - "customDnsIps": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "custom DNS servers IPs. (Default: \"\")" - } - }, - "deployDDoSNetworkProtection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Deploy DDoS Network Protection for virtual network. (Default: true)" - } - }, - "deployPrivateEndpointKeyvaultStorage": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Deploy private endpoints for key vault and storage. (Default: true)" - } - }, - "deployAvdPrivateLinkService": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Deploys the private link for AVD. Requires resource provider registration or re-registration. (Default: false)" - } - }, - "createPrivateDnsZones": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Create new Azure private DNS zones for private endpoints. (Default: true)" - } - }, - "avdVnetPrivateDnsZoneConnectionResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The ResourceID of the AVD Private DNS Zone for Connection. (privatelink.wvd.azure.com). Only required if createPrivateDNSZones is set to false." - } - }, - "avdVnetPrivateDnsZoneDiscoveryResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The ResourceID of the AVD Private DNS Zone for Discovery. (privatelink-global.wvd.azure.com). Only required if createPrivateDNSZones is set to false." - } - }, - "avdVnetPrivateDnsZoneFilesId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Use existing Azure private DNS zone for Azure files. (Default: \"\")" - } - }, - "avdVnetPrivateDnsZoneKeyvaultId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Use existing Azure private DNS zone for key vault privatelink.vaultcore.azure.net or privatelink.vaultcore.usgovcloudapi.net. (Default: \"\")" - } - }, - "vNetworkGatewayOnHub": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Does the hub contains a virtual network gateway. (Default: false)" - } - }, - "createFslogixDeployment": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Deploy Fslogix setup. (Default: true)" - } - }, - "storageService": { - "type": "string", - "defaultValue": "AzureFiles", - "allowedValues": [ - "ANF", - "AzureFiles" - ], - "metadata": { - "description": "Type of storage service to deploy for FSLogix. (Default: AzureFiles)" - } - }, - "createAppAttachDeployment": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Deploy App Attach setup. (Default: false)" - } - }, - "fslogixFileShareQuotaSize": { - "type": "int", - "defaultValue": 100, - "metadata": { - "description": "Fslogix file share size in GB. (Default: 100)" - } - }, - "appAttachFileShareQuotaSize": { - "type": "int", - "defaultValue": 100, - "metadata": { - "description": "App Attach file share size in GB. (Default: 100)" - } - }, - "avdDeploySessionHosts": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Deploy new session hosts. (Default: true)" - } - }, - "deployGpuPolicies": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Deploy VM GPU extension policies. (Default: false)" - } - }, - "avdDeployMonitoring": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Deploy AVD monitoring resources and setings. (Default: false)" - } - }, - "deployAlaWorkspace": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Deploy AVD Azure log analytics workspace. (Default: true)" - } - }, - "deployCustomPolicyMonitoring": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Create and assign custom Azure Policy for diagnostic settings for the AVD Log Analytics workspace. (Default: false)" - } - }, - "avdAlaWorkspaceDataRetention": { - "type": "int", - "defaultValue": 90, - "metadata": { - "description": "AVD Azure log analytics workspace data retention. (Default: 90)" - } - }, - "alaExistingWorkspaceResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Existing Azure log analytics workspace resource ID to connect to. (Default: \"\")" - } - }, - "avdDeploySessionHostsCount": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 100, - "metadata": { - "description": "Quantity of session hosts to deploy. (Default: 1)" - } - }, - "avdSessionHostCountIndex": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "The session host number to begin with for the deployment. This is important when adding virtual machines to ensure the names do not conflict. (Default: 1)" - } - }, - "availability": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "None", - "AvailabilityZones" - ], - "metadata": { - "description": "When set to AvailabilityZones, VMs are distributed across availability zones, when set to None, VMs are deployed at regional level." - } - }, - "zoneRedundantStorage": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "When true, Zone Redundant Storage (ZRS) is used, when set to false, Locally Redundant Storage (LRS) is used. (Default: false)" - } - }, - "availabilityZones": { - "type": "array", - "defaultValue": [ - "1", - "2", - "3" - ], - "allowedValues": [ - "1", - "2", - "3" - ], - "metadata": { - "description": "The Availability Zones to use for the session hosts." - } - }, - "fslogixStoragePerformance": { - "type": "string", - "defaultValue": "Premium", - "allowedValues": [ - "Standard", - "Premium", - "Ultra" - ], - "metadata": { - "description": "SKU for FSLogix storage. Recommended tier is Premium for storage account and Standard for ANF. (Default: Premium)" - } - }, - "appAttachStoragePerformance": { - "type": "string", - "defaultValue": "Premium", - "allowedValues": [ - "Standard", - "Premium", - "Ultra" - ], - "metadata": { - "description": "SKU for App Attach storage. RRecommended tier is Premium for storage account and Standard for ANF. (Default: Premium)" - } - }, - "diskZeroTrust": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enables a zero trust configuration on the session host disks. (Default: false)" - } - }, - "avdSessionHostsSize": { - "type": "string", - "defaultValue": "Standard_D4ads_v5", - "metadata": { - "description": "Session host VM size. (Default: Standard_D4ads_v5)" - } - }, - "avdSessionHostDiskType": { - "type": "string", - "defaultValue": "Premium_LRS", - "metadata": { - "description": "OS disk type for session host. (Default: Premium_LRS)" - } - }, - "customOsDiskSizeGB": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Custom OS Disk Size." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Enables accelerated Networking on the session hosts.\nIf using a Azure Compute Gallery Image, the Image Definition must have been configured with\nthe \\'isAcceleratedNetworkSupported\\' property set to \\'true\\'.\n" - } - }, - "securityType": { - "type": "string", - "defaultValue": "TrustedLaunch", - "allowedValues": [ - "Standard", - "TrustedLaunch" - ], - "metadata": { - "description": "Specifies the securityType of the virtual machine. \"ConfidentialVM\" and \"TrustedLaunch\" require a Gen2 Image. (Default: TrustedLaunch)" - } - }, - "secureBootEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch or ConfidentialVM to enable UefiSettings. (Default: true)" - } - }, - "vTpmEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch or ConfidentialVM to enable UefiSettings. (Default: true)" - } - }, - "useSharedImage": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Set to deploy image from Azure Compute Gallery. (Default: false)" - } - }, - "mpImageOffer": { - "type": "string", - "defaultValue": "Office-365", - "metadata": { - "description": "AVD OS image offer. (Default: Office-365)" - } - }, - "mpImageSku": { - "type": "string", - "defaultValue": "win11-24h2-avd-m365", - "metadata": { - "description": "AVD OS image SKU. (Default: win11-24h2-avd-m365)" - } - }, - "avdCustomImageDefinitionId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Source custom image ID. (Default: \"\")" - } - }, - "managementVmOsImage": { - "type": "string", - "defaultValue": "winServer_2022_Datacenter_smalldisk_g2", - "metadata": { - "description": "Management VM image SKU (Default: winServer_2022_Datacenter_smalldisk_g2)" - } - }, - "storageOuPath": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "OU name for Azure Storage Account or Azure Netapp Files. It is recommended to create a new AD Organizational Unit (OU) in AD and disable password expiration policy on computer accounts or service logon accounts accordingly. (Default: \"\")" - } - }, - "avdUseCustomNaming": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "AVD resources custom naming. (Default: false)" - } - }, - "avdServiceObjectsRgCustomName": { - "type": "string", - "defaultValue": "rg-avd-app1-dev-use2-service-objects", - "maxLength": 90, - "metadata": { - "description": "AVD service resources resource group custom name. (Default: rg-avd-app1-dev-use2-service-objects)" - } - }, - "avdNetworkObjectsRgCustomName": { - "type": "string", - "defaultValue": "rg-avd-app1-dev-use2-network", - "maxLength": 90, - "metadata": { - "description": "AVD network resources resource group custom name. (Default: rg-avd-app1-dev-use2-network)" - } - }, - "avdComputeObjectsRgCustomName": { - "type": "string", - "defaultValue": "rg-avd-app1-dev-use2-pool-compute", - "maxLength": 90, - "metadata": { - "description": "AVD network resources resource group custom name. (Default: rg-avd-app1-dev-use2-pool-compute)" - } - }, - "avdStorageObjectsRgCustomName": { - "type": "string", - "defaultValue": "rg-avd-app1-dev-use2-storage", - "maxLength": 90, - "metadata": { - "description": "AVD network resources resource group custom name. (Default: rg-avd-app1-dev-use2-storage)" - } - }, - "avdMonitoringRgCustomName": { - "type": "string", - "defaultValue": "rg-avd-dev-use2-monitoring", - "maxLength": 90, - "metadata": { - "description": "AVD monitoring resource group custom name. (Default: rg-avd-dev-use2-monitoring)" - } - }, - "avdVnetworkCustomName": { - "type": "string", - "defaultValue": "vnet-app1-dev-use2-001", - "maxLength": 64, - "metadata": { - "description": "AVD virtual network custom name. (Default: vnet-app1-dev-use2-001)" - } - }, - "avdAlaWorkspaceCustomName": { - "type": "string", - "defaultValue": "log-avd-app1-dev-use2", - "maxLength": 64, - "metadata": { - "description": "AVD Azure log analytics workspace custom name. (Default: log-avd-app1-dev-use2)" - } - }, - "avdVnetworkSubnetCustomName": { - "type": "string", - "defaultValue": "snet-avd-app1-dev-use2-001", - "maxLength": 80, - "metadata": { - "description": "AVD virtual network subnet custom name. (Default: snet-avd-app1-dev-use2-001)" - } - }, - "privateEndpointVnetworkSubnetCustomName": { - "type": "string", - "defaultValue": "snet-pe-app1-dev-use2-001", - "maxLength": 80, - "metadata": { - "description": "private endpoints virtual network subnet custom name. (Default: snet-pe-app1-dev-use2-001)" - } - }, - "anfVnetworkSubnetCustomName": { - "type": "string", - "defaultValue": "snet-anf-app1-dev-use2-001", - "maxLength": 80, - "metadata": { - "description": "ANF virtual network subnet custom name. (Default: snet-anf-app1-dev-use2-001)" - } - }, - "avdNetworksecurityGroupCustomName": { - "type": "string", - "defaultValue": "nsg-avd-app1-dev-use2-001", - "maxLength": 80, - "metadata": { - "description": "AVD network security group custom name. (Default: nsg-avd-app1-dev-use2-001)" - } - }, - "privateEndpointNetworksecurityGroupCustomName": { - "type": "string", - "defaultValue": "nsg-pe-app1-dev-use2-001", - "maxLength": 80, - "metadata": { - "description": "Private endpoint network security group custom name. (Default: nsg-pe-app1-dev-use2-001)" - } - }, - "anfNetworksecurityGroupCustomName": { - "type": "string", - "defaultValue": "nsg-anf-app1-dev-use2-001", - "maxLength": 80, - "metadata": { - "description": "ANF network security group custom name. (Default: nsg-anf-app1-dev-use2-001)" - } - }, - "avdRouteTableCustomName": { - "type": "string", - "defaultValue": "route-avd-app1-dev-use2-001", - "maxLength": 80, - "metadata": { - "description": "AVD route table custom name. (Default: route-avd-app1-dev-use2-001)" - } - }, - "privateEndpointRouteTableCustomName": { - "type": "string", - "defaultValue": "route-pe-app1-dev-use2-001", - "maxLength": 80, - "metadata": { - "description": "Private endpoint route table custom name. (Default: route-avd-app1-dev-use2-001)" - } - }, - "avdApplicationSecurityGroupCustomName": { - "type": "string", - "defaultValue": "asg-app1-dev-use2-001", - "maxLength": 80, - "metadata": { - "description": "AVD application security custom name. (Default: asg-app1-dev-use2-001)" - } - }, - "avdWorkSpaceCustomName": { - "type": "string", - "defaultValue": "vdws-app1-dev-use2-001", - "maxLength": 64, - "metadata": { - "description": "AVD workspace custom name. (Default: vdws-app1-dev-use2-001)" - } - }, - "avdWorkSpaceCustomFriendlyName": { - "type": "string", - "defaultValue": "App1 - Dev - East US 2 - 001", - "maxLength": 64, - "metadata": { - "description": "AVD workspace custom friendly (Display) name. (Default: App1 - Dev - East US 2 - 001)" - } - }, - "avdHostPoolCustomName": { - "type": "string", - "defaultValue": "vdpool-app1-dev-use2-001", - "maxLength": 64, - "metadata": { - "description": "AVD host pool custom name. (Default: vdpool-app1-dev-use2-001)" - } - }, - "avdHostPoolCustomFriendlyName": { - "type": "string", - "defaultValue": "App1 - Dev - East US 2 - 001", - "maxLength": 64, - "metadata": { - "description": "AVD host pool custom friendly (Display) name. (Default: App1 - East US - Dev - 001)" - } - }, - "avdScalingPlanCustomName": { - "type": "string", - "defaultValue": "vdscaling-app1-dev-use2-001", - "maxLength": 64, - "metadata": { - "description": "AVD scaling plan custom name. (Default: vdscaling-app1-dev-use2-001)" - } - }, - "avdApplicationGroupCustomName": { - "type": "string", - "defaultValue": "vdag-desktop-app1-dev-use2-001", - "maxLength": 64, - "metadata": { - "description": "AVD desktop application group custom name. (Default: vdag-desktop-app1-dev-use2-001)" - } - }, - "avdApplicationGroupCustomFriendlyName": { - "type": "string", - "defaultValue": "Desktops - App1 - Dev - East US 2 - 001", - "maxLength": 64, - "metadata": { - "description": "AVD desktop application group custom friendly (Display) name. (Default: Desktops - App1 - East US - Dev - 001)" - } - }, - "avdSessionHostCustomNamePrefix": { - "type": "string", - "defaultValue": "vmapp1duse2", - "maxLength": 11, - "metadata": { - "description": "AVD session host prefix custom name. (Default: vmapp1duse2)" - } - }, - "storageAccountPrefixCustomName": { - "type": "string", - "defaultValue": "st", - "maxLength": 2, - "metadata": { - "description": "AVD FSLogix and App Attach storage account prefix custom name. (Default: st)" - } - }, - "anfAccountCustomName": { - "type": "string", - "defaultValue": "anf-acc-app1-dev-use2-001", - "metadata": { - "description": "AVD FSLogix and App Attach storage account prefix custom name. (Default: anf-acc-app1-dev-use2-001)" - } - }, - "fslogixFileShareCustomName": { - "type": "string", - "defaultValue": "fslogix-pc-app1-dev-use2-001", - "metadata": { - "description": "FSLogix file share name. (Default: fslogix-pc-app1-dev-001)" - } - }, - "appAttachFileShareCustomName": { - "type": "string", - "defaultValue": "appa-app1-dev-use2-001", - "metadata": { - "description": "App Attach file share name. (Default: appa-app1-dev-001)" - } - }, - "avdWrklKvPrefixCustomName": { - "type": "string", - "defaultValue": "kv-sec", - "maxLength": 6, - "metadata": { - "description": "AVD keyvault prefix custom name (with Zero Trust to store credentials to domain join and local admin). (Default: kv-sec)" - } - }, - "ztDiskEncryptionSetCustomNamePrefix": { - "type": "string", - "defaultValue": "des-zt", - "maxLength": 6, - "metadata": { - "description": "AVD disk encryption set custom name. (Default: des-zt)" - } - }, - "ztKvPrefixCustomName": { - "type": "string", - "defaultValue": "kv-key", - "maxLength": 6, - "metadata": { - "description": "AVD key vault custom name for zero trust and store store disk encryption key (Default: kv-key)" - } - }, - "createResourceTags": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Apply tags on resources and resource groups. (Default: false)" - } - }, - "workloadNameTag": { - "type": "string", - "defaultValue": "Contoso-Workload", - "metadata": { - "description": "The name of workload for tagging purposes. (Default: Contoso-Workload)" - } - }, - "workloadTypeTag": { - "type": "string", - "defaultValue": "Light", - "allowedValues": [ - "", - "Light", - "Medium", - "High", - "Power" - ], - "metadata": { - "description": "Reference to the size of the VM for your workloads (Default: Light)" - } - }, - "dataClassificationTag": { - "type": "string", - "defaultValue": "Non-business", - "allowedValues": [ - "", - "Non-business", - "Public", - "General", - "Confidential", - "Highly-confidential" - ], - "metadata": { - "description": "Sensitivity of data hosted (Default: Non-business)" - } - }, - "departmentTag": { - "type": "string", - "defaultValue": "Contoso-AVD", - "metadata": { - "description": "Department that owns the deployment, (Dafult: Contoso-AVD)" - } - }, - "workloadCriticalityTag": { - "type": "string", - "defaultValue": "Low", - "allowedValues": [ - "", - "Low", - "Medium", - "High", - "Mission-critical", - "Custom" - ], - "metadata": { - "description": "Criticality of the workload. (Default: Low)" - } - }, - "workloadCriticalityCustomValueTag": { - "type": "string", - "defaultValue": "Contoso-Critical", - "metadata": { - "description": "Tag value for custom criticality value. (Default: Contoso-Critical)" - } - }, - "applicationNameTag": { - "type": "string", - "defaultValue": "Contoso-App", - "metadata": { - "description": "Details about the application." - } - }, - "workloadSlaTag": { - "type": "string", - "defaultValue": "Contoso-SLA", - "metadata": { - "description": "Service level agreement level of the worload. (Contoso-SLA)" - } - }, - "opsTeamTag": { - "type": "string", - "defaultValue": "workload-admins@Contoso.com", - "metadata": { - "description": "Team accountable for day-to-day operations. (workload-admins@Contoso.com)" - } - }, - "ownerTag": { - "type": "string", - "defaultValue": "workload-owner@Contoso.com", - "metadata": { - "description": "Organizational owner of the AVD deployment. (Default: workload-owner@Contoso.com)" - } - }, - "costCenterTag": { - "type": "string", - "defaultValue": "Contoso-CC", - "metadata": { - "description": "Cost center of owner team. (Default: Contoso-CC)" - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Enable usage and telemetry feedback to Microsoft." - } - }, - "enableKvPurgeProtection": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Enable purge protection for the keyvaults. (Default: true)" - } - }, - "deployAntiMalwareExt": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Deploys anti malware extension on session hosts. (Default: true)" - } - }, - "customStaticRoutes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Additional customer-provided static routes to be added to the route tables." - } - }, - "deployDefender": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable Microsoft Defender on the subscription. (Default: false)" - } - }, - "enableDefForServers": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Enable Microsoft Defender for servers. (Default: true)" - } - }, - "enableDefForStorage": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Enable Microsoft Defender for storage. (Default: true)" - } - }, - "enableDefForKeyVault": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Enable Microsoft Defender for Key Vault. (Default: true)" - } - }, - "enableDefForArm": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Enable Microsoft Defender for Azure Resource Manager. (Default: true)" - } - } - }, - "variables": { - "$fxv#0": { - "australiacentral": { - "acronym": "auc", - "timeDifference": "+10:00", - "timeZone": "AUS Eastern Standard Time" - }, - "australiacentral2": { - "acronym": "auc2", - "timeDifference": "+10:00", - "timeZone": "AUS Eastern Standard Time" - }, - "australiaeast": { - "acronym": "aue", - "timeDifference": "+10:00", - "timeZone": "AUS Eastern Standard Time" - }, - "australiasoutheast": { - "acronym": "ause", - "timeDifference": "+10:00", - "timeZone": "AUS Eastern Standard Time" - }, - "brazilsouth": { - "acronym": "brs", - "timeDifference": "-3:00", - "timeZone": "E. South America Standard Time" - }, - "brazilsoutheast": { - "acronym": "brse", - "timeDifference": "-3:00", - "timeZone": "E. South America Standard Time" - }, - "canadacentral": { - "acronym": "cac", - "timeDifference": "-5:00", - "timeZone": "Eastern Standard Time" - }, - "canadaeast": { - "acronym": "cae", - "timeDifference": "-5:00", - "timeZone": "Eastern Standard Time" - }, - "centralindia": { - "acronym": "inc", - "timeDifference": "+5:30", - "timeZone": "India Standard Time" - }, - "centralus": { - "acronym": "usc", - "timeDifference": "-6:00", - "timeZone": "Central Standard Time" - }, - "chinaeast": { - "acronym": "cne", - "timeDifference": "+8:00", - "timeZone": "China Standard Time" - }, - "chinaeast2": { - "acronym": "cne2", - "timeDifference": "+8:00", - "timeZone": "China Standard Time" - }, - "chinanorth": { - "acronym": "cnn", - "timeDifference": "+8:00", - "timeZone": "China Standard Time" - }, - "chinanorth2": { - "acronym": "cnn2", - "timeDifference": "+8:00", - "timeZone": "China Standard Time" - }, - "chinanorth3": { - "acronym": "cnn3", - "timeDifference": "+8:00", - "timeZone": "China Standard Time" - }, - "eastasia": { - "acronym": "ase", - "timeDifference": "+8:00", - "timeZone": "China Standard Time" - }, - "eastus": { - "acronym": "use", - "timeDifference": "-5:00", - "timeZone": "Eastern Standard Time" - }, - "eastus2": { - "acronym": "use2", - "timeDifference": "-5:00", - "timeZone": "Eastern Standard Time" - }, - "francecentral": { - "acronym": "frc", - "timeDifference": "+1:00", - "timeZone": "Central Europe Standard Time" - }, - "francesouth": { - "acronym": "frs", - "timeDifference": "+1:00", - "timeZone": "Central Europe Standard Time" - }, - "germanynorth": { - "acronym": "den", - "timeDifference": "+1:00", - "timeZone": "Central Europe Standard Time" - }, - "germanywestcentral": { - "acronym": "dewc", - "timeDifference": "+1:00", - "timeZone": "Central Europe Standard Time" - }, - "japaneast": { - "acronym": "jpe", - "timeDifference": "+9:00", - "timeZone": "Tokyo Standard Time" - }, - "japanwest": { - "acronym": "jpw", - "timeDifference": "+9:00", - "timeZone": "Tokyo Standard Time" - }, - "jioindiacentral": { - "acronym": "injc", - "timeDifference": "+5:30", - "timeZone": "India Standard Time" - }, - "jioindiawest": { - "acronym": "injw", - "timeDifference": "+5:30", - "timeZone": "India Standard Time" - }, - "koreacentral": { - "acronym": "krc", - "timeDifference": "+9:00", - "timeZone": "Korea Standard Time" - }, - "koreasouth": { - "acronym": "krs", - "timeDifference": "+9:00", - "timeZone": "Korea Standard Time" - }, - "northcentralus": { - "acronym": "usnc", - "timeDifference": "-6:00", - "timeZone": "Central Standard Time" - }, - "northeurope": { - "acronym": "eun", - "timeDifference": "0:00", - "timeZone": "GMT Standard Time" - }, - "norwayeast": { - "acronym": "noe", - "timeDifference": "+1:00", - "timeZone": "Central Europe Standard Time" - }, - "norwaywest": { - "acronym": "now", - "timeDifference": "+1:00", - "timeZone": "Central Europe Standard Time" - }, - "italynorth": { - "acronym": "itn", - "timeDifference": "+1:00", - "timeZone": "Central Europe Standard Time" - }, - "southafricanorth": { - "acronym": "zan", - "timeDifference": "+2:00", - "timeZone": "South Africa Standard Time" - }, - "southafricawest": { - "acronym": "zaw", - "timeDifference": "+2:00", - "timeZone": "South Africa Standard Time" - }, - "southcentralus": { - "acronym": "ussc", - "timeDifference": "-6:00", - "timeZone": "Central Standard Time" - }, - "southeastasia": { - "acronym": "asse", - "timeDifference": "+8:00", - "timeZone": "Singapore Standard Time" - }, - "southindia": { - "acronym": "ins", - "timeDifference": "+5:30", - "timeZone": "India Standard Time" - }, - "swedencentral": { - "acronym": "sec", - "timeDifference": "+1:00", - "timeZone": "Central Europe Standard Time" - }, - "switzerlandnorth": { - "acronym": "chn", - "timeDifference": "+1:00", - "timeZone": "Central Europe Standard Time" - }, - "switzerlandwest": { - "acronym": "chw", - "timeDifference": "+1:00", - "timeZone": "Central Europe Standard Time" - }, - "uaecentral": { - "acronym": "aec", - "timeDifference": "+3:00", - "timeZone": "Arabian Standard Time" - }, - "uaenorth": { - "acronym": "aen", - "timeDifference": "+3:00", - "timeZone": "Arabian Standard Time" - }, - "uksouth": { - "acronym": "uks", - "timeDifference": "0:00", - "timeZone": "GMT Standard Time" - }, - "ukwest": { - "acronym": "ukw", - "timeDifference": "0:00", - "timeZone": "GMT Standard Time" - }, - "usdodcentral": { - "acronym": "dodc", - "timeDifference": "-6:00", - "timeZone": "Central Standard Time" - }, - "usdodeast": { - "acronym": "dode", - "timeDifference": "-5:00", - "timeZone": "Eastern Standard Time" - }, - "usgovarizona": { - "acronym": "az", - "timeDifference": "-7:00", - "timeZone": "Mountain Standard Time" - }, - "usgovtexas": { - "acronym": "tx", - "timeDifference": "-6:00", - "timeZone": "Central Standard Time" - }, - "usgovvirginia": { - "acronym": "va", - "timeDifference": "-5:00", - "timeZone": "Eastern Standard Time" - }, - "westcentralus": { - "acronym": "uswc", - "timeDifference": "-7:00", - "timeZone": "Mountain Standard Time" - }, - "westeurope": { - "acronym": "euw", - "timeDifference": "+1:00", - "timeZone": "Central Europe Standard Time" - }, - "westindia": { - "acronym": "inw", - "timeDifference": "+5:30", - "timeZone": "India Standard Time" - }, - "westus": { - "acronym": "usw", - "timeDifference": "-8:00", - "timeZone": "Pacific Standard Time" - }, - "westus2": { - "acronym": "usw2", - "timeDifference": "-8:00", - "timeZone": "Pacific Standard Time" - }, - "westus3": { - "acronym": "usw3", - "timeDifference": "-7:00", - "timeZone": "Mountain Standard Time" - } - }, - "varDeploymentPrefixLowercase": "[toLower(parameters('deploymentPrefix'))]", - "varAzureCloudName": "[environment().name]", - "varDeploymentEnvironmentLowercase": "[toLower(parameters('deploymentEnvironment'))]", - "varDeploymentEnvironmentOneCharacter": "[if(equals(parameters('deploymentEnvironment'), 'Dev'), 'd', if(equals(parameters('deploymentEnvironment'), 'Test'), 't', if(equals(parameters('deploymentEnvironment'), 'Prod'), 'p', '')))]", - "varNamingUniqueStringTwoChar": "[take(format('{0}', uniqueString(parameters('avdWorkloadSubsId'), variables('varDeploymentPrefixLowercase'), parameters('time'))), 2)]", - "varSessionHostLocationAcronym": "[variables('varLocations')[variables('varSessionHostLocationLowercase')].acronym]", - "varManagementPlaneLocationAcronym": "[variables('varLocations')[variables('varManagementPlaneLocationLowercase')].acronym]", - "varLocations": "[variables('$fxv#0')]", - "varTimeZoneSessionHosts": "[variables('varLocations')[variables('varSessionHostLocationLowercase')].timeZone]", - "varManagementPlaneNamingStandard": "[format('{0}-{1}-{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentLowercase'), variables('varManagementPlaneLocationAcronym'))]", - "varComputeStorageResourcesNamingStandard": "[format('{0}-{1}-{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentLowercase'), variables('varSessionHostLocationAcronym'))]", - "varDiskEncryptionSetName": "[if(parameters('avdUseCustomNaming'), format('{0}-{1}-001', parameters('ztDiskEncryptionSetCustomNamePrefix'), variables('varComputeStorageResourcesNamingStandard')), format('des-zt-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", - "varSessionHostLocationLowercase": "[toLower(replace(parameters('avdSessionHostLocation'), ' ', ''))]", - "varManagementPlaneLocationLowercase": "[toLower(replace(parameters('avdManagementPlaneLocation'), ' ', ''))]", - "varServiceObjectsRgName": "[if(parameters('avdUseCustomNaming'), parameters('avdServiceObjectsRgCustomName'), format('rg-avd-{0}-service-objects', variables('varManagementPlaneNamingStandard')))]", - "varNetworkObjectsRgName": "[if(parameters('avdUseCustomNaming'), parameters('avdNetworkObjectsRgCustomName'), format('rg-avd-{0}-network', variables('varComputeStorageResourcesNamingStandard')))]", - "varComputeObjectsRgName": "[if(parameters('avdUseCustomNaming'), parameters('avdComputeObjectsRgCustomName'), format('rg-avd-{0}-pool-compute', variables('varComputeStorageResourcesNamingStandard')))]", - "varStorageObjectsRgName": "[if(parameters('avdUseCustomNaming'), parameters('avdStorageObjectsRgCustomName'), format('rg-avd-{0}-storage', variables('varComputeStorageResourcesNamingStandard')))]", - "varMonitoringRgName": "[if(parameters('avdUseCustomNaming'), parameters('avdMonitoringRgCustomName'), format('rg-avd-{0}-{1}-monitoring', variables('varDeploymentEnvironmentLowercase'), variables('varManagementPlaneLocationAcronym')))]", - "varVnetName": "[if(parameters('avdUseCustomNaming'), parameters('avdVnetworkCustomName'), format('vnet-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", - "varHubVnetName": "[if(and(parameters('createAvdVnet'), not(empty(parameters('existingHubVnetResourceId')))), split(parameters('existingHubVnetResourceId'), '/')[8], '')]", - "varVnetPeeringName": "[format('peer-{0}', variables('varHubVnetName'))]", - "varRemoteVnetPeeringName": "[format('peer-{0}', variables('varVnetName'))]", - "varVnetAvdSubnetName": "[if(parameters('avdUseCustomNaming'), parameters('avdVnetworkSubnetCustomName'), format('snet-avd-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", - "varVnetPrivateEndpointSubnetName": "[if(parameters('avdUseCustomNaming'), parameters('privateEndpointVnetworkSubnetCustomName'), format('snet-pe-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", - "varVnetAnfSubnetName": "[if(parameters('avdUseCustomNaming'), parameters('anfVnetworkSubnetCustomName'), format('snet-anf-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", - "varAvdNetworksecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('avdNetworksecurityGroupCustomName'), format('nsg-avd-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", - "varPrivateEndpointNetworksecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('privateEndpointNetworksecurityGroupCustomName'), format('nsg-pe-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", - "varAnfNetworksecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('anfNetworksecurityGroupCustomName'), format('nsg-anf-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", - "varAvdRouteTableName": "[if(parameters('avdUseCustomNaming'), parameters('avdRouteTableCustomName'), format('route-avd-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", - "varPrivateEndpointRouteTableName": "[if(parameters('avdUseCustomNaming'), parameters('privateEndpointRouteTableCustomName'), format('route-pe-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", - "varApplicationSecurityGroupName": "[if(parameters('avdUseCustomNaming'), parameters('avdApplicationSecurityGroupCustomName'), format('asg-{0}-001', variables('varComputeStorageResourcesNamingStandard')))]", - "varDDosProtectionPlanName": "[format('ddos-{0}', variables('varVnetName'))]", - "varWorkSpaceName": "[if(parameters('avdUseCustomNaming'), parameters('avdWorkSpaceCustomName'), format('vdws-{0}-001', variables('varManagementPlaneNamingStandard')))]", - "varWorkSpaceFriendlyName": "[if(parameters('avdUseCustomNaming'), parameters('avdWorkSpaceCustomFriendlyName'), format('Workspace {0} {1} {2} 001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('avdManagementPlaneLocation')))]", - "varHostPoolName": "[if(parameters('avdUseCustomNaming'), parameters('avdHostPoolCustomName'), format('vdpool-{0}-001', variables('varManagementPlaneNamingStandard')))]", - "varHostFriendlyName": "[if(parameters('avdUseCustomNaming'), parameters('avdHostPoolCustomFriendlyName'), format('Hostpool {0} {1} {2} 001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('avdManagementPlaneLocation')))]", - "varHostPoolPreferredAppGroupType": "[toLower(parameters('hostPoolPreferredAppGroupType'))]", - "varApplicationGroupName": "[if(parameters('avdUseCustomNaming'), parameters('avdApplicationGroupCustomName'), format('vdag-{0}-{1}-001', variables('varHostPoolPreferredAppGroupType'), variables('varManagementPlaneNamingStandard')))]", - "varApplicationGroupFriendlyName": "[if(parameters('avdUseCustomNaming'), parameters('avdApplicationGroupCustomFriendlyName'), format('{0} {1} {2} {3} 001', variables('varHostPoolPreferredAppGroupType'), parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('avdManagementPlaneLocation')))]", - "varDeployScalingPlan": "[if(equals(variables('varAzureCloudName'), 'AzureChinaCloud'), false(), parameters('avdDeployScalingPlan'))]", - "varCreateAppAttachDeployment": "[if(equals(variables('varAzureCloudName'), 'AzureChinaCloud'), false(), parameters('createAppAttachDeployment'))]", - "varScalingPlanName": "[if(parameters('avdUseCustomNaming'), parameters('avdScalingPlanCustomName'), format('vdscaling-{0}-001', variables('varManagementPlaneNamingStandard')))]", - "varPrivateEndPointConnectionName": "[format('pe-{0}-connection', variables('varHostPoolName'))]", - "varPrivateEndPointDiscoveryName": "[format('pe-{0}-discovery', variables('varWorkSpaceName'))]", - "varPrivateEndPointWorkspaceName": "[format('pe-{0}-global', variables('varWorkSpaceName'))]", - "varScalingPlanExclusionTag": "[format('exclude-{0}', variables('varScalingPlanName'))]", - "varScalingPlanWeekdaysScheduleName": "[format('Weekdays-{0}', variables('varManagementPlaneNamingStandard'))]", - "varScalingPlanWeekendScheduleName": "[format('Weekend-{0}', variables('varManagementPlaneNamingStandard'))]", - "varWrklKvName": "[if(parameters('avdUseCustomNaming'), format('{0}-{1}-{2}', parameters('avdWrklKvPrefixCustomName'), variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')), format('kv-sec-{0}-{1}', variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')))]", - "varWrklKvPrivateEndpointName": "[format('pe-{0}-vault', variables('varWrklKvName'))]", - "varWrklKeyVaultSku": "[if(or(equals(variables('varAzureCloudName'), 'AzureCloud'), equals(variables('varAzureCloudName'), 'AzureUSGovernment')), 'premium', if(equals(variables('varAzureCloudName'), 'AzureChinaCloud'), 'standard', null()))]", - "varSessionHostNamePrefix": "[if(parameters('avdUseCustomNaming'), parameters('avdSessionHostCustomNamePrefix'), format('vm{0}{1}{2}', variables('varDeploymentPrefixLowercase'), variables('varDeploymentEnvironmentOneCharacter'), variables('varSessionHostLocationAcronym')))]", - "varStorageManagedIdentityName": "[format('id-storage-{0}-001', variables('varComputeStorageResourcesNamingStandard'))]", - "varAlaWorkspaceName": "[if(parameters('avdUseCustomNaming'), parameters('avdAlaWorkspaceCustomName'), format('log-avd-{0}-{1}', variables('varDeploymentEnvironmentLowercase'), variables('varManagementPlaneLocationAcronym')))]", - "varDataCollectionRulesName": "[format('microsoft-avdi-{0}', variables('varSessionHostLocationLowercase'))]", - "varZtKvName": "[if(parameters('avdUseCustomNaming'), format('{0}-{1}-{2}', parameters('ztKvPrefixCustomName'), variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')), format('kv-key-{0}-{1}', variables('varComputeStorageResourcesNamingStandard'), variables('varNamingUniqueStringTwoChar')))]", - "varZtKvPrivateEndpointName": "[format('pe-{0}-vault', variables('varZtKvName'))]", - "varBaseScriptUri": "https://raw.githubusercontent.com/azure/avdaccelerator/anf-fslogix/workload/", - "varSessionHostConfigurationScriptUri": "[format('{0}scripts/Set-SessionHostConfiguration.ps1', variables('varBaseScriptUri'))]", - "varSessionHostConfigurationScript": "Set-SessionHostConfiguration.ps1", - "varMaxSessionHostsPerTemplate": 10, - "varMaxSessionHostsDivisionValue": "[div(parameters('avdDeploySessionHostsCount'), variables('varMaxSessionHostsPerTemplate'))]", - "varMaxSessionHostsDivisionRemainderValue": "[mod(parameters('avdDeploySessionHostsCount'), variables('varMaxSessionHostsPerTemplate'))]", - "varSessionHostBatchCount": "[if(greater(variables('varMaxSessionHostsDivisionRemainderValue'), 0), add(variables('varMaxSessionHostsDivisionValue'), 1), variables('varMaxSessionHostsDivisionValue'))]", - "varHostPoolAgentUpdateSchedule": [ - { - "dayOfWeek": "Tuesday", - "hour": 18 - }, - { - "dayOfWeek": "Friday", - "hour": 17 - } - ], - "varPersonalScalingPlanSchedules": [ - { - "daysOfWeek": [ - "Monday", - "Wednesday", - "Thursday", - "Friday" - ], - "name": "[variables('varScalingPlanWeekdaysScheduleName')]", - "offPeakStartTime": { - "hour": 20, - "minute": 0 - }, - "offPeakStartVMOnConnect": "Enable", - "offPeakMinutesToWaitOnDisconnect": 30, - "offPeakActionOnDisconnect": "Hibernate", - "offPeakMinutesToWaitOnLogoff": 0, - "offPeakActionOnLogoff": "Deallocate", - "peakStartTime": { - "hour": 9, - "minute": 0 - }, - "peakStartVMOnConnect": "Enable", - "peakMinutesToWaitOnDisconnect": 30, - "peakActionOnDisconnect": "Hibernate", - "peakMinutesToWaitOnLogoff": 0, - "peakActionOnLogoff": "Deallocate", - "rampDownStartTime": { - "hour": 18, - "minute": 0 - }, - "rampDownStartVMOnConnect": "Enable", - "rampDownMinutesToWaitOnDisconnect": 30, - "rampDownActionOnDisconnect": "Hibernate", - "rampDownMinutesToWaitOnLogoff": 0, - "rampDownActionOnLogoff": "Deallocate", - "rampUpStartTime": { - "hour": 7, - "minute": 0 - }, - "rampUpAutoStartHosts": "WithAssignedUser", - "rampUpStartVMOnConnect": "Enable", - "rampUpMinutesToWaitOnDisconnect": 30, - "rampUpActionOnDisconnect": "Hibernate", - "rampUpMinutesToWaitOnLogoff": 0, - "rampUpActionOnLogoff": "Deallocate" - }, - { - "daysOfWeek": [ - "Tuesday" - ], - "name": "[format('{0}-agent-updates', variables('varScalingPlanWeekdaysScheduleName'))]", - "offPeakStartTime": { - "hour": 20, - "minute": 0 - }, - "offPeakStartVMOnConnect": "Enable", - "offPeakMinutesToWaitOnDisconnect": 30, - "offPeakActionOnDisconnect": "Hibernate", - "offPeakMinutesToWaitOnLogoff": 0, - "offPeakActionOnLogoff": "Deallocate", - "peakStartTime": { - "hour": 9, - "minute": 0 - }, - "peakStartVMOnConnect": "Enable", - "peakMinutesToWaitOnDisconnect": 30, - "peakActionOnDisconnect": "Hibernate", - "peakMinutesToWaitOnLogoff": 0, - "peakActionOnLogoff": "Deallocate", - "rampDownStartTime": { - "hour": 18, - "minute": 0 - }, - "rampDownStartVMOnConnect": "Enable", - "rampDownMinutesToWaitOnDisconnect": 30, - "rampDownActionOnDisconnect": "Hibernate", - "rampDownMinutesToWaitOnLogoff": 0, - "rampDownActionOnLogoff": "Deallocate", - "rampUpStartTime": { - "hour": 7, - "minute": 0 - }, - "rampUpAutoStartHosts": "WithAssignedUser", - "rampUpStartVMOnConnect": "Enable", - "rampUpMinutesToWaitOnDisconnect": 30, - "rampUpActionOnDisconnect": "Hibernate", - "rampUpMinutesToWaitOnLogoff": 0, - "rampUpActionOnLogoff": "Deallocate" - }, - { - "daysOfWeek": [ - "Saturday", - "Sunday" - ], - "name": "[variables('varScalingPlanWeekendScheduleName')]", - "offPeakStartTime": { - "hour": 18, - "minute": 0 - }, - "offPeakStartVMOnConnect": "Enable", - "offPeakMinutesToWaitOnDisconnect": 30, - "offPeakActionOnDisconnect": "Hibernate", - "offPeakMinutesToWaitOnLogoff": 0, - "offPeakActionOnLogoff": "Deallocate", - "peakStartTime": { - "hour": 10, - "minute": 0 - }, - "peakStartVMOnConnect": "Enable", - "peakMinutesToWaitOnDisconnect": 30, - "peakActionOnDisconnect": "Hibernate", - "peakMinutesToWaitOnLogoff": 0, - "peakActionOnLogoff": "Deallocate", - "rampDownStartTime": { - "hour": 16, - "minute": 0 - }, - "rampDownStartVMOnConnect": "Enable", - "rampDownMinutesToWaitOnDisconnect": 30, - "rampDownActionOnDisconnect": "Hibernate", - "rampDownMinutesToWaitOnLogoff": 0, - "rampDownActionOnLogoff": "Deallocate", - "rampUpStartTime": { - "hour": 9, - "minute": 0 - }, - "rampUpAutoStartHosts": "None", - "rampUpStartVMOnConnect": "Enable", - "rampUpMinutesToWaitOnDisconnect": 30, - "rampUpActionOnDisconnect": "Hibernate", - "rampUpMinutesToWaitOnLogoff": 0, - "rampUpActionOnLogoff": "Deallocate" - } - ], - "varPooledScalingPlanSchedules": [ - { - "daysOfWeek": [ - "Monday", - "Wednesday", - "Thursday", - "Friday" - ], - "name": "[variables('varScalingPlanWeekdaysScheduleName')]", - "offPeakLoadBalancingAlgorithm": "DepthFirst", - "offPeakStartTime": { - "hour": 20, - "minute": 0 - }, - "peakLoadBalancingAlgorithm": "DepthFirst", - "peakStartTime": { - "hour": 9, - "minute": 0 - }, - "rampDownCapacityThresholdPct": 90, - "rampDownForceLogoffUsers": true, - "rampDownLoadBalancingAlgorithm": "DepthFirst", - "rampDownMinimumHostsPct": 0, - "rampDownNotificationMessage": "You will be logged off in 30 min. Make sure to save your work.", - "rampDownStartTime": { - "hour": 18, - "minute": 0 - }, - "rampDownStopHostsWhen": "ZeroActiveSessions", - "rampDownWaitTimeMinutes": 30, - "rampUpCapacityThresholdPct": 80, - "rampUpLoadBalancingAlgorithm": "BreadthFirst", - "rampUpMinimumHostsPct": 20, - "rampUpStartTime": { - "hour": 7, - "minute": 0 - } - }, - { - "daysOfWeek": [ - "Tuesday" - ], - "name": "[format('{0}-agent-updates', variables('varScalingPlanWeekdaysScheduleName'))]", - "offPeakLoadBalancingAlgorithm": "DepthFirst", - "offPeakStartTime": { - "hour": 20, - "minute": 0 - }, - "peakLoadBalancingAlgorithm": "DepthFirst", - "peakStartTime": { - "hour": 9, - "minute": 0 - }, - "rampDownCapacityThresholdPct": 90, - "rampDownForceLogoffUsers": true, - "rampDownLoadBalancingAlgorithm": "DepthFirst", - "rampDownMinimumHostsPct": 0, - "rampDownNotificationMessage": "You will be logged off in 30 min. Make sure to save your work.", - "rampDownStartTime": { - "hour": 19, - "minute": 0 - }, - "rampDownStopHostsWhen": "ZeroActiveSessions", - "rampDownWaitTimeMinutes": 30, - "rampUpCapacityThresholdPct": 80, - "rampUpLoadBalancingAlgorithm": "BreadthFirst", - "rampUpMinimumHostsPct": 20, - "rampUpStartTime": { - "hour": 7, - "minute": 0 - } - }, - { - "daysOfWeek": [ - "Saturday", - "Sunday" - ], - "name": "[variables('varScalingPlanWeekendScheduleName')]", - "offPeakLoadBalancingAlgorithm": "DepthFirst", - "offPeakStartTime": { - "hour": 18, - "minute": 0 - }, - "peakLoadBalancingAlgorithm": "DepthFirst", - "peakStartTime": { - "hour": 10, - "minute": 0 - }, - "rampDownCapacityThresholdPct": 90, - "rampDownForceLogoffUsers": true, - "rampDownLoadBalancingAlgorithm": "DepthFirst", - "rampDownMinimumHostsPct": 0, - "rampDownNotificationMessage": "You will be logged off in 30 min. Make sure to save your work.", - "rampDownStartTime": { - "hour": 16, - "minute": 0 - }, - "rampDownStopHostsWhen": "ZeroActiveSessions", - "rampDownWaitTimeMinutes": 30, - "rampUpCapacityThresholdPct": 90, - "rampUpLoadBalancingAlgorithm": "DepthFirst", - "rampUpMinimumHostsPct": 0, - "rampUpStartTime": { - "hour": 9, - "minute": 0 - } - } - ], - "varAllDnsServers": "[format('{0},168.63.129.16', parameters('customDnsIps'))]", - "varDnsServers": "[if(empty(parameters('customDnsIps')), createArray(), split(variables('varAllDnsServers'), ','))]", - "varCreateVnetPeering": "[if(not(empty(parameters('existingHubVnetResourceId'))), true(), false())]", - "varTagsWithValues": "[union(if(empty(parameters('workloadNameTag')), createObject(), createObject('WorkloadName', parameters('workloadNameTag'))), if(empty(parameters('workloadTypeTag')), createObject(), createObject('WorkloadType', parameters('workloadTypeTag'))), if(empty(parameters('dataClassificationTag')), createObject(), createObject('DataClassification', parameters('dataClassificationTag'))), if(empty(parameters('departmentTag')), createObject(), createObject('Department', parameters('departmentTag'))), if(empty(parameters('workloadCriticalityTag')), createObject(), createObject('Criticality', if(equals(parameters('workloadCriticalityTag'), 'Custom'), parameters('workloadCriticalityCustomValueTag'), parameters('workloadCriticalityTag')))), if(empty(parameters('applicationNameTag')), createObject(), createObject('ApplicationName', parameters('applicationNameTag'))), if(empty(parameters('workloadSlaTag')), createObject(), createObject('ServiceClass', parameters('workloadSlaTag'))), if(empty(parameters('opsTeamTag')), createObject(), createObject('OpsTeam', parameters('opsTeamTag'))), if(empty(parameters('ownerTag')), createObject(), createObject('Owner', parameters('ownerTag'))), if(empty(parameters('costCenterTag')), createObject(), createObject('CostCenter', parameters('costCenterTag'))))]", - "varCustomResourceTags": "[if(parameters('createResourceTags'), variables('varTagsWithValues'), createObject())]", - "varAllComputeStorageTags": "[if(contains(parameters('avdIdentityServiceProvider'), 'EntraID'), createObject('IdentityServiceProvider', parameters('avdIdentityServiceProvider')), createObject('DomainName', parameters('identityDomainName'), 'IdentityServiceProvider', parameters('avdIdentityServiceProvider')))]", - "varAvdDefaultTags": { - "cm-resource-parent": "[format('/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.DesktopVirtualization/hostpools/{2}', parameters('avdWorkloadSubsId'), variables('varServiceObjectsRgName'), variables('varHostPoolName'))]", - "Environment": "[parameters('deploymentEnvironment')]", - "ServiceWorkload": "AVD", - "CreationTimeUTC": "[parameters('time')]" - }, - "varWorkloadKeyvaultTag": { - "Purpose": "Secrets for local admin and domain join credentials" - }, - "varZtKeyvaultTag": { - "Purpose": "Disk encryption keys for zero trust" - }, - "varTelemetryId": "[format('pid-2ce4228c-d72c-43fb-bb5b-cd8f3ba2138e-{0}', parameters('avdManagementPlaneLocation'))]", - "varResourceGroups": [ - { - "purpose": "Service-Objects", - "name": "[variables('varServiceObjectsRgName')]", - "location": "[parameters('avdManagementPlaneLocation')]", - "enableDefaultTelemetry": false, - "tags": "[if(parameters('createResourceTags'), union(variables('varCustomResourceTags'), variables('varAvdDefaultTags')), union(variables('varAvdDefaultTags'), variables('varAllComputeStorageTags')))]" - }, - { - "purpose": "Pool-Compute", - "name": "[variables('varComputeObjectsRgName')]", - "location": "[parameters('avdSessionHostLocation')]", - "enableDefaultTelemetry": false, - "tags": "[if(parameters('createResourceTags'), union(variables('varAllComputeStorageTags'), variables('varAvdDefaultTags')), union(variables('varAvdDefaultTags'), variables('varAllComputeStorageTags')))]" - } - ], - "varSecurityPrincipalId": "[if(not(empty(parameters('avdSecurityGroups'))), parameters('avdSecurityGroups')[0].objectId, '')]", - "varSecurityPrincipalName": "[if(not(empty(parameters('avdSecurityGroups'))), parameters('avdSecurityGroups')[0].displayName, '')]", - "varCreateStorageDeployment": "[if(or(parameters('createFslogixDeployment'), parameters('createAppAttachDeployment')), true(), false())]" - }, - "resources": [ - { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[variables('varTelemetryId')]", - "location": "[parameters('avdManagementPlaneLocation')]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [] - } - } - }, - { - "condition": "[or(parameters('createAvdVnet'), parameters('createPrivateDnsZones'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Deploy-Network-RG-{0}', parameters('time'))]", - "subscriptionId": "[parameters('avdWorkloadSubsId')]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('varNetworkObjectsRgName')]" - }, - "location": { - "value": "[parameters('avdSessionHostLocation')]" - }, - "enableTelemetry": { - "value": false - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "5574722192240323807" - }, - "name": "Resource Groups", - "description": "This module deploys a Resource Group.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Resource Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[deployment().location]", - "metadata": { - "description": "Optional. Location of the Resource Group. It uses the deployment's location when not provided." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the storage account resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.resources-resourcegroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "location": "[parameters('location')]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "resourceGroup": { - "type": "Microsoft.Resources/resourceGroups", - "apiVersion": "2021-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": {} - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the resource group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the resource group." - }, - "value": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('resourceGroup', '2021-04-01', 'full').location]" - } - } - } - } - }, - { - "copy": { - "name": "baselineResourceGroups", - "count": "[length(variables('varResourceGroups'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}', variables('varResourceGroups')[copyIndex()].purpose, parameters('time'))]", - "subscriptionId": "[parameters('avdWorkloadSubsId')]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('varResourceGroups')[copyIndex()].name]" - }, - "location": { - "value": "[variables('varResourceGroups')[copyIndex()].location]" - }, - "enableTelemetry": { - "value": "[variables('varResourceGroups')[copyIndex()].enableDefaultTelemetry]" - }, - "tags": { - "value": "[variables('varResourceGroups')[copyIndex()].tags]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "5574722192240323807" - }, - "name": "Resource Groups", - "description": "This module deploys a Resource Group.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Resource Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[deployment().location]", - "metadata": { - "description": "Optional. Location of the Resource Group. It uses the deployment's location when not provided." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the storage account resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.resources-resourcegroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "location": "[parameters('location')]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "resourceGroup": { - "type": "Microsoft.Resources/resourceGroups", - "apiVersion": "2021-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": {} - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the resource group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the resource group." - }, - "value": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('resourceGroup', '2021-04-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[variables('varCreateStorageDeployment')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-RG-{0}', parameters('time'))]", - "subscriptionId": "[parameters('avdWorkloadSubsId')]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('varStorageObjectsRgName')]" - }, - "location": { - "value": "[parameters('avdSessionHostLocation')]" - }, - "enableTelemetry": { - "value": false - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varAllComputeStorageTags'), variables('varAvdDefaultTags'))), createObject('value', union(variables('varAvdDefaultTags'), variables('varAllComputeStorageTags'))))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "5574722192240323807" - }, - "name": "Resource Groups", - "description": "This module deploys a Resource Group.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Resource Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[deployment().location]", - "metadata": { - "description": "Optional. Location of the Resource Group. It uses the deployment's location when not provided." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the storage account resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.resources-resourcegroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "location": "[parameters('location')]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "resourceGroup": { - "type": "Microsoft.Resources/resourceGroups", - "apiVersion": "2021-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": {} - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the resource group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the resource group." - }, - "value": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('resourceGroup', '2021-04-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[parameters('avdDeployMonitoring')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Monitoring-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('avdManagementPlaneLocation')]" - }, - "deployAlaWorkspace": { - "value": "[parameters('deployAlaWorkspace')]" - }, - "computeObjectsRgName": { - "value": "[variables('varComputeObjectsRgName')]" - }, - "serviceObjectsRgName": { - "value": "[variables('varServiceObjectsRgName')]" - }, - "dataCollectionRulesName": { - "value": "[variables('varDataCollectionRulesName')]" - }, - "storageObjectsRgName": "[if(variables('varCreateStorageDeployment'), createObject('value', variables('varStorageObjectsRgName')), createObject('value', ''))]", - "networkObjectsRgName": "[if(parameters('createAvdVnet'), createObject('value', variables('varNetworkObjectsRgName')), createObject('value', ''))]", - "monitoringRgName": { - "value": "[variables('varMonitoringRgName')]" - }, - "deployCustomPolicyMonitoring": { - "value": "[parameters('deployCustomPolicyMonitoring')]" - }, - "alaWorkspaceId": "[if(parameters('deployAlaWorkspace'), createObject('value', ''), createObject('value', parameters('alaExistingWorkspaceResourceId')))]", - "alaWorkspaceName": "[if(parameters('deployAlaWorkspace'), createObject('value', variables('varAlaWorkspaceName')), createObject('value', ''))]", - "alaWorkspaceDataRetention": { - "value": "[parameters('avdAlaWorkspaceDataRetention')]" - }, - "subscriptionId": { - "value": "[parameters('avdWorkloadSubsId')]" - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "8859176354402895974" - }, - "name": "AVD LZA insights monitoring", - "description": "This module deploys Log analytics workspace, DCR and policies", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy AVD management plane." - } - }, - "subscriptionId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "deployAlaWorkspace": { - "type": "bool", - "metadata": { - "description": "create new Azure log analytics workspace." - } - }, - "deployCustomPolicyMonitoring": { - "type": "bool", - "metadata": { - "description": "Create and assign custom Azure Policy for diagnostic settings for the AVD Log Analytics workspace." - } - }, - "alaWorkspaceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Exisintg Azure log analytics workspace resource." - } - }, - "monitoringRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for monitoring resources." - } - }, - "computeObjectsRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for compute resources." - } - }, - "serviceObjectsRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for the service objects." - } - }, - "storageObjectsRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for the storage resources." - } - }, - "networkObjectsRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for the network resources." - } - }, - "alaWorkspaceName": { - "type": "string", - "metadata": { - "description": "Azure log analytics workspace name." - } - }, - "dataCollectionRulesName": { - "type": "string", - "metadata": { - "description": "Data collection rules name." - } - }, - "alaWorkspaceDataRetention": { - "type": "int", - "metadata": { - "description": " Azure log analytics workspace name data retention." - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - } - }, - "variables": { - "varAlaWorkspaceIdSplitId": "[split(parameters('alaWorkspaceId'), '/')]" - }, - "resources": [ - { - "condition": "[or(parameters('deployAlaWorkspace'), and(not(parameters('deployAlaWorkspace')), not(empty(parameters('alaWorkspaceId')))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Monitoing-RG-{0}', parameters('time'))]", - "subscriptionId": "[parameters('subscriptionId')]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('monitoringRgName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": false - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "5574722192240323807" - }, - "name": "Resource Groups", - "description": "This module deploys a Resource Group.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Resource Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[deployment().location]", - "metadata": { - "description": "Optional. Location of the Resource Group. It uses the deployment's location when not provided." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the storage account resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.resources-resourcegroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "location": "[parameters('location')]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "resourceGroup": { - "type": "Microsoft.Resources/resourceGroups", - "apiVersion": "2021-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": {} - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the resource group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the resource group." - }, - "value": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('resourceGroup', '2021-04-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[parameters('deployAlaWorkspace')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('LA-Workspace-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('monitoringRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "name": { - "value": "[parameters('alaWorkspaceName')]" - }, - "dataRetention": { - "value": "[parameters('alaWorkspaceDataRetention')]" - }, - "useResourcePermissions": { - "value": true - }, - "managedIdentities": { - "value": { - "systemAssigned": false - } - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "8971404674064738552" - }, - "name": "Log Analytics Workspaces", - "description": "This module deploys a Log Analytics Workspace.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "managedIdentitiesType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Log Analytics workspace." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "skuName": { - "type": "string", - "defaultValue": "PerGB2018", - "allowedValues": [ - "CapacityReservation", - "Free", - "LACluster", - "PerGB2018", - "PerNode", - "Premium", - "Standalone", - "Standard" - ], - "metadata": { - "description": "Optional. The name of the SKU." - } - }, - "skuCapacityReservationLevel": { - "type": "int", - "defaultValue": 100, - "minValue": 100, - "maxValue": 5000, - "metadata": { - "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." - } - }, - "storageInsightsConfigs": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of storage accounts to be read by the workspace." - } - }, - "dataRetention": { - "type": "int", - "defaultValue": 365, - "minValue": 0, - "maxValue": 730, - "metadata": { - "description": "Optional. Number of days data will be retained for." - } - }, - "dailyQuotaGb": { - "type": "int", - "defaultValue": -1, - "minValue": -1, - "metadata": { - "description": "Optional. The workspace daily quota for ingestion." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics ingestion." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics query." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", - "metadata": { - "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." - } - }, - "useResourcePermissions": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Set to 'true' to use resource or workspace permissions and 'false' (or leave empty) to require workspace permissions." - } - }, - "forceCmkForQuery": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether customer managed storage is mandatory for query management." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "logAnalyticsWorkspace": { - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2022-10-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "features": { - "searchVersion": 1, - "enableLogAccessUsingOnlyResourcePermissions": "[parameters('useResourcePermissions')]" - }, - "sku": { - "name": "[parameters('skuName')]", - "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" - }, - "retentionInDays": "[parameters('dataRetention')]", - "workspaceCapping": { - "dailyQuotaGb": "[parameters('dailyQuotaGb')]" - }, - "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", - "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", - "forceCmkForQuery": "[parameters('forceCmkForQuery')]" - }, - "identity": "[variables('identity')]" - }, - "logAnalyticsWorkspace_storageInsightConfigs": { - "copy": { - "name": "logAnalyticsWorkspace_storageInsightConfigs", - "count": "[length(parameters('storageInsightsConfigs'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "containers": "[if(contains(parameters('storageInsightsConfigs')[copyIndex()], 'containers'), createObject('value', parameters('storageInsightsConfigs')[copyIndex()].containers), createObject('value', createArray()))]", - "tables": "[if(contains(parameters('storageInsightsConfigs')[copyIndex()], 'tables'), createObject('value', parameters('storageInsightsConfigs')[copyIndex()].tables), createObject('value', createArray()))]", - "storageAccountResourceId": { - "value": "[parameters('storageInsightsConfigs')[copyIndex()].storageAccountResourceId]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4384156253703622371" - }, - "name": "Log Analytics Workspace Storage Insight Configs", - "description": "This module deploys a Log Analytics Workspace Storage Insight Config.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", - "metadata": { - "description": "Optional. The name of the storage insights config." - } - }, - "storageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Azure Resource Manager ID of the storage account resource." - } - }, - "containers": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The names of the blob containers that the workspace should read." - } - }, - "tables": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The names of the Azure tables that the workspace should read." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to configure in the resource." - } - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2022-09-01", - "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" - }, - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2022-10-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "storageinsightconfig": { - "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", - "apiVersion": "2020-08-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "containers": "[parameters('containers')]", - "tables": "[parameters('tables')]", - "storageAccount": { - "id": "[parameters('storageAccountResourceId')]", - "key": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', last(split(parameters('storageAccountResourceId'), '/'))), '2022-09-01').keys[0].value]" - } - } - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed storage insights configuration." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the storage insight configuration is deployed." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the storage insights configuration." - }, - "value": "[parameters('name')]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed log analytics workspace." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed log analytics workspace." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed log analytics workspace." - }, - "value": "[parameters('name')]" - }, - "logAnalyticsWorkspaceId": { - "type": "string", - "metadata": { - "description": "The ID associated with the workspace." - }, - "value": "[reference('logAnalyticsWorkspace').customerId]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('logAnalyticsWorkspace', '2022-10-01', 'full').location]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[coalesce(tryGet(tryGet(reference('logAnalyticsWorkspace', '2022-10-01', 'full'), 'identity'), 'principalId'), '')]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('Monitoing-RG-{0}', parameters('time')))]" - ] - }, - { - "condition": "[parameters('deployCustomPolicyMonitoring')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Custom-Policy-Monitoring-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "alaWorkspaceId": "[if(parameters('deployAlaWorkspace'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', parameters('alaWorkspaceId')))]", - "location": { - "value": "[parameters('location')]" - }, - "subscriptionId": { - "value": "[parameters('subscriptionId')]" - }, - "computeObjectsRgName": { - "value": "[parameters('computeObjectsRgName')]" - }, - "serviceObjectsRgName": { - "value": "[parameters('serviceObjectsRgName')]" - }, - "storageObjectsRgName": { - "value": "[parameters('storageObjectsRgName')]" - }, - "networkObjectsRgName": { - "value": "[parameters('networkObjectsRgName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "16349959440930876908" - } - }, - "parameters": { - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy AVD management plane." - } - }, - "subscriptionId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "alaWorkspaceId": { - "type": "string", - "metadata": { - "description": "Exisintg Azure log analytics workspace." - } - }, - "computeObjectsRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for the compute resources." - } - }, - "serviceObjectsRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for the service objects." - } - }, - "networkObjectsRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for the network resources." - } - }, - "storageObjectsRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for the storage resources." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - } - }, - "variables": { - "$fxv#0": { - "AVDScalingPlansDeployDiagnosticLogDeployLogAnalytics": { - "parameters": { - "logAnalytics": { - "value": "[[[parameters('logAnalytics')]" - }, - "effect": { - "value": "[[[parameters('AVDScalingPlansLogAnalyticsEffect')]" - }, - "profileName": { - "value": "[[[parameters('profileName')]" - } - } - }, - "NetworkNICDeployDiagnosticLogDeployLogAnalytics": { - "parameters": { - "logAnalytics": { - "value": "[[[parameters('logAnalytics')]" - }, - "effect": { - "value": "[[[parameters('NetworkNICLogAnalyticsEffect')]" - }, - "profileName": { - "value": "[[[parameters('profileName')]" - } - } - }, - "NetworkSecurityGroupsDeployDiagnosticLogDeployLogAnalytics": { - "parameters": { - "logAnalytics": { - "value": "[[[parameters('logAnalytics')]" - }, - "effect": { - "value": "[[[parameters('NetworkSecurityGroupsLogAnalyticsEffect')]" - }, - "profileName": { - "value": "[[[parameters('profileName')]" - } - } - }, - "AzureFilesDeployDiagnosticLogDeployLogAnalytics": { - "parameters": { - "logAnalytics": { - "value": "[[[parameters('logAnalytics')]" - }, - "effect": { - "value": "[[[parameters('AzureFilesLogAnalyticsEffect')]" - }, - "profileName": { - "value": "[[[parameters('profileName')]" - } - } - }, - "VirtualMachinesDeployDiagnosticLogDeployLogAnalytics": { - "parameters": { - "logAnalytics": { - "value": "[[[parameters('logAnalytics')]" - }, - "effect": { - "value": "[[[parameters('VirtualMachinesLogAnalyticsEffect')]" - }, - "profileName": { - "value": "[[[parameters('profileName')]" - } - } - }, - "VirtualNetworkDeployDiagnosticLogDeployLogAnalytics": { - "parameters": { - "logAnalytics": { - "value": "[[[parameters('logAnalytics')]" - }, - "effect": { - "value": "[[[parameters('VirtualNetworkLogAnalyticsEffect')]" - }, - "profileName": { - "value": "[[[parameters('profileName')]" - } - } - }, - "AVDAppGroupDeployDiagnosticLogDeployLogAnalytics": { - "parameters": { - "logAnalytics": { - "value": "[[[parameters('logAnalytics')]" - }, - "effect": { - "value": "[[[parameters('AVDAppGroupsLogAnalyticsEffect')]" - }, - "profileName": { - "value": "[[[parameters('profileName')]" - } - } - }, - "AVDHostPoolsDeployDiagnosticLogDeployLogAnalytics": { - "parameters": { - "logAnalytics": { - "value": "[[[parameters('logAnalytics')]" - }, - "effect": { - "value": "[[[parameters('AVDHostPoolsLogAnalyticsEffect')]" - }, - "profileName": { - "value": "[[[parameters('profileName')]" - } - } - }, - "AVDWorkspaceDeployDiagnosticLogDeployLogAnalytics": { - "parameters": { - "logAnalytics": { - "value": "[[[parameters('logAnalytics')]" - }, - "effect": { - "value": "[[[parameters('AVDWorkspaceLogAnalyticsEffect')]" - }, - "profileName": { - "value": "[[[parameters('profileName')]" - } - } - } - }, - "$fxv#1": "{\r\n \"name\": \"policy-deploy-diagnostics-avd-application-group\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for AVD Application group to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for AVD Application group to stream to a Log Analytics workspace when any application group which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all and categorys enabled.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.1\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.DesktopVirtualization/applicationGroups\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.DesktopVirtualization/applicationGroups/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"logs\": [\r\n {\r\n \"category\": \"Checkpoint\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Error\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Management\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", - "$fxv#10": "{\r\n \"name\": \"policy-set-deploy-avd-diagnostics-to-log-analytics\",\r\n \"type\": \"Microsoft.Authorization/policySetDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings to AVD Landing Zone\",\r\n \"description\": \"This policy set deploys the configurations of application Azure resources to forward diagnostic logs and metrics to an Azure Log Analytics workspace. See the list of policies of the services that are included \",\r\n \"metadata\": {\r\n \"version\": \"1.1.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"metadata\": {\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"strongType\": \"omsWorkspace\"\r\n },\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"NetworkSecurityGroupsLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for Network Security Groups to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for Network Security Groups to stream to a Log Analytics workspace when any Network Security Groups which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"NetworkNICLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for Network Interfaces to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for Network Interfaces to stream to a Log Analytics workspace when any Network Interfaces which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"VirtualNetworkLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for Virtual Network to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for Virtual Network to stream to a Log Analytics workspace when any Virtual Network which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"VirtualMachinesLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for Virtual Machines to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for Virtual Machines to stream to a Log Analytics workspace when any Virtual Machines which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"AVDScalingPlansLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for AVD Scaling Plans to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for AVD Scaling Plans to stream to a Log Analytics workspace when any application groups which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"AVDAppGroupsLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for AVD Application Groups to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for AVD Application groups to stream to a Log Analytics workspace when any application groups which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"AVDWorkspaceLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for AVD Workspace to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for AVD Workspace to stream to a Log Analytics workspace when any Workspace which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"AVDHostPoolsLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for AVD Host pools to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for AVD Host pools to stream to a Log Analytics workspace when any host pool which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n },\r\n \"AzureFilesLogAnalyticsEffect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Deploy Diagnostic Settings for Azure Files to Log Analytics Workspace\",\r\n \"description\": \"Deploys the diagnostic settings for Azure Files to stream to a Log Analytics workspace when any Azure Files share is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\"\r\n }\r\n }\r\n },\r\n \"policyDefinitions\": [\r\n {\r\n \"policyDefinitionReferenceId\": \"AVDScalingPlansDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-AVDScalingPlans\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('AVDScalingPlansLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"AVDAppGroupDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-AVDAppGroup\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('AVDAppGroupsLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"AVDWorkspaceDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-AVDWorkspace\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('AVDWorkspaceLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"AVDHostPoolsDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-AVDHostPools\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('AVDHostPoolsLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"NetworkSecurityGroupsDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-NetworkSecurityGroups\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('NetworkSecurityGroupsLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"NetworkNICDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-NIC\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('NetworkNICLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"VirtualNetworkDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-VirtualNetwork\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('VirtualNetworkLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"AzureFilesDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-AzureFiles\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('AzureFilesLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n },\r\n {\r\n \"policyDefinitionReferenceId\": \"VirtualMachinesDeployDiagnosticLogDeployLogAnalytics\",\r\n \"policyDefinitionId\": \"${avdWorkloadSubsId}/providers/Microsoft.Authorization/policyDefinitions/Deploy-Diagnostics-VM\",\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[[parameters('logAnalytics')]\"\r\n },\r\n \"effect\": {\r\n \"value\": \"[[parameters('VirtualMachinesLogAnalyticsEffect')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[[parameters('profileName')]\"\r\n }\r\n },\r\n \"groupNames\": []\r\n }\r\n ],\r\n \"policyDefinitionGroups\": null\r\n }\r\n }", - "$fxv#2": "{\r\n \"name\": \"policy-deploy-diagnostics-avd-host-pool\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for AVD Host Pools to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for AVD Host Pools to stream to a Log Analytics workspace when any Host Pools which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all and categorys enabled.\",\r\n \"metadata\": {\r\n \"version\": \"1.1.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.DesktopVirtualization/hostpools\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.DesktopVirtualization/hostpools/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"logs\": [\r\n {\r\n \"category\": \"Checkpoint\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Error\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Management\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Connection\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"HostRegistration\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"AgentHealthStatus\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"NetworkData\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"ConnectionGraphicsData\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"SessionHostManagement\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", - "$fxv#3": "{\r\n \"name\": \"policy-deploy-diagnostics-avd-scaling-plan\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for AVD Scaling Plans to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for AVD Scaling Plans to stream to a Log Analytics workspace when any Scaling Plan which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all and categorys enabled.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.DesktopVirtualization/scalingplans\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.DesktopVirtualization/scalingplans/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"logs\": [\r\n {\r\n \"category\": \"Autoscale\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", - "$fxv#4": "{\r\n \"name\": \"policy-deploy-diagnostics-avd-workspace\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for AVD Workspace to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for AVD Workspace to stream to a Log Analytics workspace when any Workspace which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all and categorys enabled.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.1\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.DesktopVirtualization/workspaces\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.DesktopVirtualization/workspaces/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"logs\": [\r\n {\r\n \"category\": \"Checkpoint\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Error\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Management\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"Feed\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", - "$fxv#5": "{\r\n \"name\": \"policy-deploy-diagnostics-network-security-group\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for Network Security Groups to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for Network Security Groups to stream to a Log Analytics workspace when any Network Security Groups which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Network/networkSecurityGroups\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.Network/networkSecurityGroups/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"metrics\": [],\r\n \"logs\": [\r\n {\r\n \"category\": \"NetworkSecurityGroupEvent\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"NetworkSecurityGroupRuleCounter\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", - "$fxv#6": "{\r\n \"name\": \"policy-deploy-diagnostics-nic\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for Network Interfaces to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for Network Interfaces to stream to a Log Analytics workspace when any Network Interfaces which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable metrics\",\r\n \"description\": \"Whether to enable metrics stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Network/networkInterfaces\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/metrics.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.Network/networkInterfaces/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"metrics\": [\r\n {\r\n \"category\": \"AllMetrics\",\r\n \"timeGrain\": null,\r\n \"enabled\": \"[parameters('metricsEnabled')]\",\r\n \"retentionPolicy\": {\r\n \"enabled\": false,\r\n \"days\": 0\r\n }\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"metricsEnabled\": {\r\n \"value\": \"[parameters('metricsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", - "$fxv#7": "{\r\n \"name\": \"policy-deploy-diagnostics-virtual-machine\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for Virtual Machines to Log Analytics Workspace\",\r\n \"description\": \"CUstom - Deploys the diagnostic settings for Virtual Machines to stream to a Log Analytics workspace when any Virtual Machines which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable metrics\",\r\n \"description\": \"Whether to enable metrics stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Compute/virtualMachines\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/metrics.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.Compute/virtualMachines/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"metrics\": [\r\n {\r\n \"category\": \"AllMetrics\",\r\n \"enabled\": \"[parameters('metricsEnabled')]\",\r\n \"retentionPolicy\": {\r\n \"enabled\": false,\r\n \"days\": 0\r\n }\r\n }\r\n ],\r\n \"logs\": []\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"metricsEnabled\": {\r\n \"value\": \"[parameters('metricsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", - "$fxv#8": "{\r\n \"name\": \"policy-deploy-diagnostics-virtual-network\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for Virtual Network to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for Virtual Network to stream to a Log Analytics workspace when any Virtual Network which is missing this diagnostic settings is created or updated. The Policy will set the diagnostic with all metrics and category enabled\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\"\r\n }\r\n },\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"DeployIfNotExists\",\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n }\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"setbypolicy\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n }\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable metrics\",\r\n \"description\": \"Whether to enable metrics stream to the Log Analytics workspace - True or False\"\r\n }\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\",\r\n \"defaultValue\": \"True\",\r\n \"allowedValues\": [\r\n \"True\",\r\n \"False\"\r\n ],\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n }\r\n }\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Network/virtualNetworks\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"setByPolicy\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/metrics.enabled\",\r\n \"equals\": \"true\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"String\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\"\r\n },\r\n \"location\": {\r\n \"type\": \"String\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\"\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"String\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"String\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.Network/virtualNetworks/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2017-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"metrics\": [\r\n {\r\n \"category\": \"AllMetrics\",\r\n \"enabled\": \"[parameters('metricsEnabled')]\",\r\n \"retentionPolicy\": {\r\n \"enabled\": false,\r\n \"days\": 0\r\n }\r\n }\r\n ],\r\n \"logs\": [\r\n {\r\n \"category\": \"VMProtectionAlerts\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n },\r\n \"metricsEnabled\": {\r\n \"value\": \"[parameters('metricsEnabled')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }", - "$fxv#9": "{\r\n \"name\": \"policy-deploy-diagnostics-azure-files\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"All\",\r\n \"displayName\": \"Custom - Deploy Diagnostic Settings for Azure Files to Log Analytics Workspace\",\r\n \"description\": \"Custom - Deploys the diagnostic settings for File Services to stream resource logs to a Log Analytics workspace when any file Service which is missing this diagnostic settings is created or updated.\",\r\n \"metadata\": {\r\n \"version\": \"1.0.0\",\r\n \"category\": \"Monitoring\"\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Storage/storageAccounts/fileServices\"\r\n },\r\n \"then\": {\r\n \"effect\": \"[parameters('effect')]\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Insights/diagnosticSettings\",\r\n \"name\": \"[parameters('profileName')]\",\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/logs.enabled\",\r\n \"equals\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/metrics.enabled\",\r\n \"equals\": \"[parameters('metricsEnabled')]\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Insights/diagnosticSettings/workspaceId\",\r\n \"equals\": \"[parameters('logAnalytics')]\"\r\n }\r\n ]\r\n },\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa\",\r\n \"/providers/microsoft.authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293\"\r\n ],\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"resourceName\": {\r\n \"type\": \"string\"\r\n },\r\n \"location\": {\r\n \"type\": \"string\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"string\"\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"bool\"\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"bool\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"string\"\r\n }\r\n },\r\n \"variables\": {},\r\n \"resources\": [\r\n {\r\n \"type\": \"Microsoft.Storage/storageAccounts/fileServices/providers/diagnosticSettings\",\r\n \"apiVersion\": \"2021-05-01-preview\",\r\n \"name\": \"[concat(parameters('resourceName'), '/', 'Microsoft.Insights/', parameters('profileName'))]\",\r\n \"location\": \"[parameters('location')]\",\r\n \"dependsOn\": [],\r\n \"properties\": {\r\n \"workspaceId\": \"[parameters('logAnalytics')]\",\r\n \"metrics\": [\r\n {\r\n \"category\": \"Transaction\",\r\n \"enabled\": \"[parameters('metricsEnabled')]\"\r\n }\r\n ],\r\n \"logs\": [\r\n {\r\n \"category\": \"StorageRead\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"StorageWrite\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n },\r\n {\r\n \"category\": \"StorageDelete\",\r\n \"enabled\": \"[parameters('logsEnabled')]\"\r\n }\r\n ]\r\n }\r\n }\r\n ],\r\n \"outputs\": {}\r\n },\r\n \"parameters\": {\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n },\r\n \"resourceName\": {\r\n \"value\": \"[field('fullName')]\"\r\n },\r\n \"logAnalytics\": {\r\n \"value\": \"[parameters('logAnalytics')]\"\r\n },\r\n \"metricsEnabled\": {\r\n \"value\": \"[parameters('metricsEnabled')]\"\r\n },\r\n \"logsEnabled\": {\r\n \"value\": \"[parameters('logsEnabled')]\"\r\n },\r\n \"profileName\": {\r\n \"value\": \"[parameters('profileName')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n \"parameters\": {\r\n \"effect\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Effect\",\r\n \"description\": \"Enable or disable the execution of the policy\"\r\n },\r\n \"allowedValues\": [\r\n \"DeployIfNotExists\",\r\n \"AuditIfNotExists\",\r\n \"Disabled\"\r\n ],\r\n \"defaultValue\": \"DeployIfNotExists\"\r\n },\r\n \"profileName\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Profile name\",\r\n \"description\": \"The diagnostic settings profile name\"\r\n },\r\n \"defaultValue\": \"setbypolicy\"\r\n },\r\n \"logAnalytics\": {\r\n \"type\": \"String\",\r\n \"metadata\": {\r\n \"displayName\": \"Log Analytics workspace\",\r\n \"description\": \"Select Log Analytics workspace from dropdown list. If this workspace is outside of the scope of the assignment you must manually grant 'Log Analytics Contributor' permissions (or similar) to the policy assignment's principal ID.\",\r\n \"strongType\": \"omsWorkspace\",\r\n \"assignPermissions\": true\r\n }\r\n },\r\n \"metricsEnabled\": {\r\n \"type\": \"Boolean\",\r\n \"metadata\": {\r\n \"displayName\": \"Enable metrics\",\r\n \"description\": \"Whether to enable metrics stream to the Log Analytics workspace - True or False\"\r\n },\r\n \"allowedValues\": [\r\n true,\r\n false\r\n ],\r\n \"defaultValue\": true\r\n },\r\n \"logsEnabled\": {\r\n \"type\": \"Boolean\",\r\n \"metadata\": {\r\n \"displayName\": \"Enable logs\",\r\n \"description\": \"Whether to enable logs stream to the Log Analytics workspace - True or False\"\r\n },\r\n \"allowedValues\": [\r\n true,\r\n false\r\n ],\r\n \"defaultValue\": true\r\n }\r\n }\r\n }\r\n}", - "varComputeServObjRgs": [ - { - "rgName": "[parameters('computeObjectsRgName')]" - }, - { - "rgName": "[parameters('serviceObjectsRgName')]" - } - ], - "varNetworkObjRgs": "[if(not(empty(parameters('networkObjectsRgName'))), createArray(createObject('rgName', parameters('networkObjectsRgName'))), createArray())]", - "varStorageObjRgs": "[if(not(empty(parameters('storageObjectsRgName'))), createArray(createObject('rgName', parameters('storageObjectsRgName'))), createArray())]", - "varPolicyAssignmentRgs": "[union(variables('varComputeServObjRgs'), variables('varNetworkObjRgs'), variables('varStorageObjRgs'))]", - "varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters": "[variables('$fxv#0')]", - "varCustomPolicyDefinitions": [ - { - "deploymentName": "App-Group-Diag", - "libDefinition": "[json(variables('$fxv#1'))]" - }, - { - "deploymentName": "Host-Pool-Diag", - "libDefinition": "[json(variables('$fxv#2'))]" - }, - { - "deploymentName": "Scaling-Plan-Diag", - "libDefinition": "[json(variables('$fxv#3'))]" - }, - { - "deploymentName": "Workspace-Diag", - "libDefinition": "[json(variables('$fxv#4'))]" - }, - { - "deploymentName": "NSG-Diag", - "libDefinition": "[json(variables('$fxv#5'))]" - }, - { - "deploymentName": "NIC-Diag", - "libDefinition": "[json(variables('$fxv#6'))]" - }, - { - "deploymentName": "VM-Diag", - "libDefinition": "[json(variables('$fxv#7'))]" - }, - { - "deploymentName": "vNet-Diag", - "libDefinition": "[json(variables('$fxv#8'))]" - }, - { - "deploymentName": "Azure-Files-Diag", - "libDefinition": "[json(variables('$fxv#9'))]" - } - ], - "varCustomPolicySetDefinitions": { - "deploymentName": "policy-set-avd-diagnostics", - "libSetDefinition": "[json(variables('$fxv#10'))]", - "libSetChildDefinitions": [ - { - "definitionReferenceId": "AVDAppGroupDeployDiagnosticLogDeployLogAnalytics", - "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-avd-application-group', parameters('subscriptionId'))]", - "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').AVDAppGroupDeployDiagnosticLogDeployLogAnalytics.parameters]" - }, - { - "definitionReferenceId": "AVDHostPoolsDeployDiagnosticLogDeployLogAnalytics", - "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-avd-host-pool', parameters('subscriptionId'))]", - "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').AVDHostPoolsDeployDiagnosticLogDeployLogAnalytics.parameters]" - }, - { - "definitionReferenceId": "AVDScalingPlansDeployDiagnosticLogDeployLogAnalytics", - "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-avd-scaling-plan', parameters('subscriptionId'))]", - "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').AVDScalingPlansDeployDiagnosticLogDeployLogAnalytics.parameters]" - }, - { - "definitionReferenceId": "AVDWorkspaceDeployDiagnosticLogDeployLogAnalytics", - "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-avd-workspace', parameters('subscriptionId'))]", - "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').AVDWorkspaceDeployDiagnosticLogDeployLogAnalytics.parameters]" - }, - { - "definitionReferenceId": "NetworkSecurityGroupsDeployDiagnosticLogDeployLogAnalytics", - "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-network-security-group', parameters('subscriptionId'))]", - "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').NetworkSecurityGroupsDeployDiagnosticLogDeployLogAnalytics.parameters]" - }, - { - "definitionReferenceId": "NetworkNICDeployDiagnosticLogDeployLogAnalytics", - "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-nic', parameters('subscriptionId'))]", - "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').NetworkNICDeployDiagnosticLogDeployLogAnalytics.parameters]" - }, - { - "definitionReferenceId": "VirtualMachinesDeployDiagnosticLogDeployLogAnalytics", - "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-virtual-machine', parameters('subscriptionId'))]", - "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').VirtualMachinesDeployDiagnosticLogDeployLogAnalytics.parameters]" - }, - { - "definitionReferenceId": "VirtualNetworkDeployDiagnosticLogDeployLogAnalytics", - "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-virtual-network', parameters('subscriptionId'))]", - "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').VirtualNetworkDeployDiagnosticLogDeployLogAnalytics.parameters]" - }, - { - "definitionReferenceId": "AzureFilesDeployDiagnosticLogDeployLogAnalytics", - "definitionId": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policyDefinitions/policy-deploy-diagnostics-azure-files', parameters('subscriptionId'))]", - "definitionParameters": "[variables('varPolicySetDefinitionEsDeployDiagnosticsLoganalyticsParameters').AzureFilesDeployDiagnosticLogDeployLogAnalytics.parameters]" - } - ] - } - }, - "resources": [ - { - "copy": { - "name": "policyDefinitions", - "count": "[length(variables('varCustomPolicyDefinitions'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.name]" - }, - "displayName": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.displayName]" - }, - "metadata": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.metadata]" - }, - "mode": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.mode]" - }, - "parameters": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.parameters]" - }, - "policyRule": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.policyRule]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "15296566503434303805" - } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 64, - "metadata": { - "description": "Required. Specifies the name of the policy definition. Maximum length is 64 characters." - } - }, - "displayName": { - "type": "string", - "defaultValue": "", - "maxLength": 128, - "metadata": { - "description": "Optional. The display name of the policy definition. Maximum length is 128 characters." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The policy definition description." - } - }, - "mode": { - "type": "string", - "defaultValue": "All", - "allowedValues": [ - "All", - "Indexed", - "Microsoft.KeyVault.Data", - "Microsoft.ContainerService.Data", - "Microsoft.Kubernetes.Data", - "Microsoft.Network.Data" - ], - "metadata": { - "description": "Optional. The policy definition mode. Default is All, Some examples are All, Indexed, Microsoft.KeyVault.Data." - } - }, - "metadata": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The policy Definition metadata. Metadata is an open ended object and is typically a collection of key-value pairs." - } - }, - "parameters": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The policy definition parameters that can be used in policy definition references." - } - }, - "policyRule": { - "type": "object", - "metadata": { - "description": "Required. The Policy Rule details for the Policy Definition." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/policyDefinitions", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "properties": { - "policyType": "Custom", - "mode": "[parameters('mode')]", - "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", - "parameters": "[if(not(empty(parameters('parameters'))), parameters('parameters'), null())]", - "policyRule": "[parameters('policyRule')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "Policy Definition Name." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Policy Definition resource ID." - }, - "value": "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name'))]" - }, - "roleDefinitionIds": { - "type": "array", - "metadata": { - "description": "Policy Definition Role Definition IDs." - }, - "value": "[if(contains(reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then, 'details'), if(contains(reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then.details, 'roleDefinitionIds'), reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then.details.roleDefinitionIds, createArray()), createArray())]" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Policy-Set-Definition-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.name]" - }, - "description": { - "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.description]" - }, - "displayName": { - "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.displayName]" - }, - "metadata": { - "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.metadata]" - }, - "parameters": { - "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.parameters]" - }, - "policyDefinitions": { - "copy": [ - { - "name": "value", - "count": "[length(variables('varCustomPolicySetDefinitions').libSetChildDefinitions)]", - "input": "[createObject('policyDefinitionReferenceId', variables('varCustomPolicySetDefinitions').libSetChildDefinitions[copyIndex('value')].definitionReferenceId, 'policyDefinitionId', variables('varCustomPolicySetDefinitions').libSetChildDefinitions[copyIndex('value')].definitionId, 'parameters', variables('varCustomPolicySetDefinitions').libSetChildDefinitions[copyIndex('value')].definitionParameters)]" - } - ] - }, - "policyDefinitionGroups": { - "value": [] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "10756132163516015710" - } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 64, - "metadata": { - "description": "Required. Specifies the name of the policy Set Definition (Initiative). Maximum length is 64 characters for subscription scope." - } - }, - "displayName": { - "type": "string", - "defaultValue": "", - "maxLength": 128, - "metadata": { - "description": "Optional. The display name of the Set Definition (Initiative). Maximum length is 128 characters." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description name of the Set Definition (Initiative)." - } - }, - "metadata": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The Set Definition (Initiative) metadata. Metadata is an open ended object and is typically a collection of key-value pairs." - } - }, - "policyDefinitions": { - "type": "array", - "metadata": { - "description": "Required. The array of Policy definitions object to include for this policy set. Each object must include the Policy definition ID, and optionally other properties like parameters." - } - }, - "policyDefinitionGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The metadata describing groups of policy definition references within the Policy Set Definition (Initiative)." - } - }, - "parameters": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The Set Definition (Initiative) parameters that can be used in policy definition references." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/policySetDefinitions", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "properties": { - "policyType": "Custom", - "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", - "parameters": "[if(not(empty(parameters('parameters'))), parameters('parameters'), null())]", - "policyDefinitions": "[parameters('policyDefinitions')]", - "policyDefinitionGroups": "[if(not(empty(parameters('policyDefinitionGroups'))), parameters('policyDefinitionGroups'), createArray())]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "Policy Set Definition Name." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Policy Set Definition resource ID." - }, - "value": "[subscriptionResourceId('Microsoft.Authorization/policySetDefinitions', parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "policyDefinitions" - ] - }, - { - "copy": { - "name": "policySetAssignment", - "count": "[length(variables('varPolicyAssignmentRgs'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Policy-Set-Assignment-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', variables('varPolicyAssignmentRgs')[copyIndex()].rgName)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "name": { - "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.name]" - }, - "description": { - "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.description]" - }, - "displayName": { - "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.displayName]" - }, - "metadata": { - "value": "[variables('varCustomPolicySetDefinitions').libSetDefinition.properties.metadata]" - }, - "identity": { - "value": "SystemAssigned" - }, - "roleDefinitionIds": { - "value": [ - "/providers/Microsoft.Authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa", - "/providers/Microsoft.Authorization/roleDefinitions/92aaf0da-9dab-42b6-94a3-d43ce8d16293" - ] - }, - "parameters": { - "value": { - "logAnalytics": { - "value": "[parameters('alaWorkspaceId')]" - } - } - }, - "policyDefinitionId": { - "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/policySetDefinitions/policy-set-deploy-avd-diagnostics-to-log-analytics', parameters('subscriptionId'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "10386382608825992636" - }, - "name": "Policy Assignments (Resource Group scope)", - "description": "This module deploys a Policy Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 64, - "metadata": { - "description": "Required. Specifies the name of the policy assignment. Maximum length is 64 characters for resource group scope." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. This message will be part of response in case of policy violation." - } - }, - "displayName": { - "type": "string", - "defaultValue": "", - "maxLength": 128, - "metadata": { - "description": "Optional. The display name of the policy assignment. Maximum length is 128 characters." - } - }, - "policyDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. Specifies the ID of the policy definition or policy set definition being assigned." - } - }, - "parameters": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Parameters for the policy assignment if needed." - } - }, - "identity": { - "type": "string", - "defaultValue": "SystemAssigned", - "allowedValues": [ - "SystemAssigned", - "UserAssigned", - "None" - ], - "metadata": { - "description": "Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions." - } - }, - "userAssignedIdentityId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Resource ID for the user assigned identity to assign to the policy assignment." - } - }, - "roleDefinitionIds": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." - } - }, - "metadata": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs." - } - }, - "nonComplianceMessages": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The messages that describe why a resource is non-compliant with the policy." - } - }, - "enforcementMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "DoNotEnforce" - ], - "metadata": { - "description": "Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce." - } - }, - "notScopes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The policy excluded scopes." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "overrides": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition." - } - }, - "resourceSelectors": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. The Target Scope for the Policy. The name of the resource group for the policy assignment. If not provided, will use the current scope for deployment." - } - } - }, - "variables": { - "identityVar": "[if(equals(parameters('identity'), 'SystemAssigned'), createObject('type', parameters('identity')), if(equals(parameters('identity'), 'UserAssigned'), createObject('type', parameters('identity'), 'userAssignedIdentities', createObject(format('{0}', parameters('userAssignedIdentityId')), createObject())), null()))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2022-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "properties": { - "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", - "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "policyDefinitionId": "[parameters('policyDefinitionId')]", - "parameters": "[parameters('parameters')]", - "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), parameters('nonComplianceMessages'), createArray())]", - "enforcementMode": "[parameters('enforcementMode')]", - "notScopes": "[if(not(empty(parameters('notScopes'))), parameters('notScopes'), createArray())]", - "overrides": "[if(not(empty(parameters('overrides'))), parameters('overrides'), createArray())]", - "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), createArray())]" - }, - "identity": "[variables('identityVar')]" - }, - { - "copy": { - "name": "roleAssignment", - "count": "[length(parameters('roleDefinitionIds'))]" - }, - "condition": "[and(not(empty(parameters('roleDefinitionIds'))), equals(parameters('identity'), 'SystemAssigned'))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), parameters('roleDefinitionIds')[copyIndex()], parameters('location'), parameters('name'))]", - "properties": { - "roleDefinitionId": "[parameters('roleDefinitionIds')[copyIndex()]]", - "principalId": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]", - "principalType": "ServicePrincipal" - }, - "dependsOn": [ - "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" - ] - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "Policy Assignment Name." - }, - "value": "[parameters('name')]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Policy Assignment principal ID." - }, - "value": "[coalesce(tryGet(tryGet(reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full'), 'identity'), 'principalId'), '')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Policy Assignment resource ID." - }, - "value": "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the policy was assigned to." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId(format('{0}', parameters('subscriptionId')), 'Microsoft.Resources/deployments', format('Policy-Set-Definition-{0}', parameters('time')))]" - ] - }, - { - "copy": { - "name": "policySetRemediation", - "count": "[length(variables('varPolicyAssignmentRgs'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Remm-Diag-{0}-{1}', variables('varCustomPolicySetDefinitions').deploymentName, copyIndex())]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', variables('varPolicyAssignmentRgs')[copyIndex()].rgName)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}-{1}', variables('varCustomPolicySetDefinitions').deploymentName, copyIndex())]" - }, - "policyAssignmentId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', variables('varPolicyAssignmentRgs')[copyIndex()].rgName)), 'Microsoft.Resources/deployments', format('Policy-Set-Assignment-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "8141314117626850328" - }, - "name": "Policy Insights Remediations (Resource Group scope)", - "description": "This module deploys a Policy Insights Remediation on a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Specifies the name of the policy remediation." - } - }, - "failureThresholdPercentage": { - "type": "string", - "defaultValue": "1", - "metadata": { - "description": "Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail." - } - }, - "filtersLocations": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The filters that will be applied to determine which resources to remediate." - } - }, - "parallelDeployments": { - "type": "int", - "defaultValue": 10, - "minValue": 1, - "maxValue": 30, - "metadata": { - "description": "Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used." - } - }, - "resourceCount": { - "type": "int", - "defaultValue": 500, - "minValue": 1, - "maxValue": 50000, - "metadata": { - "description": "Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used." - } - }, - "resourceDiscoveryMode": { - "type": "string", - "defaultValue": "ExistingNonCompliant", - "allowedValues": [ - "ExistingNonCompliant", - "ReEvaluateCompliance" - ], - "metadata": { - "description": "Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified." - } - }, - "policyAssignmentId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the policy assignment that should be remediated." - } - }, - "policyDefinitionReferenceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location deployment metadata." - } - } - }, - "resources": [ - { - "type": "Microsoft.PolicyInsights/remediations", - "apiVersion": "2021-10-01", - "name": "[parameters('name')]", - "properties": { - "failureThreshold": { - "percentage": "[json(parameters('failureThresholdPercentage'))]" - }, - "filters": { - "locations": "[parameters('filtersLocations')]" - }, - "parallelDeployments": "[parameters('parallelDeployments')]", - "policyAssignmentId": "[parameters('policyAssignmentId')]", - "policyDefinitionReferenceId": "[parameters('policyDefinitionReferenceId')]", - "resourceCount": "[parameters('resourceCount')]", - "resourceDiscoveryMode": "[parameters('resourceDiscoveryMode')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the remediation." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the remediation." - }, - "value": "[resourceId('Microsoft.PolicyInsights/remediations', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed remediation." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[parameters('location')]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', variables('varPolicyAssignmentRgs')[copyIndex()].rgName)), 'Microsoft.Resources/deployments', format('Policy-Set-Assignment-{0}', parameters('time')))]" - ] - } - ] - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time')))]", - "[subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('Monitoing-RG-{0}', parameters('time')))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Mon-DCR-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('monitoringRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": "[if(parameters('deployAlaWorkspace'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time'))), '2022-09-01').outputs.location.value), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('varAlaWorkspaceIdSplitId')[2], variables('varAlaWorkspaceIdSplitId')[4]), 'Microsoft.OperationalInsights/workspaces', variables('varAlaWorkspaceIdSplitId')[8]), '2022-10-01', 'full').location))]", - "name": { - "value": "[parameters('dataCollectionRulesName')]" - }, - "alaWorkspaceId": "[if(parameters('deployAlaWorkspace'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', parameters('alaWorkspaceId')))]", - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13560993199783159016" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Data colleciton rule name." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy resources." - } - }, - "alaWorkspaceId": { - "type": "string", - "metadata": { - "description": "Exisintg Azure log analytics workspace." - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Tags to be applied to resources" - } - } - }, - "variables": { - "varAlaWorkspaceName": "[split(parameters('alaWorkspaceId'), '/')[8]]" - }, - "resources": [ - { - "type": "Microsoft.Insights/dataCollectionRules", - "apiVersion": "2022-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "kind": "Windows", - "identity": { - "type": "systemassigned" - }, - "properties": { - "dataFlows": [ - { - "streams": [ - "Microsoft-Perf", - "Microsoft-Event" - ], - "destinations": [ - "[variables('varAlaWorkspaceName')]" - ] - } - ], - "dataSources": { - "performanceCounters": [ - { - "streams": [ - "Microsoft-Perf" - ], - "samplingFrequencyInSeconds": 30, - "counterSpecifiers": [ - "\\LogicalDisk(C:)\\Avg. Disk Queue Length", - "\\LogicalDisk(C:)\\Current Disk Queue Length", - "\\Memory\\Available Mbytes", - "\\Memory\\Page Faults/sec", - "\\Memory\\Pages/sec", - "\\Memory\\% Committed Bytes In Use", - "\\PhysicalDisk(*)\\Avg. Disk Queue Length", - "\\PhysicalDisk(*)\\Avg. Disk sec/Read", - "\\PhysicalDisk(*)\\Avg. Disk sec/Transfer", - "\\PhysicalDisk(*)\\Avg. Disk sec/Write", - "\\Processor Information(_Total)\\% Processor Time", - "\\User Input Delay per Process(*)\\Max Input Delay", - "\\User Input Delay per Session(*)\\Max Input Delay", - "\\RemoteFX Network(*)\\Current TCP RTT", - "\\RemoteFX Network(*)\\Current UDP Bandwidth" - ], - "name": "perfCounterDataSource10" - }, - { - "streams": [ - "Microsoft-Perf" - ], - "samplingFrequencyInSeconds": 60, - "counterSpecifiers": [ - "\\LogicalDisk(C:)\\% Free Space", - "\\LogicalDisk(C:)\\Avg. Disk sec/Transfer", - "\\Terminal Services(*)\\Active Sessions", - "\\Terminal Services(*)\\Inactive Sessions", - "\\Terminal Services(*)\\Total Sessions" - ], - "name": "perfCounterDataSource30" - } - ], - "windowsEventLogs": [ - { - "streams": [ - "Microsoft-Event" - ], - "xPathQueries": [ - "Microsoft-Windows-TerminalServices-RemoteConnectionManager/Admin!*[System[(Level=2 or Level=3 or Level=4 or Level=0) ]]", - "Microsoft-Windows-TerminalServices-LocalSessionManager/Operational!*[System[(Level=2 or Level=3 or Level=4 or Level=0)]]", - "System!*", - "Microsoft-FSLogix-Apps/Operational!*[System[(Level=2 or Level=3 or Level=4 or Level=0)]]", - "Application!*[System[(Level=2 or Level=3)]]", - "Microsoft-FSLogix-Apps/Admin!*[System[(Level=2 or Level=3 or Level=4 or Level=0)]]" - ], - "name": "eventLogsDataSource" - } - ] - }, - "description": "AVD Insights settings", - "destinations": { - "logAnalytics": [ - { - "name": "[variables('varAlaWorkspaceName')]", - "workspaceResourceId": "[parameters('alaWorkspaceId')]" - } - ] - }, - "streamDeclarations": {} - } - } - ], - "outputs": { - "dataCollectionRulesId": { - "type": "string", - "value": "[resourceId('Microsoft.Insights/dataCollectionRules', parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time')))]", - "[subscriptionResourceId(parameters('subscriptionId'), 'Microsoft.Resources/deployments', format('Monitoing-RG-{0}', parameters('time')))]" - ] - } - ], - "outputs": { - "avdAlaWorkspaceResourceId": { - "type": "string", - "value": "[if(parameters('deployAlaWorkspace'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, parameters('alaWorkspaceId'))]" - }, - "avdAlaWorkspaceId": { - "type": "string", - "value": "[if(parameters('deployAlaWorkspace'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('LA-Workspace-{0}', parameters('time'))), '2022-09-01').outputs.logAnalyticsWorkspaceId.value, parameters('alaWorkspaceId'))]" - }, - "dataCollectionRuleId": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('monitoringRgName'))), 'Microsoft.Resources/deployments', format('Mon-DCR-{0}', parameters('time'))), '2022-09-01').outputs.dataCollectionRulesId.value]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Deploy-Network-RG-{0}', parameters('time')))]", - "baselineResourceGroups", - "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]" - ] - }, - { - "condition": "[or(or(or(or(parameters('createAvdVnet'), parameters('createPrivateDnsZones')), parameters('avdDeploySessionHosts')), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Networking-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "createVnet": { - "value": "[parameters('createAvdVnet')]" - }, - "deployAsg": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', true()), createObject('value', false()))]", - "existingAvdSubnetResourceId": { - "value": "[parameters('existingVnetAvdSubnetResourceId')]" - }, - "createPrivateDnsZones": "[if(or(parameters('deployPrivateEndpointKeyvaultStorage'), parameters('deployAvdPrivateLinkService')), createObject('value', parameters('createPrivateDnsZones')), createObject('value', false()))]", - "applicationSecurityGroupName": { - "value": "[variables('varApplicationSecurityGroupName')]" - }, - "computeObjectsRgName": { - "value": "[variables('varComputeObjectsRgName')]" - }, - "networkObjectsRgName": { - "value": "[variables('varNetworkObjectsRgName')]" - }, - "avdNetworksecurityGroupName": { - "value": "[variables('varAvdNetworksecurityGroupName')]" - }, - "anfNetworksecurityGroupName": { - "value": "[variables('varAnfNetworksecurityGroupName')]" - }, - "privateEndpointNetworksecurityGroupName": { - "value": "[variables('varPrivateEndpointNetworksecurityGroupName')]" - }, - "avdRouteTableName": { - "value": "[variables('varAvdRouteTableName')]" - }, - "privateEndpointRouteTableName": { - "value": "[variables('varPrivateEndpointRouteTableName')]" - }, - "vnetAddressPrefixes": { - "value": "[parameters('avdVnetworkAddressPrefixes')]" - }, - "vnetName": { - "value": "[variables('varVnetName')]" - }, - "vnetPeeringName": { - "value": "[variables('varVnetPeeringName')]" - }, - "remoteVnetPeeringName": { - "value": "[variables('varRemoteVnetPeeringName')]" - }, - "vnetAvdSubnetName": { - "value": "[variables('varVnetAvdSubnetName')]" - }, - "vnetPrivateEndpointSubnetName": { - "value": "[variables('varVnetPrivateEndpointSubnetName')]" - }, - "vnetAnfSubnetName": { - "value": "[variables('varVnetAnfSubnetName')]" - }, - "createVnetPeering": { - "value": "[variables('varCreateVnetPeering')]" - }, - "deployDDoSNetworkProtection": { - "value": "[parameters('deployDDoSNetworkProtection')]" - }, - "ddosProtectionPlanName": { - "value": "[variables('varDDosProtectionPlanName')]" - }, - "deployPrivateEndpointSubnet": "[if(or(parameters('deployPrivateEndpointKeyvaultStorage'), parameters('deployAvdPrivateLinkService')), createObject('value', true()), createObject('value', false()))]", - "deployAnfSubnet": "[if(equals(parameters('storageService'), 'ANF'), createObject('value', true()), createObject('value', false()))]", - "deployAvdPrivateLinkService": { - "value": "[parameters('deployAvdPrivateLinkService')]" - }, - "vNetworkGatewayOnHub": { - "value": "[parameters('vNetworkGatewayOnHub')]" - }, - "existingHubVnetResourceId": { - "value": "[parameters('existingHubVnetResourceId')]" - }, - "location": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostLocation')), createObject('value', parameters('avdManagementPlaneLocation')))]", - "vnetAvdSubnetAddressPrefix": { - "value": "[parameters('vNetworkAvdSubnetAddressPrefix')]" - }, - "vnetPrivateEndpointSubnetAddressPrefix": { - "value": "[parameters('vNetworkPrivateEndpointSubnetAddressPrefix')]" - }, - "vnetAnfSubnetAddressPrefix": { - "value": "[parameters('vNetworkAnfSubnetAddressPrefix')]" - }, - "workloadSubsId": { - "value": "[parameters('avdWorkloadSubsId')]" - }, - "dnsServers": { - "value": "[variables('varDnsServers')]" - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]", - "alaWorkspaceResourceId": "[if(parameters('avdDeployMonitoring'), if(parameters('deployAlaWorkspace'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.avdAlaWorkspaceResourceId.value), createObject('value', parameters('alaExistingWorkspaceResourceId'))), createObject('value', ''))]", - "customStaticRoutes": { - "value": "[parameters('customStaticRoutes')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "9241376745009248833" - }, - "name": "AVD LZA networking", - "description": "This module deploys vNet, NSG, ASG, UDR, private DNs zones", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "workloadSubsId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario" - } - }, - "createVnet": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Create new virtual network." - } - }, - "deployAsg": { - "type": "bool", - "metadata": { - "description": "Deploy application security group." - } - }, - "existingAvdSubnetResourceId": { - "type": "string", - "metadata": { - "description": "Existing virtual network subnet for AVD." - } - }, - "computeObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group Name for the AVD session hosts" - } - }, - "networkObjectsRgName": { - "type": "string", - "metadata": { - "description": "If new virtual network required for the AVD machines. Resource Group name for the virtual network." - } - }, - "vnetName": { - "type": "string", - "metadata": { - "description": "Name of the virtual network if required to be created." - } - }, - "avdNetworksecurityGroupName": { - "type": "string", - "metadata": { - "description": "AVD Network Security Group Name" - } - }, - "privateEndpointNetworksecurityGroupName": { - "type": "string", - "metadata": { - "description": "Private endpoint Network Security Group Name" - } - }, - "anfNetworksecurityGroupName": { - "type": "string", - "metadata": { - "description": "ANF Network Security Group Name" - } - }, - "applicationSecurityGroupName": { - "type": "string", - "metadata": { - "description": "Created if a new VNet for AVD is created. Application Security Group (ASG) for the session hosts." - } - }, - "avdRouteTableName": { - "type": "string", - "metadata": { - "description": "Created if the new VNet for AVD is created. Route Table name for AVD." - } - }, - "privateEndpointRouteTableName": { - "type": "string", - "metadata": { - "description": "Created if the new VNet for AVD is created. Route Table name for private endpoints." - } - }, - "vNetworkGatewayOnHub": { - "type": "bool", - "metadata": { - "description": "Does the hub contain a virtual network gateway." - } - }, - "existingHubVnetResourceId": { - "type": "string", - "metadata": { - "description": "Existing hub virtual network for peering." - } - }, - "vnetPeeringName": { - "type": "string", - "metadata": { - "description": "VNet peering name for AVD VNet to vHub." - } - }, - "remoteVnetPeeringName": { - "type": "string", - "metadata": { - "description": "Remote VNet peering name for AVD VNet to vHub." - } - }, - "createVnetPeering": { - "type": "bool", - "metadata": { - "description": "Create virtual network peering to hub." - } - }, - "ddosProtectionPlanName": { - "type": "string", - "metadata": { - "description": "DDoS Protection Plan name." - } - }, - "deployDDoSNetworkProtection": { - "type": "bool", - "metadata": { - "description": "Deploy DDoS Network Protection for virtual network." - } - }, - "deployPrivateEndpointSubnet": { - "type": "bool", - "metadata": { - "description": "Optional. AVD Accelerator will deploy with private endpoints by default." - } - }, - "deployAnfSubnet": { - "type": "bool", - "metadata": { - "description": "Deploy with ANf subnet." - } - }, - "deployAvdPrivateLinkService": { - "type": "bool", - "metadata": { - "description": "Optional. Deploys private endpoints for the AVD Private Link Service. (Default: false)" - } - }, - "vnetAddressPrefixes": { - "type": "string", - "metadata": { - "description": "AVD VNet address prefixes." - } - }, - "vnetAvdSubnetName": { - "type": "string", - "metadata": { - "description": "AVD subnet Name." - } - }, - "vnetPrivateEndpointSubnetName": { - "type": "string", - "metadata": { - "description": "Private endpoint subnet Name." - } - }, - "vnetAnfSubnetName": { - "type": "string", - "metadata": { - "description": "ANF subnet Name." - } - }, - "vnetAvdSubnetAddressPrefix": { - "type": "string", - "metadata": { - "description": "AVD VNet subnet address prefix." - } - }, - "vnetPrivateEndpointSubnetAddressPrefix": { - "type": "string", - "metadata": { - "description": "Private endpoint VNet subnet address prefix." - } - }, - "vnetAnfSubnetAddressPrefix": { - "type": "string", - "metadata": { - "description": "ANF VNet subnet address prefix." - } - }, - "dnsServers": { - "type": "array", - "metadata": { - "description": "custom DNS servers IPs" - } - }, - "createPrivateDnsZones": { - "type": "bool", - "metadata": { - "description": "Optional. Use Azure private DNS zones for private endpoints." - } - }, - "location": { - "type": "string", - "defaultValue": "[deployment().location]", - "metadata": { - "description": "Location where to deploy resources." - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "alaWorkspaceResourceId": { - "type": "string", - "metadata": { - "description": "Log analytics workspace for diagnostic logs." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment" - } - }, - "customStaticRoutes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Additional customer-provided static routes to be added to the route tables." - } - } - }, - "variables": { - "varAzureCloudName": "[environment().name]", - "varCreateAvdStaticRoute": true, - "varExistingAvdVnetSubId": "[if(not(parameters('createVnet')), split(parameters('existingAvdSubnetResourceId'), '/')[2], '')]", - "varExistingAvdVnetSubRgName": "[if(not(parameters('createVnet')), split(parameters('existingAvdSubnetResourceId'), '/')[4], '')]", - "varExistingAvdVnetName": "[if(not(parameters('createVnet')), split(parameters('existingAvdSubnetResourceId'), '/')[8], '')]", - "varExistingAvdVnetResourceId": "[if(not(parameters('createVnet')), format('/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/virtualNetworks/{2}', variables('varExistingAvdVnetSubId'), variables('varExistingAvdVnetSubRgName'), variables('varExistingAvdVnetName')), '')]", - "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]", - "varWindowsActivationKMSPrefixesNsg": "[if(equals(variables('varAzureCloudName'), 'AzureCloud'), createArray('20.118.99.224', '40.83.235.53', '23.102.135.246'), if(equals(variables('varAzureCloudName'), 'AzureUSGovernment'), createArray('23.97.0.13', '52.126.105.2'), if(equals(variables('varAzureCloudName'), 'AzureChinaCloud'), createArray('159.27.28.100', '163.228.64.161', '42.159.7.249'), createArray())))]", - "varDefaultStaticRoutes": "[if(equals(variables('varAzureCloudName'), 'AzureCloud'), createArray(createObject('name', 'AVDServiceTraffic', 'properties', createObject('addressPrefix', 'WindowsVirtualDesktop', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'AVDStunInfraTurnRelayTraffic', 'properties', createObject('addressPrefix', '20.202.0.0/16', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'AVDTurnRelayTraffic', 'properties', createObject('addressPrefix', '51.5.0.0/16', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS', 'properties', createObject('addressPrefix', '20.118.99.224/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS01', 'properties', createObject('addressPrefix', '40.83.235.53/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS02', 'properties', createObject('addressPrefix', '23.102.135.246/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet'))), if(equals(variables('varAzureCloudName'), 'AzureUSGovernment'), createArray(createObject('name', 'AVDServiceTraffic', 'properties', createObject('addressPrefix', 'WindowsVirtualDesktop', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'AVDStunTurnTraffic', 'properties', createObject('addressPrefix', '20.202.0.0/16', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS', 'properties', createObject('addressPrefix', '23.97.0.13/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS01', 'properties', createObject('addressPrefix', '52.126.105.2/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet'))), if(equals(variables('varAzureCloudName'), 'AzureChinaCloud'), createArray(createObject('name', 'AVDServiceTraffic', 'properties', createObject('addressPrefix', 'WindowsVirtualDesktop', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'AVDStunTurnTraffic', 'properties', createObject('addressPrefix', '20.202.0.0/16', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS', 'properties', createObject('addressPrefix', '159.27.28.100/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS01', 'properties', createObject('addressPrefix', '163.228.64.161/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet')), createObject('name', 'DirectRouteToKMS02', 'properties', createObject('addressPrefix', '42.159.7.249/32', 'hasBgpOverride', true(), 'nextHopType', 'Internet'))), createArray())))]", - "varStaticRoutes": "[union(variables('varDefaultStaticRoutes'), parameters('customStaticRoutes'))]", - "privateDnsZoneNames": { - "AutomationAgentService": "[format('privatelink.agentsvc.azure-automation.{0}', variables('privateDnsZoneSuffixes_AzureAutomation')[environment().name])]", - "Automation": "[format('privatelink.azure-automation.{0}', variables('privateDnsZoneSuffixes_AzureAutomation')[environment().name])]", - "AVDFeedConnections": "[format('privatelink.wvd.{0}', variables('privateDnsZoneSuffixes_AzureVirtualDesktop')[environment().name])]", - "AVDDiscovery": "[format('privatelink-global.wvd.{0}', variables('privateDnsZoneSuffixes_AzureVirtualDesktop')[environment().name])]", - "StorageFiles": "[format('privatelink.file.{0}', environment().suffixes.storage)]", - "StorageQueue": "[format('privatelink.queue.{0}', environment().suffixes.storage)]", - "StorageTable": "[format('privatelink.table.{0}', environment().suffixes.storage)]", - "StorageBlob": "[format('privatelink.blob.{0}', environment().suffixes.storage)]", - "KeyVault": "[replace(format('privatelink{0}', environment().suffixes.keyvaultDns), 'vault', 'vaultcore')]", - "Monitor": "[format('privatelink.monitor.{0}', variables('privateDnsZoneSuffixes_Monitor')[environment().name])]", - "MonitorODS": "[format('privatelink.ods.opinsights.{0}', variables('privateDnsZoneSuffixes_Monitor')[environment().name])]", - "MonitorOMS": "[format('privatelink.oms.opinsights.{0}', variables('privateDnsZoneSuffixes_Monitor')[environment().name])]" - }, - "privateDnsZoneSuffixes_AzureAutomation": { - "AzureCloud": "net", - "AzureUSGovernment": "us" - }, - "privateDnsZoneSuffixes_AzureVirtualDesktop": { - "AzureCloud": "microsoft.com", - "AzureUSGovernment": "azure.us" - }, - "privateDnsZoneSuffixes_Monitor": { - "AzureCloud": "azure.com", - "AzureUSGovernment": "azure.us" - } - }, - "resources": [ - { - "condition": "[parameters('createVnet')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('NSG-AVD-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('avdNetworksecurityGroupName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - }, - "securityRules": { - "value": [ - { - "name": "AVDServiceTraffic", - "properties": { - "priority": 100, - "access": "Allow", - "description": "Session host traffic to AVD control plane", - "destinationAddressPrefix": "WindowsVirtualDesktop", - "direction": "Outbound", - "sourcePortRange": "*", - "destinationPortRange": "443", - "protocol": "Tcp", - "sourceAddressPrefix": "VirtualNetwork" - } - }, - { - "name": "AzureCloud", - "properties": { - "priority": 110, - "access": "Allow", - "description": "Session host traffic to Azure cloud services", - "destinationAddressPrefix": "AzureCloud", - "direction": "Outbound", - "sourcePortRange": "*", - "destinationPortRange": "8443", - "protocol": "Tcp", - "sourceAddressPrefix": "VirtualNetwork" - } - }, - { - "name": "AzureMonitor", - "properties": { - "priority": 120, - "access": "Allow", - "description": "Session host traffic to Azure Monitor", - "destinationAddressPrefix": "AzureMonitor", - "direction": "Outbound", - "sourcePortRange": "*", - "destinationPortRange": "443", - "protocol": "Tcp", - "sourceAddressPrefix": "VirtualNetwork" - } - }, - { - "name": "AzureMarketPlace", - "properties": { - "priority": 130, - "access": "Allow", - "description": "Session host traffic to Azure Monitor", - "destinationAddressPrefix": "AzureFrontDoor.Frontend", - "direction": "Outbound", - "sourcePortRange": "*", - "destinationPortRange": "443", - "protocol": "Tcp", - "sourceAddressPrefix": "VirtualNetwork" - } - }, - { - "name": "WindowsActivationKMS", - "properties": { - "priority": 140, - "access": "Allow", - "description": "Session host traffic to Windows license activation services", - "destinationAddressPrefixes": "[variables('varWindowsActivationKMSPrefixesNsg')]", - "direction": "Outbound", - "sourcePortRange": "*", - "destinationPortRange": "1688", - "protocol": "Tcp", - "sourceAddressPrefix": "VirtualNetwork" - } - }, - { - "name": "AzureInstanceMetadata", - "properties": { - "priority": 150, - "access": "Allow", - "description": "Session host traffic to Azure instance metadata", - "destinationAddressPrefix": "169.254.169.254", - "direction": "Outbound", - "sourcePortRange": "*", - "destinationPortRange": "80", - "protocol": "Tcp", - "sourceAddressPrefix": "VirtualNetwork" - } - }, - { - "name": "RDPShortpath", - "properties": { - "priority": 150, - "access": "Allow", - "description": "Session host traffic to Azure instance metadata", - "destinationAddressPrefix": "VirtualNetwork", - "direction": "Inbound", - "sourcePortRange": "*", - "destinationPortRange": "3390", - "protocol": "Udp", - "sourceAddressPrefix": "VirtualNetwork" - } - }, - { - "name": "RDPShortpathTurnStun", - "properties": { - "priority": 160, - "access": "Allow", - "description": "Session host traffic to RDP shortpath STUN/TURN", - "destinationAddressPrefix": "20.202.0.0/16", - "direction": "Outbound", - "sourcePortRange": "*", - "destinationPortRange": "3478", - "protocol": "Udp", - "sourceAddressPrefix": "VirtualNetwork" - } - }, - { - "name": "RDPShortpathTurnRelay", - "properties": { - "priority": 170, - "access": "Allow", - "description": "Session host traffic to RDP shortpath STUN/TURN", - "destinationAddressPrefix": "51.5.0.0/16", - "direction": "Outbound", - "sourcePortRange": "*", - "destinationPortRange": "3478", - "protocol": "Udp", - "sourceAddressPrefix": "VirtualNetwork" - } - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "9898059387129093740" - }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG).", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Network Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "securityRules": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the NSG resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2023-11-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(parameters('securityRules'))]", - "input": { - "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", - "properties": { - "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", - "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", - "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", - "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", - "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" - } - } - } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_securityRules": { - "copy": { - "name": "networkSecurityGroup_securityRules", - "count": "[length(parameters('securityRules'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('securityRules')[copyIndex()].name]" - }, - "networkSecurityGroupName": { - "value": "[parameters('name')]" - }, - "protocol": { - "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" - }, - "access": { - "value": "[parameters('securityRules')[copyIndex()].properties.access]" - }, - "priority": { - "value": "[parameters('securityRules')[copyIndex()].properties.priority]" - }, - "direction": { - "value": "[parameters('securityRules')[copyIndex()].properties.direction]" - }, - "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "714966927696814087" - }, - "name": "Network Security Group (NSG) Security Rules", - "description": "This module deploys a Network Security Group (NSG) Security Rule.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the security rule." - } - }, - "networkSecurityGroupName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." - } - }, - "access": { - "type": "string", - "defaultValue": "Deny", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Optional. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "maxLength": 140, - "metadata": { - "description": "Optional. A description for this rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The application security group specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "destinationPortRanges": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "metadata": { - "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The CIDR or source IP ranges." - } - }, - "sourceApplicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The application security group specified as source." - } - }, - "sourcePortRange": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "sourcePortRanges": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The source port ranges." - } - } - }, - "resources": [ - { - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-11-01", - "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", - "properties": { - "access": "[parameters('access')]", - "description": "[parameters('description')]", - "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", - "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", - "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", - "destinationPortRange": "[parameters('destinationPortRange')]", - "destinationPortRanges": "[parameters('destinationPortRanges')]", - "direction": "[parameters('direction')]", - "priority": "[parameters('priority')]", - "protocol": "[parameters('protocol')]", - "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", - "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", - "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", - "sourcePortRange": "[parameters('sourcePortRange')]", - "sourcePortRanges": "[parameters('sourcePortRanges')]" - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the security rule was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the security rule." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the security rule." - }, - "value": "[parameters('name')]" - } - } - } - }, - "dependsOn": [ - "networkSecurityGroup" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the network security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the network security group." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the network security group." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('NSG-Private-Endpoint-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('privateEndpointNetworksecurityGroupName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - }, - "securityRules": { - "value": [] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "9898059387129093740" - }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG).", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Network Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "securityRules": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the NSG resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2023-11-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(parameters('securityRules'))]", - "input": { - "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", - "properties": { - "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", - "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", - "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", - "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", - "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" - } - } - } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_securityRules": { - "copy": { - "name": "networkSecurityGroup_securityRules", - "count": "[length(parameters('securityRules'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('securityRules')[copyIndex()].name]" - }, - "networkSecurityGroupName": { - "value": "[parameters('name')]" - }, - "protocol": { - "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" - }, - "access": { - "value": "[parameters('securityRules')[copyIndex()].properties.access]" - }, - "priority": { - "value": "[parameters('securityRules')[copyIndex()].properties.priority]" - }, - "direction": { - "value": "[parameters('securityRules')[copyIndex()].properties.direction]" - }, - "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "714966927696814087" - }, - "name": "Network Security Group (NSG) Security Rules", - "description": "This module deploys a Network Security Group (NSG) Security Rule.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the security rule." - } - }, - "networkSecurityGroupName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." - } - }, - "access": { - "type": "string", - "defaultValue": "Deny", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Optional. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "maxLength": 140, - "metadata": { - "description": "Optional. A description for this rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The application security group specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "destinationPortRanges": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "metadata": { - "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The CIDR or source IP ranges." - } - }, - "sourceApplicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The application security group specified as source." - } - }, - "sourcePortRange": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "sourcePortRanges": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The source port ranges." - } - } - }, - "resources": [ - { - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-11-01", - "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", - "properties": { - "access": "[parameters('access')]", - "description": "[parameters('description')]", - "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", - "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", - "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", - "destinationPortRange": "[parameters('destinationPortRange')]", - "destinationPortRanges": "[parameters('destinationPortRanges')]", - "direction": "[parameters('direction')]", - "priority": "[parameters('priority')]", - "protocol": "[parameters('protocol')]", - "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", - "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", - "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", - "sourcePortRange": "[parameters('sourcePortRange')]", - "sourcePortRanges": "[parameters('sourcePortRanges')]" - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the security rule was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the security rule." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the security rule." - }, - "value": "[parameters('name')]" - } - } - } - }, - "dependsOn": [ - "networkSecurityGroup" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the network security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the network security group." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the network security group." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[and(parameters('createVnet'), parameters('deployAnfSubnet'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('NSG-ANF-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('anfNetworksecurityGroupName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - }, - "securityRules": { - "value": [] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "9898059387129093740" - }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG).", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Network Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "securityRules": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the NSG resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2023-11-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(parameters('securityRules'))]", - "input": { - "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", - "properties": { - "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", - "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", - "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", - "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", - "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" - } - } - } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_securityRules": { - "copy": { - "name": "networkSecurityGroup_securityRules", - "count": "[length(parameters('securityRules'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('securityRules')[copyIndex()].name]" - }, - "networkSecurityGroupName": { - "value": "[parameters('name')]" - }, - "protocol": { - "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" - }, - "access": { - "value": "[parameters('securityRules')[copyIndex()].properties.access]" - }, - "priority": { - "value": "[parameters('securityRules')[copyIndex()].properties.priority]" - }, - "direction": { - "value": "[parameters('securityRules')[copyIndex()].properties.direction]" - }, - "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "714966927696814087" - }, - "name": "Network Security Group (NSG) Security Rules", - "description": "This module deploys a Network Security Group (NSG) Security Rule.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the security rule." - } - }, - "networkSecurityGroupName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." - } - }, - "access": { - "type": "string", - "defaultValue": "Deny", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Optional. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "maxLength": 140, - "metadata": { - "description": "Optional. A description for this rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The application security group specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "destinationPortRanges": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "metadata": { - "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The CIDR or source IP ranges." - } - }, - "sourceApplicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The application security group specified as source." - } - }, - "sourcePortRange": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "sourcePortRanges": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The source port ranges." - } - } - }, - "resources": [ - { - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-11-01", - "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", - "properties": { - "access": "[parameters('access')]", - "description": "[parameters('description')]", - "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", - "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", - "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", - "destinationPortRange": "[parameters('destinationPortRange')]", - "destinationPortRanges": "[parameters('destinationPortRanges')]", - "direction": "[parameters('direction')]", - "priority": "[parameters('priority')]", - "protocol": "[parameters('protocol')]", - "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", - "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", - "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", - "sourcePortRange": "[parameters('sourcePortRange')]", - "sourcePortRanges": "[parameters('sourcePortRanges')]" - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the security rule was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the security rule." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the security rule." - }, - "value": "[parameters('name')]" - } - } - } - }, - "dependsOn": [ - "networkSecurityGroup" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the network security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the network security group." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the network security group." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[parameters('deployAsg')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('ASG-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('applicationSecurityGroupName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "6399800135303615704" - }, - "name": "Application Security Groups (ASG)", - "description": "This module deploys an Application Security Group (ASG).", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Application Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-applicationsecuritygroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "applicationSecurityGroup": { - "type": "Microsoft.Network/applicationSecurityGroups", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": {} - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the application security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the application security group." - }, - "value": "[resourceId('Microsoft.Network/applicationSecurityGroups', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the application security group." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('applicationSecurityGroup', '2023-04-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[parameters('createVnet')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Route-Table-AVD-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('avdRouteTableName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "routes": "[if(variables('varCreateAvdStaticRoute'), createObject('value', variables('varStaticRoutes')), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "17894283484101609343" - }, - "name": "Route Tables", - "description": "This module deploys a User Defined Route Table (UDR).", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "routeType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the route." - } - }, - "properties": { - "type": "object", - "properties": { - "nextHopType": { - "type": "string", - "allowedValues": [ - "Internet", - "None", - "VirtualAppliance", - "VirtualNetworkGateway", - "VnetLocal" - ], - "metadata": { - "description": "Required. The type of Azure hop the packet should be sent to." - } - }, - "addressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination CIDR to which the route applies." - } - }, - "hasBgpOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." - } - }, - "nextHopIpAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." - } - } - }, - "metadata": { - "description": "Required. Properties of the route." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name given for the hub route table." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "routes": { - "$ref": "#/definitions/routeType", - "metadata": { - "description": "Optional. An array of routes to be established within the hub route table." - } - }, - "disableBgpRoutePropagation": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Switch to disable BGP route propagation." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "routeTable": { - "type": "Microsoft.Network/routeTables", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "routes": "[parameters('routes')]", - "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" - } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the route table was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the route table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the route table." - }, - "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('routeTable', '2023-04-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Route-Table-PE-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('privateEndpointRouteTableName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "routes": { - "value": [] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "17894283484101609343" - }, - "name": "Route Tables", - "description": "This module deploys a User Defined Route Table (UDR).", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "routeType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the route." - } - }, - "properties": { - "type": "object", - "properties": { - "nextHopType": { - "type": "string", - "allowedValues": [ - "Internet", - "None", - "VirtualAppliance", - "VirtualNetworkGateway", - "VnetLocal" - ], - "metadata": { - "description": "Required. The type of Azure hop the packet should be sent to." - } - }, - "addressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination CIDR to which the route applies." - } - }, - "hasBgpOverride": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." - } - }, - "nextHopIpAddress": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." - } - } - }, - "metadata": { - "description": "Required. Properties of the route." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name given for the hub route table." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "routes": { - "$ref": "#/definitions/routeType", - "metadata": { - "description": "Optional. An array of routes to be established within the hub route table." - } - }, - "disableBgpRoutePropagation": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Switch to disable BGP route propagation." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "routeTable": { - "type": "Microsoft.Network/routeTables", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "routes": "[parameters('routes')]", - "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" - } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the route table was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the route table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the route table." - }, - "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('routeTable', '2023-04-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[parameters('deployDDoSNetworkProtection')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('DDoS-Protection-Plan-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('ddosProtectionPlanName')]" - }, - "location": { - "value": "[parameters('location')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "6678083091788427255" - }, - "name": "DDoS Protection Plans", - "description": "This module deploys a DDoS Protection Plan.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "minLength": 1, - "metadata": { - "description": "Required. Name of the DDoS protection plan to assign the VNET to." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-ddosprotectionplan.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "ddosProtectionPlan": { - "type": "Microsoft.Network/ddosProtectionPlans", - "apiVersion": "2023-11-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": {} - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the DDOS protection plan was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the DDOS protection plan." - }, - "value": "[resourceId('Microsoft.Network/ddosProtectionPlans', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the DDOS protection plan." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('ddosProtectionPlan', '2023-11-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[parameters('createVnet')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('vNet-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('vnetName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "addressPrefixes": { - "value": "[array(parameters('vnetAddressPrefixes'))]" - }, - "dnsServers": { - "value": "[parameters('dnsServers')]" - }, - "peerings": "[if(parameters('createVnetPeering'), createObject('value', createArray(createObject('remoteVirtualNetworkId', parameters('existingHubVnetResourceId'), 'name', parameters('vnetPeeringName'), 'allowForwardedTraffic', true(), 'allowGatewayTransit', false(), 'allowVirtualNetworkAccess', true(), 'doNotVerifyRemoteGateways', true(), 'useRemoteGateways', if(parameters('vNetworkGatewayOnHub'), true(), false()), 'remotePeeringEnabled', true(), 'remotePeeringName', parameters('remoteVnetPeeringName'), 'remotePeeringAllowForwardedTraffic', true(), 'remotePeeringAllowGatewayTransit', if(parameters('vNetworkGatewayOnHub'), true(), false()), 'remotePeeringAllowVirtualNetworkAccess', true(), 'remotePeeringDoNotVerifyRemoteGateways', true(), 'remotePeeringUseRemoteGateways', false()))), createObject('value', createArray()))]", - "subnets": { - "value": "[union(if(parameters('deployPrivateEndpointSubnet'), createArray(createObject('name', parameters('vnetAvdSubnetName'), 'addressPrefix', parameters('vnetAvdSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''))), createArray(createObject('name', parameters('vnetAvdSubnetName'), 'addressPrefix', parameters('vnetAvdSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage', 'locations', createArray(format('{0}', parameters('location')))), createObject('service', 'Microsoft.KeyVault', 'locations', createArray(format('{0}', parameters('location')))))))), if(parameters('deployAnfSubnet'), createArray(createObject('name', parameters('vnetAnfSubnetName'), 'addressPrefix', parameters('vnetAnfSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(and(parameters('createVnet'), parameters('deployAnfSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-ANF-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'delegations', createArray(createObject('name', 'delegation', 'properties', createObject('serviceName', 'Microsoft.NetApp/volumes'))))), createArray()), if(parameters('deployPrivateEndpointSubnet'), createArray(createObject('name', parameters('vnetPrivateEndpointSubnetName'), 'addressPrefix', parameters('vnetPrivateEndpointSubnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-Private-Endpoint-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''), 'routeTableResourceId', if(and(parameters('createVnet'), parameters('deployPrivateEndpointSubnet')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-PE-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, ''))), createArray()))]" - }, - "ddosProtectionPlanResourceId": "[if(parameters('deployDDoSNetworkProtection'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('DDoS-Protection-Plan-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', ''))]", - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "18267772730058349233" - }, - "name": "Virtual Networks", - "description": "This module deploys a Virtual Network (vNet).", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Virtual Network (vNet)." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "addressPrefixes": { - "type": "array", - "metadata": { - "description": "Required. An Array of 1 or more IP Address Prefixes for the Virtual Network." - } - }, - "subnets": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. An Array of subnets to deploy to the Virtual Network." - } - }, - "dnsServers": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. DNS Servers associated to the Virtual Network." - } - }, - "ddosProtectionPlanResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." - } - }, - "peerings": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Virtual Network Peerings configurations." - } - }, - "vnetEncryption": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." - } - }, - "vnetEncryptionEnforcement": { - "type": "string", - "defaultValue": "AllowUnencrypted", - "allowedValues": [ - "AllowUnencrypted", - "DropUnencrypted" - ], - "metadata": { - "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." - } - }, - "flowTimeoutInMinutes": { - "type": "int", - "defaultValue": 0, - "maxValue": 30, - "metadata": { - "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "virtualNetwork": { - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "subnets", - "count": "[length(parameters('subnets'))]", - "input": { - "name": "[parameters('subnets')[copyIndex('subnets')].name]", - "properties": { - "addressPrefix": "[parameters('subnets')[copyIndex('subnets')].addressPrefix]", - "addressPrefixes": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'addressPrefixes'), parameters('subnets')[copyIndex('subnets')].addressPrefixes, createArray())]", - "applicationGatewayIPConfigurations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'applicationGatewayIPConfigurations'), parameters('subnets')[copyIndex('subnets')].applicationGatewayIPConfigurations, createArray())]", - "delegations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'delegations'), parameters('subnets')[copyIndex('subnets')].delegations, createArray())]", - "ipAllocations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'ipAllocations'), parameters('subnets')[copyIndex('subnets')].ipAllocations, createArray())]", - "natGateway": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'natGatewayResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].natGatewayResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].natGatewayResourceId), null())]", - "networkSecurityGroup": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'networkSecurityGroupResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].networkSecurityGroupResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].networkSecurityGroupResourceId), null())]", - "privateEndpointNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'privateEndpointNetworkPolicies'), parameters('subnets')[copyIndex('subnets')].privateEndpointNetworkPolicies, null())]", - "privateLinkServiceNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'privateLinkServiceNetworkPolicies'), parameters('subnets')[copyIndex('subnets')].privateLinkServiceNetworkPolicies, null())]", - "routeTable": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'routeTableResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].routeTableResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].routeTableResourceId), null())]", - "serviceEndpoints": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'serviceEndpoints'), parameters('subnets')[copyIndex('subnets')].serviceEndpoints, createArray())]", - "serviceEndpointPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'serviceEndpointPolicies'), parameters('subnets')[copyIndex('subnets')].serviceEndpointPolicies, createArray())]" - } - } - } - ], - "addressSpace": { - "addressPrefixes": "[parameters('addressPrefixes')]" - }, - "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", - "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", - "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", - "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", - "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]" - } - }, - "virtualNetwork_diagnosticSettings": { - "copy": { - "name": "virtualNetwork_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_subnets": { - "copy": { - "name": "virtualNetwork_subnets", - "count": "[length(parameters('subnets'))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-subnet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualNetworkName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[parameters('subnets')[copyIndex()].name]" - }, - "addressPrefix": { - "value": "[parameters('subnets')[copyIndex()].addressPrefix]" - }, - "addressPrefixes": "[if(contains(parameters('subnets')[copyIndex()], 'addressPrefixes'), createObject('value', parameters('subnets')[copyIndex()].addressPrefixes), createObject('value', createArray()))]", - "applicationGatewayIPConfigurations": "[if(contains(parameters('subnets')[copyIndex()], 'applicationGatewayIPConfigurations'), createObject('value', parameters('subnets')[copyIndex()].applicationGatewayIPConfigurations), createObject('value', createArray()))]", - "delegations": "[if(contains(parameters('subnets')[copyIndex()], 'delegations'), createObject('value', parameters('subnets')[copyIndex()].delegations), createObject('value', createArray()))]", - "ipAllocations": "[if(contains(parameters('subnets')[copyIndex()], 'ipAllocations'), createObject('value', parameters('subnets')[copyIndex()].ipAllocations), createObject('value', createArray()))]", - "natGatewayResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'natGatewayResourceId'), createObject('value', parameters('subnets')[copyIndex()].natGatewayResourceId), createObject('value', ''))]", - "networkSecurityGroupResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('subnets')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", - "privateEndpointNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'privateEndpointNetworkPolicies'), createObject('value', parameters('subnets')[copyIndex()].privateEndpointNetworkPolicies), createObject('value', ''))]", - "privateLinkServiceNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'privateLinkServiceNetworkPolicies'), createObject('value', parameters('subnets')[copyIndex()].privateLinkServiceNetworkPolicies), createObject('value', ''))]", - "roleAssignments": "[if(contains(parameters('subnets')[copyIndex()], 'roleAssignments'), createObject('value', parameters('subnets')[copyIndex()].roleAssignments), createObject('value', createArray()))]", - "routeTableResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'routeTableResourceId'), createObject('value', parameters('subnets')[copyIndex()].routeTableResourceId), createObject('value', ''))]", - "serviceEndpointPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'serviceEndpointPolicies'), createObject('value', parameters('subnets')[copyIndex()].serviceEndpointPolicies), createObject('value', createArray()))]", - "serviceEndpoints": "[if(contains(parameters('subnets')[copyIndex()], 'serviceEndpoints'), createObject('value', parameters('subnets')[copyIndex()].serviceEndpoints), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "16351454463417912386" - }, - "name": "Virtual Network Subnets", - "description": "This module deploys a Virtual Network Subnet.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Optional. The Name of the subnet resource." - } - }, - "virtualNetworkName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." - } - }, - "addressPrefix": { - "type": "string", - "metadata": { - "description": "Required. The address prefix for the subnet." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The resource ID of the network security group to assign to the subnet." - } - }, - "routeTableResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." - } - }, - "serviceEndpoints": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." - } - }, - "delegations": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The delegations to enable on the subnet." - } - }, - "natGatewayResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." - } - }, - "privateEndpointNetworkPolicies": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "Disabled", - "Enabled", - "" - ], - "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." - } - }, - "privateLinkServiceNetworkPolicies": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "Disabled", - "Enabled", - "" - ], - "metadata": { - "description": "Optional. enable or disable apply network policies on private link service in the subnet." - } - }, - "addressPrefixes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of address prefixes for the subnet." - } - }, - "applicationGatewayIPConfigurations": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." - } - }, - "ipAllocations": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of IpAllocation which reference this subnet." - } - }, - "serviceEndpointPolicies": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. An array of service endpoint policies." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - } - }, - "resources": { - "virtualNetwork": { - "existing": true, - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2023-04-01", - "name": "[parameters('virtualNetworkName')]" - }, - "subnet": { - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", - "properties": { - "addressPrefix": "[parameters('addressPrefix')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", - "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", - "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", - "serviceEndpoints": "[parameters('serviceEndpoints')]", - "delegations": "[parameters('delegations')]", - "privateEndpointNetworkPolicies": "[if(not(empty(parameters('privateEndpointNetworkPolicies'))), parameters('privateEndpointNetworkPolicies'), null())]", - "privateLinkServiceNetworkPolicies": "[if(not(empty(parameters('privateLinkServiceNetworkPolicies'))), parameters('privateLinkServiceNetworkPolicies'), null())]", - "addressPrefixes": "[parameters('addressPrefixes')]", - "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", - "ipAllocations": "[parameters('ipAllocations')]", - "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]" - } - }, - "subnet_roleAssignments": { - "copy": { - "name": "subnet_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/virtualNetworks/{0}/subnets/{1}', parameters('virtualNetworkName'), parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "subnet" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network peering was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network peering." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network peering." - }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" - }, - "subnetAddressPrefix": { - "type": "string", - "metadata": { - "description": "The address prefix for the subnet." - }, - "value": "[reference('subnet').addressPrefix]" - }, - "subnetAddressPrefixes": { - "type": "array", - "metadata": { - "description": "List of address prefixes for the subnet." - }, - "value": "[if(not(empty(parameters('addressPrefixes'))), reference('subnet').addressPrefixes, createArray())]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_peering_local": { - "copy": { - "name": "virtualNetwork_peering_local", - "count": "[length(parameters('peerings'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "localVnetName": { - "value": "[parameters('name')]" - }, - "remoteVirtualNetworkId": { - "value": "[parameters('peerings')[copyIndex()].remoteVirtualNetworkId]" - }, - "name": "[if(contains(parameters('peerings')[copyIndex()], 'name'), createObject('value', parameters('peerings')[copyIndex()].name), createObject('value', format('{0}-{1}', parameters('name'), last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')))))]", - "allowForwardedTraffic": "[if(contains(parameters('peerings')[copyIndex()], 'allowForwardedTraffic'), createObject('value', parameters('peerings')[copyIndex()].allowForwardedTraffic), createObject('value', true()))]", - "allowGatewayTransit": "[if(contains(parameters('peerings')[copyIndex()], 'allowGatewayTransit'), createObject('value', parameters('peerings')[copyIndex()].allowGatewayTransit), createObject('value', false()))]", - "allowVirtualNetworkAccess": "[if(contains(parameters('peerings')[copyIndex()], 'allowVirtualNetworkAccess'), createObject('value', parameters('peerings')[copyIndex()].allowVirtualNetworkAccess), createObject('value', true()))]", - "doNotVerifyRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'doNotVerifyRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].doNotVerifyRemoteGateways), createObject('value', true()))]", - "useRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'useRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].useRemoteGateways), createObject('value', false()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "15212353974601574751" - }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", - "metadata": { - "description": "Optional. The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName." - } - }, - "localVnetName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." - } - }, - "remoteVirtualNetworkId": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "allowGatewayTransit": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "allowVirtualNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." - } - }, - "useRemoteGateways": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - } - }, - "resources": [ - { - "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", - "properties": { - "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", - "allowGatewayTransit": "[parameters('allowGatewayTransit')]", - "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", - "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", - "useRemoteGateways": "[parameters('useRemoteGateways')]", - "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkId')]" - } - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network peering was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network peering." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network peering." - }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_peering_remote": { - "copy": { - "name": "virtualNetwork_peering_remote", - "count": "[length(parameters('peerings'))]" - }, - "condition": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringEnabled'), equals(parameters('peerings')[copyIndex()].remotePeeringEnabled, true()), false())]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[2]]", - "resourceGroup": "[split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "localVnetName": { - "value": "[last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/'))]" - }, - "remoteVirtualNetworkId": { - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" - }, - "name": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringName'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringName), createObject('value', format('{0}-{1}', last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')), parameters('name'))))]", - "allowForwardedTraffic": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowForwardedTraffic'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowForwardedTraffic), createObject('value', true()))]", - "allowGatewayTransit": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowGatewayTransit'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowGatewayTransit), createObject('value', false()))]", - "allowVirtualNetworkAccess": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowVirtualNetworkAccess), createObject('value', true()))]", - "doNotVerifyRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringDoNotVerifyRemoteGateways), createObject('value', true()))]", - "useRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringUseRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringUseRemoteGateways), createObject('value', false()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "15212353974601574751" - }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", - "metadata": { - "description": "Optional. The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName." - } - }, - "localVnetName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." - } - }, - "remoteVirtualNetworkId": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "allowGatewayTransit": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "allowVirtualNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." - } - }, - "useRemoteGateways": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - } - }, - "resources": [ - { - "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", - "properties": { - "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", - "allowGatewayTransit": "[parameters('allowGatewayTransit')]", - "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", - "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", - "useRemoteGateways": "[parameters('useRemoteGateways')]", - "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkId')]" - } - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network peering was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network peering." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network peering." - }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network." - }, - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network." - }, - "value": "[parameters('name')]" - }, - "subnetNames": { - "type": "array", - "metadata": { - "description": "The names of the deployed subnets." - }, - "copy": { - "count": "[length(parameters('subnets'))]", - "input": "[parameters('subnets')[copyIndex()].name]" - } - }, - "subnetResourceIds": { - "type": "array", - "metadata": { - "description": "The resource IDs of the deployed subnets." - }, - "copy": { - "count": "[length(parameters('subnets'))]", - "input": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('name'), parameters('subnets')[copyIndex()].name)]" - } - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('virtualNetwork', '2023-04-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('DDoS-Protection-Plan-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-ANF-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-AVD-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('NSG-Private-Endpoint-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-AVD-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Route-Table-PE-{0}', parameters('time')))]" - ] - }, - { - "condition": "[parameters('createPrivateDnsZones')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Private-DNS-Files-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('privateDnsZoneNames').StorageFiles]" - }, - "virtualNetworkLinks": "[if(parameters('createVnet'), createObject('value', createArray(createObject('virtualNetworkResourceId', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value))), createObject('value', createArray(createObject('virtualNetworkResourceId', variables('varExistingAvdVnetResourceId')))))]", - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "9826379828964980786" - }, - "name": "Private DNS Zones", - "description": "This module deploys a Private DNS zone.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Private DNS zone name." - } - }, - "virtualNetworkLinks": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2024-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "privateDnsZone_virtualNetworkLinks": { - "copy": { - "name": "privateDnsZone_virtualNetworkLinks", - "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-VirtualNetworkLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" - }, - "virtualNetworkResourceId": { - "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" - }, - "registrationEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4846633428140292997" - }, - "name": "Private DNS Zone Virtual Network Link", - "description": "This module deploys a Private DNS Zone Virtual Network Link.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The name of the virtual network link." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "registrationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Link to another virtual network resource ID." - } - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2024-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "virtualNetworkLink": { - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2024-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "registrationEnabled": "[parameters('registrationEnabled')]", - "virtualNetwork": { - "id": "[parameters('virtualNetworkResourceId')]" - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed virtual network link." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed virtual network link." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed virtual network link." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private DNS zone was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private DNS zone." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private DNS zone." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateDnsZone', '2024-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time')))]" - ] - }, - { - "condition": "[parameters('createPrivateDnsZones')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Private-DNS-Kv-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('privateDnsZoneNames').KeyVault]" - }, - "virtualNetworkLinks": "[if(parameters('createVnet'), createObject('value', createArray(createObject('virtualNetworkResourceId', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value))), createObject('value', createArray(createObject('virtualNetworkResourceId', variables('varExistingAvdVnetResourceId')))))]", - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "9826379828964980786" - }, - "name": "Private DNS Zones", - "description": "This module deploys a Private DNS zone.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Private DNS zone name." - } - }, - "virtualNetworkLinks": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2024-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "privateDnsZone_virtualNetworkLinks": { - "copy": { - "name": "privateDnsZone_virtualNetworkLinks", - "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-VirtualNetworkLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" - }, - "virtualNetworkResourceId": { - "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" - }, - "registrationEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4846633428140292997" - }, - "name": "Private DNS Zone Virtual Network Link", - "description": "This module deploys a Private DNS Zone Virtual Network Link.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The name of the virtual network link." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "registrationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Link to another virtual network resource ID." - } - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2024-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "virtualNetworkLink": { - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2024-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "registrationEnabled": "[parameters('registrationEnabled')]", - "virtualNetwork": { - "id": "[parameters('virtualNetworkResourceId')]" - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed virtual network link." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed virtual network link." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed virtual network link." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private DNS zone was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private DNS zone." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private DNS zone." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateDnsZone', '2024-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time')))]" - ] - }, - { - "condition": "[and(parameters('createPrivateDnsZones'), parameters('deployAvdPrivateLinkService'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Private-DNS-AVD-Connection-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('privateDnsZoneNames').AVDFeedConnections]" - }, - "virtualNetworkLinks": "[if(parameters('createVnet'), createObject('value', createArray(createObject('virtualNetworkResourceId', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value))), createObject('value', createArray(createObject('virtualNetworkResourceId', variables('varExistingAvdVnetResourceId')))))]", - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "9826379828964980786" - }, - "name": "Private DNS Zones", - "description": "This module deploys a Private DNS zone.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Private DNS zone name." - } - }, - "virtualNetworkLinks": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2024-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "privateDnsZone_virtualNetworkLinks": { - "copy": { - "name": "privateDnsZone_virtualNetworkLinks", - "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-VirtualNetworkLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" - }, - "virtualNetworkResourceId": { - "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" - }, - "registrationEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4846633428140292997" - }, - "name": "Private DNS Zone Virtual Network Link", - "description": "This module deploys a Private DNS Zone Virtual Network Link.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The name of the virtual network link." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "registrationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Link to another virtual network resource ID." - } - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2024-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "virtualNetworkLink": { - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2024-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "registrationEnabled": "[parameters('registrationEnabled')]", - "virtualNetwork": { - "id": "[parameters('virtualNetworkResourceId')]" - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed virtual network link." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed virtual network link." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed virtual network link." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private DNS zone was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private DNS zone." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private DNS zone." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateDnsZone', '2024-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time')))]" - ] - }, - { - "condition": "[and(parameters('createPrivateDnsZones'), parameters('deployAvdPrivateLinkService'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Private-DNS-AVD-Discovery-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('workloadSubsId'))]", - "resourceGroup": "[format('{0}', parameters('networkObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('privateDnsZoneNames').AVDDiscovery]" - }, - "virtualNetworkLinks": "[if(parameters('createVnet'), createObject('value', createArray(createObject('virtualNetworkResourceId', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value))), createObject('value', createArray(createObject('virtualNetworkResourceId', variables('varExistingAvdVnetResourceId')))))]", - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "9826379828964980786" - }, - "name": "Private DNS Zones", - "description": "This module deploys a Private DNS zone.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Private DNS zone name." - } - }, - "virtualNetworkLinks": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateDnsZone": { - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2024-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "privateDnsZone_virtualNetworkLinks": { - "copy": { - "name": "privateDnsZone_virtualNetworkLinks", - "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-VirtualNetworkLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" - }, - "virtualNetworkResourceId": { - "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" - }, - "registrationEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4846633428140292997" - }, - "name": "Private DNS Zone Virtual Network Link", - "description": "This module deploys a Private DNS Zone Virtual Network Link.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The name of the virtual network link." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "registrationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Link to another virtual network resource ID." - } - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2024-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "virtualNetworkLink": { - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2024-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "registrationEnabled": "[parameters('registrationEnabled')]", - "virtualNetwork": { - "id": "[parameters('virtualNetworkResourceId')]" - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed virtual network link." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed virtual network link." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed virtual network link." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private DNS zone was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private DNS zone." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private DNS zone." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateDnsZone', '2024-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time')))]" - ] - } - ], - "outputs": { - "applicationSecurityGroupResourceId": { - "type": "string", - "value": "[if(parameters('deployAsg'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('computeObjectsRgName'))), 'Microsoft.Resources/deployments', format('ASG-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" - }, - "virtualNetworkResourceId": { - "type": "string", - "value": "[if(parameters('createVnet'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('vNet-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" - }, - "azureFilesDnsZoneResourceId": { - "type": "string", - "value": "[if(parameters('createPrivateDnsZones'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Private-DNS-Files-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" - }, - "keyVaultDnsZoneResourceId": { - "type": "string", - "value": "[if(parameters('createPrivateDnsZones'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Private-DNS-Kv-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" - }, - "avdDnsConnectionZoneResourceId": { - "type": "string", - "value": "[if(and(parameters('createPrivateDnsZones'), parameters('deployAvdPrivateLinkService')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Private-DNS-AVD-Connection-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" - }, - "avdDnsDiscoveryZoneResourceId": { - "type": "string", - "value": "[if(and(parameters('createPrivateDnsZones'), parameters('deployAvdPrivateLinkService')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('workloadSubsId')), format('{0}', parameters('networkObjectsRgName'))), 'Microsoft.Resources/deployments', format('Private-DNS-AVD-Discovery-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Deploy-Network-RG-{0}', parameters('time')))]", - "baselineResourceGroups", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('AVD-MGMT-Plane-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "applicationGroupName": { - "value": "[variables('varApplicationGroupName')]" - }, - "applicationGroupFriendlyNameDesktop": { - "value": "[variables('varApplicationGroupFriendlyName')]" - }, - "workSpaceName": { - "value": "[variables('varWorkSpaceName')]" - }, - "mpImageSku": "[if(parameters('useSharedImage'), createObject('value', ''), createObject('value', parameters('mpImageSku')))]", - "keyVaultResourceId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" - }, - "workSpaceFriendlyName": { - "value": "[variables('varWorkSpaceFriendlyName')]" - }, - "computeTimeZone": { - "value": "[variables('varTimeZoneSessionHosts')]" - }, - "hostPoolName": { - "value": "[variables('varHostPoolName')]" - }, - "hostPoolFriendlyName": { - "value": "[variables('varHostFriendlyName')]" - }, - "hostPoolRdpProperties": { - "value": "[parameters('avdHostPoolRdpProperties')]" - }, - "hostPoolLoadBalancerType": { - "value": "[parameters('avdHostPoolLoadBalancerType')]" - }, - "hostPoolType": { - "value": "[parameters('avdHostPoolType')]" - }, - "preferredAppGroupType": "[if(equals(parameters('hostPoolPreferredAppGroupType'), 'RemoteApp'), createObject('value', 'RailApplications'), createObject('value', 'Desktop'))]", - "deployScalingPlan": "[if(not(empty(parameters('avdServicePrincipalObjectId'))), createObject('value', variables('varDeployScalingPlan')), createObject('value', false()))]", - "scalingPlanExclusionTag": { - "value": "[variables('varScalingPlanExclusionTag')]" - }, - "scalingPlanSchedules": "[if(equals(parameters('avdHostPoolType'), 'Pooled'), createObject('value', variables('varPooledScalingPlanSchedules')), createObject('value', variables('varPersonalScalingPlanSchedules')))]", - "scalingPlanName": { - "value": "[variables('varScalingPlanName')]" - }, - "hostPoolMaxSessions": { - "value": "[parameters('hostPoolMaxSessions')]" - }, - "personalAssignType": { - "value": "[parameters('avdPersonalAssignType')]" - }, - "managementPlaneLocation": { - "value": "[parameters('avdManagementPlaneLocation')]" - }, - "serviceObjectsRgName": { - "value": "[variables('varServiceObjectsRgName')]" - }, - "startVmOnConnect": { - "value": "[parameters('avdStartVmOnConnect')]" - }, - "subscriptionId": { - "value": "[parameters('avdWorkloadSubsId')]" - }, - "identityServiceProvider": { - "value": "[parameters('avdIdentityServiceProvider')]" - }, - "securityPrincipalId": { - "value": "[variables('varSecurityPrincipalId')]" - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]", - "alaWorkspaceResourceId": "[if(parameters('avdDeployMonitoring'), if(parameters('deployAlaWorkspace'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.avdAlaWorkspaceResourceId.value), createObject('value', parameters('alaExistingWorkspaceResourceId'))), createObject('value', ''))]", - "hostPoolAgentUpdateSchedule": { - "value": "[variables('varHostPoolAgentUpdateSchedule')]" - }, - "deployAvdPrivateLinkService": { - "value": "[parameters('deployAvdPrivateLinkService')]" - }, - "hostPoolPublicNetworkAccess": { - "value": "[parameters('hostPoolPublicNetworkAccess')]" - }, - "workspacePublicNetworkAccess": { - "value": "[parameters('workspacePublicNetworkAccess')]" - }, - "privateEndpointSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName'))), createObject('value', parameters('existingVnetPrivateEndpointSubnetResourceId')))]", - "avdVnetPrivateDnsZoneDiscoveryResourceId": "[if(parameters('deployAvdPrivateLinkService'), if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.avdDnsDiscoveryZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneDiscoveryResourceId'))), createObject('value', ''))]", - "avdVnetPrivateDnsZoneConnectionResourceId": "[if(parameters('deployAvdPrivateLinkService'), if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.avdDnsConnectionZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneConnectionResourceId'))), createObject('value', ''))]", - "privateEndpointConnectionName": { - "value": "[variables('varPrivateEndPointConnectionName')]" - }, - "privateEndpointDiscoveryName": { - "value": "[variables('varPrivateEndPointDiscoveryName')]" - }, - "privateEndpointWorkspaceName": { - "value": "[variables('varPrivateEndPointWorkspaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4866343470162672721" - }, - "name": "AVD LZA management plane", - "description": "This module deploys AVD workspace, host pool, application group scaling plan", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "managementPlaneLocation": { - "type": "string", - "metadata": { - "description": "Location where to deploy AVD management plane." - } - }, - "subscriptionId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "computeTimeZone": { - "type": "string", - "metadata": { - "description": "Virtual machine time zone." - } - }, - "identityServiceProvider": { - "type": "string", - "metadata": { - "description": "The service providing domain services for Azure Virtual Desktop." - } - }, - "securityPrincipalId": { - "type": "string", - "metadata": { - "description": "Identity ID to grant RBAC role to access AVD application group." - } - }, - "mpImageSku": { - "type": "string", - "metadata": { - "description": "Marketplace AVD OS image sku." - } - }, - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Resource ID of keyvault that will contain host pool registration token." - } - }, - "serviceObjectsRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for the service objects." - } - }, - "applicationGroupName": { - "type": "string", - "metadata": { - "description": "AVD Application group for the session hosts. Desktop type." - } - }, - "applicationGroupFriendlyNameDesktop": { - "type": "string", - "metadata": { - "description": "AVD Application group for the session hosts. Desktop type (friendly name)." - } - }, - "deployScalingPlan": { - "type": "bool", - "metadata": { - "description": "AVD deploy scaling plan." - } - }, - "hostPoolName": { - "type": "string", - "metadata": { - "description": "AVD Host Pool Name" - } - }, - "hostPoolFriendlyName": { - "type": "string", - "metadata": { - "description": "AVD Host Pool friendly Name" - } - }, - "scalingPlanName": { - "type": "string", - "metadata": { - "description": "AVD scaling plan name" - } - }, - "scalingPlanSchedules": { - "type": "array", - "metadata": { - "description": "AVD scaling plan schedules" - } - }, - "workSpaceName": { - "type": "string", - "metadata": { - "description": "AVD workspace name." - } - }, - "workSpaceFriendlyName": { - "type": "string", - "metadata": { - "description": "AVD workspace friendly name." - } - }, - "hostPoolRdpProperties": { - "type": "string", - "metadata": { - "description": "AVD host pool Custom RDP properties." - } - }, - "hostPoolType": { - "type": "string", - "allowedValues": [ - "Personal", - "Pooled" - ], - "metadata": { - "description": "Optional. AVD host pool type." - } - }, - "preferredAppGroupType": { - "type": "string", - "defaultValue": "Desktop", - "allowedValues": [ - "Desktop", - "None", - "RailApplications" - ], - "metadata": { - "description": "Optional. The type of preferred application group type, default to Desktop Application Group." - } - }, - "deployAvdPrivateLinkService": { - "type": "bool", - "metadata": { - "description": "Deploys the AVD Private Link Service." - } - }, - "privateEndpointConnectionName": { - "type": "string", - "metadata": { - "description": "Name of the Private Endpoint for the Connection" - } - }, - "privateEndpointDiscoveryName": { - "type": "string", - "metadata": { - "description": "Name of the Private Endpoint for the Discovery" - } - }, - "privateEndpointWorkspaceName": { - "type": "string", - "metadata": { - "description": "Name of the Private Endpoint for the Workspace" - } - }, - "privateEndpointSubnetResourceId": { - "type": "string", - "metadata": { - "description": "The subnet resource ID that the private endpoint should be deployed in." - } - }, - "avdVnetPrivateDnsZoneConnectionResourceId": { - "type": "string", - "metadata": { - "description": "The ResourceID of the AVD Private DNS Zone for Connection. (privatelink.wvd.azure.com)" - } - }, - "avdVnetPrivateDnsZoneDiscoveryResourceId": { - "type": "string", - "metadata": { - "description": "The ResourceID of the AVD Private DNS Zone for Discovery. (privatelink-global.wvd.azure.com)" - } - }, - "hostPoolPublicNetworkAccess": { - "type": "string", - "defaultValue": "EnabledForClientsOnly", - "allowedValues": [ - "Disabled", - "Enabled", - "EnabledForClientsOnly", - "EnabledForSessionHostsOnly" - ], - "metadata": { - "description": "Enables or Disables public network access on the host pool. (Default: EnabledForClientsOnly.)" - } - }, - "workspacePublicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Default to Enabled. Enables or Disables public network access on the workspace." - } - }, - "personalAssignType": { - "type": "string", - "allowedValues": [ - "Automatic", - "Direct" - ], - "metadata": { - "description": "Optional. AVD host pool type." - } - }, - "hostPoolLoadBalancerType": { - "type": "string", - "allowedValues": [ - "BreadthFirst", - "DepthFirst" - ], - "metadata": { - "description": "AVD host pool load balacing type." - } - }, - "hostPoolMaxSessions": { - "type": "int", - "metadata": { - "description": "Optional. AVD host pool maximum number of user sessions per session host." - } - }, - "startVmOnConnect": { - "type": "bool", - "metadata": { - "description": "Optional. AVD host pool start VM on Connect." - } - }, - "hostPoolAgentUpdateSchedule": { - "type": "array", - "metadata": { - "description": "Optional. AVD host pool start VM on Connect." - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "scalingPlanExclusionTag": { - "type": "string", - "metadata": { - "description": "Tag to exclude resources from scaling plan." - } - }, - "alaWorkspaceResourceId": { - "type": "string", - "metadata": { - "description": "Log analytics workspace for diagnostic logs." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - } - }, - "variables": { - "varApplicationGroups": [ - { - "name": "[parameters('applicationGroupName')]", - "friendlyName": "[parameters('applicationGroupFriendlyNameDesktop')]", - "location": "[parameters('managementPlaneLocation')]", - "applicationGroupType": "[if(equals(parameters('preferredAppGroupType'), 'Desktop'), 'Desktop', 'RemoteApp')]" - } - ], - "varHostPoolRdpPropertiesDomainServiceCheck": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), format('{0};targetisaadjoined:i:1;enablerdsaadauth:i:1', parameters('hostPoolRdpProperties')), parameters('hostPoolRdpProperties'))]", - "varRAppApplicationGroupsStandardApps": "[if(equals(parameters('preferredAppGroupType'), 'RailApplications'), createArray(createObject('name', 'Task Manager', 'description', 'Task Manager', 'friendlyName', 'Task Manager', 'showInPortal', true(), 'filePath', 'C:\\Windows\\system32\\taskmgr.exe'), createObject('name', 'WordPad', 'description', 'WordPad', 'friendlyName', 'WordPad', 'showInPortal', true(), 'filePath', 'C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe'), createObject('name', 'Microsoft Edge', 'description', 'Microsoft Edge', 'friendlyName', 'Edge', 'showInPortal', true(), 'filePath', 'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe'), createObject('name', 'Remote Desktop Connection', 'description', 'Remote Desktop Connection', 'friendlyName', 'Remote Desktop', 'showInPortal', true(), 'filePath', 'C:\\WINDOWS\\system32\\mtsc.exe')), createArray())]", - "varRAppApplicationGroupsOfficeApps": "[if(equals(parameters('preferredAppGroupType'), 'RailApplications'), createArray(createObject('name', 'Microsoft Excel', 'description', 'Microsoft Excel', 'friendlyName', 'Excel', 'showInPortal', true(), 'filePath', 'C:\\Program Files\\Microsoft Office\\root\\Office16\\EXCEL.EXE'), createObject('name', 'Microsoft PowerPoint', 'description', 'Microsoft PowerPoint', 'friendlyName', 'PowerPoint', 'showInPortal', true(), 'filePath', 'C:\\Program Files\\Microsoft Office\\root\\Office16\\POWERPNT.EXE'), createObject('name', 'Microsoft Word', 'description', 'Microsoft Word', 'friendlyName', 'Word', 'showInPortal', true(), 'filePath', 'C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE'), createObject('name', 'Microsoft Outlook', 'description', 'Microsoft Word', 'friendlyName', 'Outlook', 'showInPortal', true(), 'filePath', 'C:\\Program Files\\Microsoft Office\\root\\Office16\\OUTLOOK.EXE')), createArray())]", - "varRAppApplicationGroupsApps": "[if(equals(parameters('preferredAppGroupType'), 'RailApplications'), if(contains(parameters('mpImageSku'), 'office'), union(variables('varRAppApplicationGroupsStandardApps'), variables('varRAppApplicationGroupsOfficeApps')), variables('varRAppApplicationGroupsStandardApps')), createArray())]", - "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'))), createArray())]" - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('HostPool-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('hostPoolName')]" - }, - "friendlyName": { - "value": "[parameters('hostPoolFriendlyName')]" - }, - "location": { - "value": "[parameters('managementPlaneLocation')]" - }, - "hostPoolType": { - "value": "[parameters('hostPoolType')]" - }, - "startVMOnConnect": { - "value": "[parameters('startVmOnConnect')]" - }, - "customRdpProperty": { - "value": "[variables('varHostPoolRdpPropertiesDomainServiceCheck')]" - }, - "loadBalancerType": { - "value": "[parameters('hostPoolLoadBalancerType')]" - }, - "maxSessionLimit": { - "value": "[parameters('hostPoolMaxSessions')]" - }, - "preferredAppGroupType": { - "value": "[parameters('preferredAppGroupType')]" - }, - "personalDesktopAssignmentType": { - "value": "[parameters('personalAssignType')]" - }, - "keyVaultResourceId": { - "value": "[parameters('keyVaultResourceId')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "publicNetworkAccess": "[if(parameters('deployAvdPrivateLinkService'), createObject('value', parameters('hostPoolPublicNetworkAccess')), createObject('value', null()))]", - "privateEndpoints": "[if(parameters('deployAvdPrivateLinkService'), createObject('value', createArray(createObject('name', parameters('privateEndpointConnectionName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'privateDnsZoneResourceIds', createArray(parameters('avdVnetPrivateDnsZoneConnectionResourceId'))))), createObject('value', createArray()))]", - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - }, - "agentUpdate": "[if(not(empty(parameters('hostPoolAgentUpdateSchedule'))), createObject('value', createObject('maintenanceWindows', parameters('hostPoolAgentUpdateSchedule'), 'maintenanceWindowTimeZone', parameters('computeTimeZone'), 'type', 'Scheduled', 'useSessionHostLocalTime', true())), createObject('value', createObject()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "17896773356115754728" - }, - "name": "Azure Virtual Desktop Host Pool", - "description": "This module deploys an Azure Virtual Desktop Host Pool", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "privateEndpointType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "resourceGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the host pool." - } - }, - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the keyvault." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location of the scaling plan. Defaults to resource group location." - } - }, - "friendlyName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Friendly name of the scaling plan." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Description of the scaling plan." - } - }, - "hostPoolType": { - "type": "string", - "defaultValue": "Pooled", - "allowedValues": [ - "Personal", - "Pooled" - ], - "metadata": { - "description": "Optional. Set this parameter to Personal if you would like to enable Persistent Desktop experience. Defaults to Pooled." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Disabled", - "Enabled", - "EnabledForClientsOnly", - "EnabledForSessionHostsOnly" - ], - "metadata": { - "description": "Optional. Set public network access." - } - }, - "privateEndpoints": { - "$ref": "#/definitions/privateEndpointType", - "metadata": { - "description": "Optional. Configuration details for private endpoints." - } - }, - "personalDesktopAssignmentType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "Automatic", - "Direct", - "" - ], - "metadata": { - "description": "Optional. Set the type of assignment for a Personal Host Pool type." - } - }, - "loadBalancerType": { - "type": "string", - "defaultValue": "BreadthFirst", - "allowedValues": [ - "BreadthFirst", - "DepthFirst", - "Persistent" - ], - "metadata": { - "description": "Optional. Type of load balancer algorithm." - } - }, - "maxSessionLimit": { - "type": "int", - "defaultValue": 99999, - "metadata": { - "description": "Optional. Maximum number of sessions." - } - }, - "customRdpProperty": { - "type": "string", - "defaultValue": "audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2;", - "metadata": { - "description": "Optional. Host Pool RDP properties." - } - }, - "validationEnvironment": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Validation host pools allows you to test service changes before they are deployed to production. When set to true, the Host Pool will be deployed in a validation 'ring' (environment) that receives all the new features (might be less stable). Defaults to false that stands for the stable, production-ready environment." - } - }, - "vmTemplate": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The necessary information for adding more VMs to this Host Pool." - } - }, - "tokenValidityLength": { - "type": "string", - "defaultValue": "PT8H", - "metadata": { - "description": "Optional. Host Pool token validity length. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the token will be valid for 8 hours." - } - }, - "baseTime": { - "type": "string", - "defaultValue": "[utcNow('u')]", - "metadata": { - "description": "Generated. Do not provide a value! This date value is used to generate a registration token." - } - }, - "preferredAppGroupType": { - "type": "string", - "defaultValue": "Desktop", - "allowedValues": [ - "Desktop", - "None", - "RailApplications" - ], - "metadata": { - "description": "Optional. The type of preferred application group type, default to Desktop Application Group." - } - }, - "startVMOnConnect": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable Start VM on connect to allow users to start the virtual machine from a deallocated state. Important: Custom RBAC role required to power manage VMs." - } - }, - "agentUpdate": { - "type": "object", - "defaultValue": { - "useSessionHostLocalTime": true - }, - "metadata": { - "description": "Optional. The session host configuration for updating agent, monitoring agent, and stack component." - } - }, - "ring": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. The ring number of HostPool." - } - }, - "ssoadfsAuthority": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. URL to customer ADFS server for signing WVD SSO certificates." - } - }, - "ssoClientId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. ClientId for the registered Relying Party used to issue WVD SSO certificates." - } - }, - "ssoClientSecretKeyVaultPath": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Path to Azure KeyVault storing the secret used for communication to ADFS." - } - }, - "ssoSecretType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "Certificate", - "CertificateInKeyVault", - "SharedKey", - "SharedKeyInKeyVault" - ], - "metadata": { - "description": "Optional. The type of single sign on Secret Type." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", - "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", - "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[take(format('46d3xbcp.res.desktopvirtualization-hostpool.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "hostPool": { - "type": "Microsoft.DesktopVirtualization/hostPools", - "apiVersion": "2023-09-05", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "friendlyName": "[parameters('friendlyName')]", - "description": "[parameters('description')]", - "hostPoolType": "[parameters('hostPoolType')]", - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "customRdpProperty": "[parameters('customRdpProperty')]", - "personalDesktopAssignmentType": "[parameters('personalDesktopAssignmentType')]", - "preferredAppGroupType": "[parameters('preferredAppGroupType')]", - "maxSessionLimit": "[parameters('maxSessionLimit')]", - "loadBalancerType": "[parameters('loadBalancerType')]", - "startVMOnConnect": "[parameters('startVMOnConnect')]", - "validationEnvironment": "[parameters('validationEnvironment')]", - "registrationInfo": { - "expirationTime": "[dateTimeAdd(parameters('baseTime'), parameters('tokenValidityLength'))]", - "token": null, - "registrationTokenOperation": "Update" - }, - "vmTemplate": "[if(not(empty(parameters('vmTemplate'))), null(), string(parameters('vmTemplate')))]", - "agentUpdate": "[parameters('agentUpdate')]", - "ring": "[if(not(equals(parameters('ring'), -1)), parameters('ring'), null())]", - "ssoadfsAuthority": "[parameters('ssoadfsAuthority')]", - "ssoClientId": "[parameters('ssoClientId')]", - "ssoClientSecretKeyVaultPath": "[parameters('ssoClientSecretKeyVaultPath')]", - "ssoSecretType": "[parameters('ssoSecretType')]" - } - }, - "hostPool_diagnosticSettings": { - "copy": { - "name": "hostPool_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.DesktopVirtualization/hostPools/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "hostPool" - ] - }, - "keyVaultHostPoolSecret": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-HP-Token-Secret', uniqueString(deployment().name, parameters('location')))]", - "subscriptionId": "[format('{0}', variables('varKeyVaultSubId'))]", - "resourceGroup": "[format('{0}', variables('varKeyVaultRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[variables('varKeyVaultName')]" - }, - "name": { - "value": "hostPoolRegistrationToken" - }, - "value": { - "value": "[reference('hostPool').registrationInfo.token]" - }, - "contentType": { - "value": "Host pool registration token for session hosts" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12190317675030946449" - }, - "name": "Key Vault Secrets", - "description": "This module deploys a Key Vault Secret.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "attributesEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Determines whether the object is enabled." - } - }, - "attributesExp": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." - } - }, - "attributesNbf": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." - } - }, - "contentType": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. The content type of the secret." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", - "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", - "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", - "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", - "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-07-01", - "name": "[parameters('keyVaultName')]" - }, - "secret": { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2023-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "contentType": "[parameters('contentType')]", - "attributes": { - "enabled": "[parameters('attributesEnabled')]", - "exp": "[parameters('attributesExp')]", - "nbf": "[parameters('attributesNbf')]" - }, - "value": "[parameters('value')]" - } - }, - "secret_roleAssignments": { - "copy": { - "name": "secret_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "secret" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the secret." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the secret." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the secret was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "hostPool" - ] - }, - "hostPool_privateEndpoints": { - "copy": { - "name": "hostPool_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-hostPool-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" - }, - "privateDnsZoneGroupName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" - }, - "privateDnsZoneResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "4120048060064073955" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "ipConfigurationsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true - }, - "manualPrivateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "privateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "customDnsConfigType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "$ref": "#/definitions/ipConfigurationsType", - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "$ref": "#/definitions/customDnsConfigType", - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", - "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." - } - }, - "privateLinkServiceConnections": { - "$ref": "#/definitions/privateLinkServiceConnectionsType", - "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" - }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "11244630631275470040" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDNSResourceIds": { - "type": "array", - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", - "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" - } - } - } - ] - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" - }, - "groupId": { - "type": "string", - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" - } - } - } - }, - "dependsOn": [ - "hostPool" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the host pool." - }, - "value": "[resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the host pool was created in." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the host pool." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location of the host pool." - }, - "value": "[reference('hostPool', '2023-09-05', 'full').location]" - }, - "keyVaultTokenSecretResourceId": { - "type": "string", - "metadata": { - "description": "Host pool registration token secret resource ID." - }, - "value": "[reference('keyVaultHostPoolSecret').outputs.resourceId.value]" - } - } - } - } - }, - { - "copy": { - "name": "applicationGroups", - "count": "[length(variables('varApplicationGroups'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}', variables('varApplicationGroups')[copyIndex()].name, parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('varApplicationGroups')[copyIndex()].name]" - }, - "friendlyName": { - "value": "[variables('varApplicationGroups')[copyIndex()].friendlyName]" - }, - "location": { - "value": "[variables('varApplicationGroups')[copyIndex()].location]" - }, - "applicationGroupType": { - "value": "[variables('varApplicationGroups')[copyIndex()].applicationGroupType]" - }, - "hostpoolName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('HostPool-{0}', parameters('time'))), '2022-09-01').outputs.name.value]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "applications": "[if(equals(variables('varApplicationGroups')[copyIndex()].applicationGroupType, 'RemoteApp'), createObject('value', variables('varRAppApplicationGroupsApps')), createObject('value', createArray()))]", - "roleAssignments": "[if(not(empty(parameters('securityPrincipalId'))), createObject('value', createArray(createObject('roleDefinitionIdOrName', 'Desktop Virtualization User', 'principalId', parameters('securityPrincipalId')))), createObject('value', createArray()))]", - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4794696781017607017" - }, - "name": "Azure Virtual Desktop Application Group", - "description": "This module deploys an Azure Virtual Desktop Application Group.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "minLength": 3, - "metadata": { - "description": "Required. Name of the Application Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "applicationGroupType": { - "type": "string", - "allowedValues": [ - "RemoteApp", - "Desktop" - ], - "metadata": { - "description": "Required. The type of the Application Group to be created. Allowed values: RemoteApp or Desktop." - } - }, - "hostpoolName": { - "type": "string", - "metadata": { - "description": "Required. Name of the Host Pool to be linked to this Application Group." - } - }, - "friendlyName": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. The friendly name of the Application Group to be created." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Description of the application group." - } - }, - "applications": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of applications to be created in the Application Group." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "builtInRoleNames": { - "Owner": "/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635", - "Contributor": "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c", - "Reader": "/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7", - "Role Based Access Control Administrator (Preview)": "/providers/Microsoft.Authorization/roleDefinitions/f58310d9-a9f6-439a-9e8d-f62e7b41a168", - "User Access Administrator": "/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9", - "Application Group Contributor": "/providers/Microsoft.Authorization/roleDefinitions/ca6382a4-1721-4bcf-a114-ff0c70227b6b", - "Desktop Virtualization Application Group Contributor": "/providers/Microsoft.Authorization/roleDefinitions/86240b0e-9422-4c43-887b-b61143f32ba8", - "Desktop Virtualization Application Group Reader": "/providers/Microsoft.Authorization/roleDefinitions/aebf23d0-b568-4e86-b8f9-fe83a2c6ab55", - "Desktop Virtualization Contributor": "/providers/Microsoft.Authorization/roleDefinitions/082f0a83-3be5-4ba1-904c-961cca79b387", - "Desktop Virtualization Host Pool Contributor": "/providers/Microsoft.Authorization/roleDefinitions/e307426c-f9b6-4e81-87de-d99efb3c32bc", - "Desktop Virtualization Host Pool Reader": "/providers/Microsoft.Authorization/roleDefinitions/ceadfde2-b300-400a-ab7b-6143895aa822", - "Desktop Virtualization Power On Off Contributor": "/providers/Microsoft.Authorization/roleDefinitions/40c5ff49-9181-41f8-ae61-143b0e78555e", - "Desktop Virtualization Reader": "/providers/Microsoft.Authorization/roleDefinitions/49a72310-ab8d-41df-bbb0-79b649203868", - "Desktop Virtualization Session Host Operator": "/providers/Microsoft.Authorization/roleDefinitions/2ad6aaab-ead9-4eaa-8ac5-da422f562408", - "Desktop Virtualization User": "/providers/Microsoft.Authorization/roleDefinitions/1d18fff3-a72a-46b5-b4a9-0b38a3cd7e63", - "Desktop Virtualization User Session Operator": "/providers/Microsoft.Authorization/roleDefinitions/ea4bfff8-7fb4-485a-aadd-d4129a0ffaa6", - "Desktop Virtualization Virtual Machine Contributor": "/providers/Microsoft.Authorization/roleDefinitions/a959dbd1-f747-45e3-8ba6-dd80f235f97c", - "Desktop Virtualization Workspace Contributor": "/providers/Microsoft.Authorization/roleDefinitions/21efdde3-836f-432b-bf3d-3e8e734d4b2b", - "Desktop Virtualization Workspace Reader": "/providers/Microsoft.Authorization/roleDefinitions/0fa44ee9-7a7d-466b-9bb2-2bf446b1204d", - "Managed Application Contributor Role": "/providers/Microsoft.Authorization/roleDefinitions/641177b8-a67a-45b9-a033-47bc880bb21e", - "Managed Application Operator Role": "/providers/Microsoft.Authorization/roleDefinitions/c7393b34-138c-406f-901b-d8cf2b17e6ae", - "Managed Applications Reader": "/providers/Microsoft.Authorization/roleDefinitions/b9331d33-8a36-4f8c-b097-4f54124fdb44" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.desktopvirtualization-appgroup.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "appGroup_hostpool": { - "existing": true, - "type": "Microsoft.DesktopVirtualization/hostPools", - "apiVersion": "2023-09-05", - "name": "[parameters('hostpoolName')]" - }, - "appGroup": { - "type": "Microsoft.DesktopVirtualization/applicationGroups", - "apiVersion": "2023-09-05", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "hostPoolArmPath": "[resourceId('Microsoft.DesktopVirtualization/hostPools', parameters('hostpoolName'))]", - "friendlyName": "[parameters('friendlyName')]", - "description": "[parameters('description')]", - "applicationGroupType": "[parameters('applicationGroupType')]" - } - }, - "appGroup_roleAssignments": { - "copy": { - "name": "appGroup_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.DesktopVirtualization/applicationGroups/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.DesktopVirtualization/applicationGroups', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "appGroup" - ] - }, - "appGroup_diagnosticSettings": { - "copy": { - "name": "appGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.DesktopVirtualization/applicationGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "appGroup" - ] - }, - "appGroup_applications": { - "copy": { - "name": "appGroup_applications", - "count": "[length(parameters('applications'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-AppGroup-App-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('applications')[copyIndex()].name]" - }, - "applicationGroupName": { - "value": "[parameters('name')]" - }, - "description": { - "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'description'), '')]" - }, - "friendlyName": { - "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'friendlyName'), parameters('name'))]" - }, - "filePath": { - "value": "[parameters('applications')[copyIndex()].filePath]" - }, - "commandLineSetting": { - "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'commandLineSetting'), 'DoNotAllow')]" - }, - "commandLineArguments": { - "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'commandLineArguments'), '')]" - }, - "showInPortal": { - "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'showInPortal'), false())]" - }, - "iconPath": { - "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'iconPath'), parameters('applications')[copyIndex()].filePath)]" - }, - "iconIndex": { - "value": "[coalesce(tryGet(parameters('applications')[copyIndex()], 'iconIndex'), 0)]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "11724144502531514491" - }, - "name": "Azure Virtual Desktop Application Group Application", - "description": "This module deploys an Azure Virtual Desktop Application Group Application.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "applicationGroupName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Application Group to create the application(s) in. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Application to be created in the Application Group." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Description of the Application." - } - }, - "friendlyName": { - "type": "string", - "metadata": { - "description": "Required. Friendly name of the Application." - } - }, - "filePath": { - "type": "string", - "metadata": { - "description": "Required. Specifies a path for the executable file for the Application." - } - }, - "commandLineSetting": { - "type": "string", - "defaultValue": "DoNotAllow", - "allowedValues": [ - "Allow", - "DoNotAllow", - "Require" - ], - "metadata": { - "description": "Optional. Specifies whether this published Application can be launched with command-line arguments provided by the client, command-line arguments specified at publish time, or no command-line arguments at all." - } - }, - "commandLineArguments": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Command-Line Arguments for the Application." - } - }, - "showInPortal": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether to show the RemoteApp program in the RD Web Access server." - } - }, - "iconPath": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Path to icon." - } - }, - "iconIndex": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Index of the icon." - } - } - }, - "resources": [ - { - "type": "Microsoft.DesktopVirtualization/applicationGroups/applications", - "apiVersion": "2023-09-05", - "name": "[format('{0}/{1}', parameters('applicationGroupName'), parameters('name'))]", - "properties": { - "description": "[parameters('description')]", - "friendlyName": "[parameters('friendlyName')]", - "filePath": "[parameters('filePath')]", - "commandLineSetting": "[parameters('commandLineSetting')]", - "commandLineArguments": "[parameters('commandLineArguments')]", - "showInPortal": "[parameters('showInPortal')]", - "iconPath": "[parameters('iconPath')]", - "iconIndex": "[parameters('iconIndex')]" - } - } - ], - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Application." - }, - "value": "[resourceId('Microsoft.DesktopVirtualization/applicationGroups/applications', parameters('applicationGroupName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Application was created in." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Application." - }, - "value": "[parameters('name')]" - } - } - } - }, - "dependsOn": [ - "appGroup" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the scaling plan." - }, - "value": "[resourceId('Microsoft.DesktopVirtualization/applicationGroups', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the scaling plan was created in." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the scaling plan." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location of the scaling plan." - }, - "value": "[reference('appGroup', '2023-09-05', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('HostPool-{0}', parameters('time')))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Workspace-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('workSpaceName')]" - }, - "friendlyName": { - "value": "[parameters('workSpaceFriendlyName')]" - }, - "location": { - "value": "[parameters('managementPlaneLocation')]" - }, - "applicationGroupReferences": { - "value": [ - "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('{0}-{1}', variables('varApplicationGroups')[0].name, parameters('time'))), '2022-09-01').outputs.resourceId.value]" - ] - }, - "tags": { - "value": "[parameters('tags')]" - }, - "publicNetworkAccess": "[if(parameters('deployAvdPrivateLinkService'), createObject('value', parameters('workspacePublicNetworkAccess')), createObject('value', null()))]", - "privateEndpoints": "[if(parameters('deployAvdPrivateLinkService'), createObject('value', createArray(createObject('name', parameters('privateEndpointWorkspaceName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'service', 'feed', 'privateDnsZoneResourceIds', createArray(parameters('avdVnetPrivateDnsZoneConnectionResourceId'))), createObject('name', parameters('privateEndpointDiscoveryName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'service', 'global', 'privateDnsZoneResourceIds', createArray(parameters('avdVnetPrivateDnsZoneDiscoveryResourceId'))))), createObject('value', createArray()))]", - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "16965361488789112059" - }, - "name": "Workspace", - "description": "This module deploys an Azure Virtual Desktop Workspace.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "privateEndpointType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"feed\" or \"global\"." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "resourceGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the workspace." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "applicationGroupReferences": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of application group references." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Description of the workspace." - } - }, - "friendlyName": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. Friendly name of the workspace." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Enabled", - "metadata": { - "description": "Optional. Public network access for the workspace. Enabled by default." - } - }, - "privateEndpoints": { - "$ref": "#/definitions/privateEndpointType", - "metadata": { - "description": "Optional. Configuration details for private endpoints." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[take(format('46d3xbcp.res.desktopvirtualization-workspace.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "workspace": { - "type": "Microsoft.DesktopVirtualization/workspaces", - "apiVersion": "2023-09-05", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "applicationGroupReferences": "[parameters('applicationGroupReferences')]", - "description": "[parameters('description')]", - "friendlyName": "[parameters('friendlyName')]", - "publicNetworkAccess": "[parameters('publicNetworkAccess')]" - } - }, - "workspace_diagnosticSettings": { - "copy": { - "name": "workspace_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.DesktopVirtualization/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true())))]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "workspace" - ] - }, - "workspace_privateEndpoints": { - "copy": { - "name": "workspace_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-workspace-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'connection')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" - }, - "privateDnsZoneGroupName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" - }, - "privateDnsZoneResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "4120048060064073955" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "ipConfigurationsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true - }, - "manualPrivateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "privateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "customDnsConfigType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "$ref": "#/definitions/ipConfigurationsType", - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "$ref": "#/definitions/customDnsConfigType", - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", - "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." - } - }, - "privateLinkServiceConnections": { - "$ref": "#/definitions/privateLinkServiceConnectionsType", - "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" - }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "11244630631275470040" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDNSResourceIds": { - "type": "array", - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", - "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" - } - } - } - ] - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" - }, - "groupId": { - "type": "string", - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" - } - } - } - }, - "dependsOn": [ - "workspace" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the workspace." - }, - "value": "[resourceId('Microsoft.DesktopVirtualization/workspaces', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the workspace was created in." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the workspace." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location of the workspace." - }, - "value": "[reference('workspace', '2023-09-05', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('{0}-{1}', variables('varApplicationGroups')[0].name, parameters('time')))]" - ] - }, - { - "condition": "[parameters('deployScalingPlan')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Scaling-Plan-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('scalingPlanName')]" - }, - "location": { - "value": "[parameters('managementPlaneLocation')]" - }, - "hostPoolType": { - "value": "[parameters('hostPoolType')]" - }, - "exclusionTag": { - "value": "[parameters('scalingPlanExclusionTag')]" - }, - "timeZone": { - "value": "[parameters('computeTimeZone')]" - }, - "schedules": { - "value": "[parameters('scalingPlanSchedules')]" - }, - "hostPoolReferences": { - "value": [ - { - "hostPoolArmPath": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('HostPool-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]", - "scalingPlanEnabled": true - } - ] - }, - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13077254828568021707" - }, - "name": "Azure Virtual Desktop Scaling Plan", - "description": "This module deploys an Azure Virtual Desktop Scaling Plan.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `AllLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Scaling Plan." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location of the Scaling Plan. Defaults to resource group location." - } - }, - "friendlyName": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. Friendly name of the Scaling Plan." - } - }, - "timeZone": { - "type": "string", - "defaultValue": "UTC", - "metadata": { - "description": "Optional. Time zone of the Scaling Plan. Defaults to UTC." - } - }, - "hostPoolType": { - "type": "string", - "defaultValue": "Pooled", - "allowedValues": [ - "Personal", - "Pooled" - ], - "metadata": { - "description": "Optional. Host pool type of the Scaling Plan." - } - }, - "exclusionTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Exclusion tag to be used for exclusion of VMs from Scaling Plan." - } - }, - "schedules": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Schedules of the Scaling Plan." - } - }, - "hostPoolReferences": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Host pool references of the Scaling Plan." - } - }, - "description": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. Description of the Scaling Plan." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.desktopvirtualization-scalingplan.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "scalingPlan": { - "type": "Microsoft.DesktopVirtualization/scalingPlans", - "apiVersion": "2023-09-05", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "friendlyName": "[parameters('friendlyName')]", - "timeZone": "[parameters('timeZone')]", - "hostPoolType": "[parameters('hostPoolType')]", - "exclusionTag": "[parameters('exclusionTag')]", - "schedules": [], - "hostPoolReferences": "[parameters('hostPoolReferences')]", - "description": "[parameters('description')]" - } - }, - "scalingPlanSchedulePersonal": { - "copy": { - "name": "scalingPlanSchedulePersonal", - "count": "[length(parameters('schedules'))]" - }, - "condition": "[equals(parameters('hostPoolType'), 'Personal')]", - "type": "Microsoft.DesktopVirtualization/scalingPlans/personalSchedules", - "apiVersion": "2023-09-05", - "name": "[format('{0}/{1}', parameters('name'), format('{0}', parameters('schedules')[copyIndex()].name))]", - "properties": "[parameters('schedules')[copyIndex()]]", - "dependsOn": [ - "scalingPlan" - ] - }, - "scalingPlanSchedulePooled": { - "copy": { - "name": "scalingPlanSchedulePooled", - "count": "[length(parameters('schedules'))]" - }, - "condition": "[equals(parameters('hostPoolType'), 'Pooled')]", - "type": "Microsoft.DesktopVirtualization/scalingPlans/pooledSchedules", - "apiVersion": "2023-09-05", - "name": "[format('{0}/{1}', parameters('name'), format('{0}', parameters('schedules')[copyIndex()].name))]", - "properties": "[parameters('schedules')[copyIndex()]]", - "dependsOn": [ - "scalingPlan" - ] - }, - "scalingPlan_diagnosticSettings": { - "copy": { - "name": "scalingPlan_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.DesktopVirtualization/scalingPlans/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "scalingPlan" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Scaling Plan." - }, - "value": "[resourceId('Microsoft.DesktopVirtualization/scalingPlans', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Scaling Plan was created in." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Scaling Plan." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location of the Scaling Plan." - }, - "value": "[reference('scalingPlan', '2023-09-05', 'full').location]" - } - } - } - }, - "dependsOn": [ - "applicationGroups", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('HostPool-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workspace-{0}', parameters('time')))]" - ] - } - ], - "outputs": { - "hostPoolResourceId": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('HostPool-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" - } - } - } - }, - "dependsOn": [ - "baselineResourceGroups", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Identities-And-RoleAssign-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('avdSessionHostLocation')]" - }, - "subscriptionId": { - "value": "[parameters('avdWorkloadSubsId')]" - }, - "computeObjectsRgName": { - "value": "[variables('varComputeObjectsRgName')]" - }, - "createAppAttachRoleAssignments": { - "value": "[and(parameters('createAppAttachDeployment'), equals(parameters('avdIdentityServiceProvider'), 'EntraID'))]" - }, - "serviceObjectsRgName": { - "value": "[variables('varServiceObjectsRgName')]" - }, - "storageObjectsRgName": { - "value": "[variables('varStorageObjectsRgName')]" - }, - "avdServicePrincipalObjectId": { - "value": "[parameters('avdServicePrincipalObjectId')]" - }, - "avdArmServicePrincipalObjectId": { - "value": "[parameters('avdArmServicePrincipalObjectId')]" - }, - "deployScalingPlan": "[if(not(empty(parameters('avdServicePrincipalObjectId'))), createObject('value', variables('varDeployScalingPlan')), createObject('value', false()))]", - "storageManagedIdentityName": { - "value": "[variables('varStorageManagedIdentityName')]" - }, - "enableStartVmOnConnect": { - "value": "[parameters('avdStartVmOnConnect')]" - }, - "identityServiceProvider": { - "value": "[parameters('avdIdentityServiceProvider')]" - }, - "createStorageDeployment": { - "value": "[variables('varCreateStorageDeployment')]" - }, - "securityPrincipalId": { - "value": "[variables('varSecurityPrincipalId')]" - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "16449043338553652850" - } - }, - "parameters": { - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy AVD session hosts." - } - }, - "subscriptionId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "serviceObjectsRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for the service objects." - } - }, - "computeObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group name for the session hosts." - } - }, - "storageObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group Name for Azure Files." - } - }, - "avdServicePrincipalObjectId": { - "type": "string", - "metadata": { - "description": "Azure Virtual Desktop service principal object ID." - } - }, - "avdArmServicePrincipalObjectId": { - "type": "string", - "metadata": { - "description": "Azure Virtual Desktop ARM provider service principal object ID." - } - }, - "createAppAttachRoleAssignments": { - "type": "bool", - "metadata": { - "description": "Configure App Attach Role Assignments." - } - }, - "enableStartVmOnConnect": { - "type": "bool", - "metadata": { - "description": "Configure start VM on connect." - } - }, - "identityServiceProvider": { - "type": "string", - "metadata": { - "description": "Required, The service providing domain services for Azure Virtual Desktop." - } - }, - "securityPrincipalId": { - "type": "string", - "metadata": { - "description": "Required, Identity ID to grant RBAC role to access AVD application group." - } - }, - "deployScalingPlan": { - "type": "bool", - "metadata": { - "description": "Deploy scaling plan." - } - }, - "storageManagedIdentityName": { - "type": "string", - "metadata": { - "description": "Storage managed identity name." - } - }, - "createStorageDeployment": { - "type": "bool", - "metadata": { - "description": "Deploy Storage setup." - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - } - }, - "variables": { - "varVirtualMachineUserLoginRole": { - "id": "fb879df8-f326-4884-b1cf-06f3ad86be52", - "name": "Virtual Machine User Login" - }, - "varStorageSmbShareContributorRole": { - "id": "0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb", - "name": "Storage File Data SMB Share Contributor" - }, - "varDesktopVirtualizationPowerOnContributorRole": { - "id": "489581de-a3bd-480d-9518-53dea7416b33", - "name": "Desktop Virtualization Power On Contributor" - }, - "varDesktopVirtualizationPowerOnOffContributorRole": { - "id": "40c5ff49-9181-41f8-ae61-143b0e78555e", - "name": "Desktop Virtualization Power On Off Contributor" - }, - "computeAndServiceObjectsRgs": [ - { - "name": "ServiceObjects", - "rgName": "[parameters('computeObjectsRgName')]" - }, - { - "name": "Compute", - "rgName": "[parameters('serviceObjectsRgName')]" - } - ], - "storageRoleAssignments": [ - { - "name": "Storage Account Contributor", - "acronym": "StoraContri", - "id": "17d1049b-9a84-46fb-8f53-869881c3d3ab" - }, - { - "name": "Reader", - "acronym": "Reader", - "id": "acdd72a7-3385-48ef-bd42-f606fba81ae7" - } - ], - "appAttachEntraIDPrincpals": [ - { - "name": "AVD", - "id": "[parameters('avdServicePrincipalObjectId')]" - }, - { - "name": "AVDARM", - "id": "[parameters('avdArmServicePrincipalObjectId')]" - } - ] - }, - "resources": [ - { - "condition": "[and(parameters('createStorageDeployment'), not(equals(parameters('identityServiceProvider'), 'EntraID')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('MI-Storage-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('storageManagedIdentityName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "11657260805865946801" - }, - "name": "User Assigned Identities", - "description": "This module deploys a User Assigned Identity.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the User Assigned Identity." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", - "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "userAssignedIdentity": { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "userAssignedIdentity_roleAssignments": { - "copy": { - "name": "userAssignedIdentity_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the user assigned identity." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the user assigned identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The principal ID (object ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').principalId]" - }, - "clientId": { - "type": "string", - "metadata": { - "description": "The client ID (application ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').clientId]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the user assigned identity was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('userAssignedIdentity', '2023-01-31', 'full').location]" - } - } - } - } - }, - { - "copy": { - "name": "startVMonConnectRoleAssignCompute", - "count": "[length(variables('computeAndServiceObjectsRgs'))]" - }, - "condition": "[and(and(parameters('enableStartVmOnConnect'), not(parameters('deployScalingPlan'))), not(empty(parameters('avdServicePrincipalObjectId'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('StartOnCon-RolAssign-{0}-{1}', variables('computeAndServiceObjectsRgs')[copyIndex()].name, parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', variables('computeAndServiceObjectsRgs')[copyIndex()].rgName)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "roleDefinitionIdOrName": { - "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/{1}', parameters('subscriptionId'), variables('varDesktopVirtualizationPowerOnContributorRole').id)]" - }, - "principalId": { - "value": "[parameters('avdServicePrincipalObjectId')]" - }, - "resourceGroupName": { - "value": "[variables('computeAndServiceObjectsRgs')[copyIndex()].rgName]" - }, - "principalType": { - "value": "ServicePrincipal" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "298383569508499170" - }, - "name": "Role Assignments (Resource Group scope)", - "description": "This module deploys a Role Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. ID of the delegated managed identity resource." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." - } - }, - "conditionVersion": { - "type": "string", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - }, - "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", - "properties": { - "roleDefinitionId": "[variables('roleDefinitionIdVar')]", - "principalId": "[parameters('principalId')]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - }, - "scope": { - "type": "string", - "metadata": { - "description": "The scope this Role Assignment applies to." - }, - "value": "[resourceGroup().id]" - } - } - } - } - }, - { - "copy": { - "name": "scalingPlanRoleAssignCompute", - "count": "[length(variables('computeAndServiceObjectsRgs'))]" - }, - "condition": "[and(parameters('deployScalingPlan'), not(empty(parameters('avdServicePrincipalObjectId'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('ScalingPlan-RolAssign-{0}-{1}', variables('computeAndServiceObjectsRgs')[copyIndex()].name, parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', variables('computeAndServiceObjectsRgs')[copyIndex()].rgName)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "roleDefinitionIdOrName": { - "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/{1}', parameters('subscriptionId'), variables('varDesktopVirtualizationPowerOnOffContributorRole').id)]" - }, - "principalId": { - "value": "[parameters('avdServicePrincipalObjectId')]" - }, - "resourceGroupName": { - "value": "[variables('computeAndServiceObjectsRgs')[copyIndex()].rgName]" - }, - "subscriptionId": { - "value": "[parameters('subscriptionId')]" - }, - "principalType": { - "value": "ServicePrincipal" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "298383569508499170" - }, - "name": "Role Assignments (Resource Group scope)", - "description": "This module deploys a Role Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. ID of the delegated managed identity resource." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." - } - }, - "conditionVersion": { - "type": "string", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - }, - "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", - "properties": { - "roleDefinitionId": "[variables('roleDefinitionIdVar')]", - "principalId": "[parameters('principalId')]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - }, - "scope": { - "type": "string", - "metadata": { - "description": "The scope this Role Assignment applies to." - }, - "value": "[resourceGroup().id]" - } - } - } - } - }, - { - "copy": { - "name": "storageContributorRoleAssign", - "count": "[length(variables('storageRoleAssignments'))]" - }, - "condition": "[and(parameters('createStorageDeployment'), not(equals(parameters('identityServiceProvider'), 'EntraID')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Stora-RolAssign-{0}-{1}', variables('storageRoleAssignments')[copyIndex()].acronym, parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "roleDefinitionIdOrName": { - "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/{1}', parameters('subscriptionId'), variables('storageRoleAssignments')[copyIndex()].id)]" - }, - "principalId": "[if(parameters('createStorageDeployment'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('MI-Storage-{0}', parameters('time'))), '2022-09-01').outputs.principalId.value), createObject('value', ''))]", - "resourceGroupName": { - "value": "[parameters('storageObjectsRgName')]" - }, - "subscriptionId": { - "value": "[parameters('subscriptionId')]" - }, - "principalType": { - "value": "ServicePrincipal" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "298383569508499170" - }, - "name": "Role Assignments (Resource Group scope)", - "description": "This module deploys a Role Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. ID of the delegated managed identity resource." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." - } - }, - "conditionVersion": { - "type": "string", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - }, - "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", - "properties": { - "roleDefinitionId": "[variables('roleDefinitionIdVar')]", - "principalId": "[parameters('principalId')]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - }, - "scope": { - "type": "string", - "metadata": { - "description": "The scope this Role Assignment applies to." - }, - "value": "[resourceGroup().id]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('MI-Storage-{0}', parameters('time')))]" - ] - }, - { - "condition": "[and(and(parameters('createStorageDeployment'), not(empty(parameters('securityPrincipalId')))), not(equals(parameters('identityServiceProvider'), 'EntraID')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Stora-SmbContri-RolAssign{0}-{1}', take(format('{0}', parameters('securityPrincipalId')), 6), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "roleDefinitionIdOrName": { - "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/{1}', parameters('subscriptionId'), variables('varStorageSmbShareContributorRole').id)]" - }, - "principalId": "[if(not(empty(parameters('securityPrincipalId'))), createObject('value', parameters('securityPrincipalId')), createObject('value', ''))]", - "resourceGroupName": { - "value": "[parameters('storageObjectsRgName')]" - }, - "subscriptionId": { - "value": "[parameters('subscriptionId')]" - }, - "principalType": { - "value": "Group" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "298383569508499170" - }, - "name": "Role Assignments (Resource Group scope)", - "description": "This module deploys a Role Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. ID of the delegated managed identity resource." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." - } - }, - "conditionVersion": { - "type": "string", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - }, - "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", - "properties": { - "roleDefinitionId": "[variables('roleDefinitionIdVar')]", - "principalId": "[parameters('principalId')]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - }, - "scope": { - "type": "string", - "metadata": { - "description": "The scope this Role Assignment applies to." - }, - "value": "[resourceGroup().id]" - } - } - } - } - }, - { - "copy": { - "name": "storageReaderandDataAccessRoleAssign", - "count": "[length(variables('appAttachEntraIDPrincpals'))]" - }, - "condition": "[parameters('createAppAttachRoleAssignments')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Stora-ReaderData-RolAssign-{0}-{1}', variables('appAttachEntraIDPrincpals')[copyIndex()].name, parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "principalId": { - "value": "[variables('appAttachEntraIDPrincpals')[copyIndex()].id]" - }, - "roleDefinitionIdOrName": { - "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/c12c1c16-33a1-487b-954d-41c89c60f349', parameters('subscriptionId'))]" - }, - "resourceGroupName": { - "value": "[parameters('storageObjectsRgName')]" - }, - "subscriptionId": { - "value": "[parameters('subscriptionId')]" - }, - "principalType": { - "value": "ServicePrincipal" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "298383569508499170" - }, - "name": "Role Assignments (Resource Group scope)", - "description": "This module deploys a Role Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. ID of the delegated managed identity resource." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." - } - }, - "conditionVersion": { - "type": "string", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - }, - "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", - "properties": { - "roleDefinitionId": "[variables('roleDefinitionIdVar')]", - "principalId": "[parameters('principalId')]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - }, - "scope": { - "type": "string", - "metadata": { - "description": "The scope this Role Assignment applies to." - }, - "value": "[resourceGroup().id]" - } - } - } - } - }, - { - "condition": "[and(contains(parameters('identityServiceProvider'), 'EntraID'), not(empty(parameters('securityPrincipalId'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('VM-Login-Comp-{0}-{1}', take(format('{0}', parameters('securityPrincipalId')), 6), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "roleDefinitionIdOrName": { - "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/{1}', parameters('subscriptionId'), variables('varVirtualMachineUserLoginRole').id)]" - }, - "principalId": "[if(not(empty(parameters('securityPrincipalId'))), createObject('value', parameters('securityPrincipalId')), createObject('value', ''))]", - "resourceGroupName": { - "value": "[parameters('computeObjectsRgName')]" - }, - "subscriptionId": { - "value": "[parameters('subscriptionId')]" - }, - "principalType": { - "value": "Group" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "298383569508499170" - }, - "name": "Role Assignments (Resource Group scope)", - "description": "This module deploys a Role Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. ID of the delegated managed identity resource." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." - } - }, - "conditionVersion": { - "type": "string", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - }, - "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", - "properties": { - "roleDefinitionId": "[variables('roleDefinitionIdVar')]", - "principalId": "[parameters('principalId')]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - }, - "scope": { - "type": "string", - "metadata": { - "description": "The scope this Role Assignment applies to." - }, - "value": "[resourceGroup().id]" - } - } - } - } - }, - { - "condition": "[and(contains(parameters('identityServiceProvider'), 'EntraID'), not(empty(parameters('securityPrincipalId'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('VM-Login-Serv-{0}-{1}', take(format('{0}', parameters('securityPrincipalId')), 6), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "roleDefinitionIdOrName": { - "value": "[format('/subscriptions/{0}/providers/Microsoft.Authorization/roleDefinitions/{1}', parameters('subscriptionId'), variables('varVirtualMachineUserLoginRole').id)]" - }, - "principalId": "[if(not(empty(parameters('securityPrincipalId'))), createObject('value', parameters('securityPrincipalId')), createObject('value', ''))]", - "resourceGroupName": { - "value": "[parameters('serviceObjectsRgName')]" - }, - "subscriptionId": { - "value": "[parameters('subscriptionId')]" - }, - "principalType": { - "value": "Group" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "298383569508499170" - }, - "name": "Role Assignments (Resource Group scope)", - "description": "This module deploys a Role Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. ID of the delegated managed identity resource." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." - } - }, - "conditionVersion": { - "type": "string", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - }, - "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", - "properties": { - "roleDefinitionId": "[variables('roleDefinitionIdVar')]", - "principalId": "[parameters('principalId')]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - }, - "scope": { - "type": "string", - "metadata": { - "description": "The scope this Role Assignment applies to." - }, - "value": "[resourceGroup().id]" - } - } - } - } - } - ], - "outputs": { - "managedIdentityStorageResourceId": { - "type": "string", - "value": "[if(and(parameters('createStorageDeployment'), not(equals(parameters('identityServiceProvider'), 'EntraID'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('MI-Storage-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value, '')]" - }, - "managedIdentityStorageClientId": { - "type": "string", - "value": "[if(and(parameters('createStorageDeployment'), not(equals(parameters('identityServiceProvider'), 'EntraID'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('MI-Storage-{0}', parameters('time'))), '2022-09-01').outputs.clientId.value, '')]" - } - } - } - }, - "dependsOn": [ - "baselineResourceGroups", - "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]" - ] - }, - { - "condition": "[and(parameters('diskZeroTrust'), parameters('avdDeploySessionHosts'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Zero-Trust-{0}', parameters('time'))]", - "subscriptionId": "[parameters('avdWorkloadSubsId')]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('avdSessionHostLocation')]" - }, - "subscriptionId": { - "value": "[parameters('avdWorkloadSubsId')]" - }, - "diskZeroTrust": { - "value": "[parameters('diskZeroTrust')]" - }, - "serviceObjectsRgName": { - "value": "[variables('varServiceObjectsRgName')]" - }, - "computeObjectsRgName": { - "value": "[variables('varComputeObjectsRgName')]" - }, - "vaultSku": { - "value": "[variables('varWrklKeyVaultSku')]" - }, - "diskEncryptionKeyExpirationInDays": { - "value": "[parameters('diskEncryptionKeyExpirationInDays')]" - }, - "diskEncryptionSetName": { - "value": "[variables('varDiskEncryptionSetName')]" - }, - "ztKvName": { - "value": "[variables('varZtKvName')]" - }, - "ztKvPrivateEndpointName": { - "value": "[variables('varZtKvPrivateEndpointName')]" - }, - "privateEndpointsubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName'))), createObject('value', parameters('existingVnetPrivateEndpointSubnetResourceId')))]", - "deployPrivateEndpointKeyvaultStorage": { - "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" - }, - "keyVaultprivateDNSResourceId": "[if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.keyVaultDnsZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneKeyvaultId')))]", - "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]", - "enableKvPurgeProtection": { - "value": "[parameters('enableKvPurgeProtection')]" - }, - "kvTags": { - "value": "[variables('varZtKeyvaultTag')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "7927730494789166511" - } - }, - "parameters": { - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy compute services." - } - }, - "subscriptionId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "diskZeroTrust": { - "type": "bool", - "metadata": { - "description": "Enables a zero trust configuration on the session host disks." - } - }, - "serviceObjectsRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for the service objects." - } - }, - "computeObjectsRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for the service objects." - } - }, - "diskEncryptionKeyExpirationInDays": { - "type": "int", - "metadata": { - "description": "This value is used to set the expiration date on the disk encryption key." - } - }, - "deployPrivateEndpointKeyvaultStorage": { - "type": "bool", - "metadata": { - "description": "Deploy private endpoints for key vault and storage." - } - }, - "ztKvPrivateEndpointName": { - "type": "string", - "metadata": { - "description": "Key vault private endpoint name." - } - }, - "privateEndpointsubnetResourceId": { - "type": "string", - "metadata": { - "description": "Private endpoint subnet resource ID" - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "kvTags": { - "type": "object", - "metadata": { - "description": "Tags to be added to key vault" - } - }, - "diskEncryptionSetName": { - "type": "string", - "metadata": { - "description": "Encryption set name" - } - }, - "ztKvName": { - "type": "string", - "metadata": { - "description": "Key vault name" - } - }, - "keyVaultprivateDNSResourceId": { - "type": "string", - "metadata": { - "description": "Private DNS zone for key vault private endpoint" - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - }, - "enableKvPurgeProtection": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Enable purge protection on the key vault" - } - }, - "vaultSku": { - "type": "string", - "metadata": { - "description": "Specifies the SKU for the vault." - } - } - }, - "variables": { - "$fxv#0": "{\r\n \"name\": \"AVD-ACC-Zero-Trust-Disable-Managed-Disk-Network-Access\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Zero Trust - Disable Managed Disk Network Access\",\r\n \"description\": \"This policy definition sets the network access policy property to \\\"DenyAll\\\" and the public network access property to \\\"Disabled\\\" on all the managed disks within the assigned scope.\",\r\n \"metadata\": {\r\n \"version\": \"1.1.0\",\r\n \"category\": \"Security\"\r\n },\r\n \"parameters\": {\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Compute/disks\"\r\n },\r\n \"then\": {\r\n \"effect\": \"modify\",\r\n \"details\": {\r\n \"roleDefinitionIds\": [\r\n \"/providers/Microsoft.Authorization/roleDefinitions/60fc6e62-5479-42d4-8bf4-67625fcc2840\"\r\n ],\r\n \"operations\": [\r\n {\r\n \"operation\": \"addOrReplace\",\r\n \"field\": \"Microsoft.Compute/disks/networkAccessPolicy\",\r\n \"value\": \"DenyAll\"\r\n },\r\n {\r\n \"operation\": \"addOrReplace\",\r\n \"field\": \"Microsoft.Compute/disks/publicNetworkAccess\",\r\n \"value\": \"Disabled\"\r\n }\r\n ]\r\n }\r\n }\r\n }\r\n }\r\n}", - "varCustomPolicyDefinitions": [ - { - "deploymentName": "ZT-Disk", - "libDefinition": "[json(variables('$fxv#0'))]" - } - ] - }, - "resources": [ - { - "copy": { - "name": "ztPolicyDefinitions", - "count": "[length(variables('varCustomPolicyDefinitions'))]" - }, - "condition": "[parameters('diskZeroTrust')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "description": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.description]" - }, - "displayName": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.displayName]" - }, - "name": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.name]" - }, - "metadata": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.metadata]" - }, - "mode": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.mode]" - }, - "parameters": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.parameters]" - }, - "policyRule": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.policyRule]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "15296566503434303805" - } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 64, - "metadata": { - "description": "Required. Specifies the name of the policy definition. Maximum length is 64 characters." - } - }, - "displayName": { - "type": "string", - "defaultValue": "", - "maxLength": 128, - "metadata": { - "description": "Optional. The display name of the policy definition. Maximum length is 128 characters." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The policy definition description." - } - }, - "mode": { - "type": "string", - "defaultValue": "All", - "allowedValues": [ - "All", - "Indexed", - "Microsoft.KeyVault.Data", - "Microsoft.ContainerService.Data", - "Microsoft.Kubernetes.Data", - "Microsoft.Network.Data" - ], - "metadata": { - "description": "Optional. The policy definition mode. Default is All, Some examples are All, Indexed, Microsoft.KeyVault.Data." - } - }, - "metadata": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The policy Definition metadata. Metadata is an open ended object and is typically a collection of key-value pairs." - } - }, - "parameters": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The policy definition parameters that can be used in policy definition references." - } - }, - "policyRule": { - "type": "object", - "metadata": { - "description": "Required. The Policy Rule details for the Policy Definition." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/policyDefinitions", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "properties": { - "policyType": "Custom", - "mode": "[parameters('mode')]", - "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", - "parameters": "[if(not(empty(parameters('parameters'))), parameters('parameters'), null())]", - "policyRule": "[parameters('policyRule')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "Policy Definition Name." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Policy Definition resource ID." - }, - "value": "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name'))]" - }, - "roleDefinitionIds": { - "type": "array", - "metadata": { - "description": "Policy Definition Role Definition IDs." - }, - "value": "[if(contains(reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then, 'details'), if(contains(reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then.details, 'roleDefinitionIds'), reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then.details.roleDefinitionIds, createArray()), createArray())]" - } - } - } - } - }, - { - "copy": { - "name": "ztPolicyAssignmentServiceObjects", - "count": "[length(variables('varCustomPolicyDefinitions'))]" - }, - "condition": "[parameters('diskZeroTrust')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Pol-Assign-ServObj{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.name]" - }, - "displayName": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.displayName]" - }, - "description": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.description]" - }, - "identity": { - "value": "SystemAssigned" - }, - "location": { - "value": "[parameters('location')]" - }, - "policyDefinitionId": "[if(parameters('diskZeroTrust'), createObject('value', reference(subscriptionResourceId(format('{0}', parameters('subscriptionId')), 'Microsoft.Resources/deployments', format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', ''))]", - "resourceSelectors": { - "value": [ - { - "name": "VirtualMachineDisks", - "selectors": [ - { - "in": [ - "Microsoft.Compute/disks" - ], - "kind": "resourceType" - } - ] - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "10386382608825992636" - }, - "name": "Policy Assignments (Resource Group scope)", - "description": "This module deploys a Policy Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 64, - "metadata": { - "description": "Required. Specifies the name of the policy assignment. Maximum length is 64 characters for resource group scope." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. This message will be part of response in case of policy violation." - } - }, - "displayName": { - "type": "string", - "defaultValue": "", - "maxLength": 128, - "metadata": { - "description": "Optional. The display name of the policy assignment. Maximum length is 128 characters." - } - }, - "policyDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. Specifies the ID of the policy definition or policy set definition being assigned." - } - }, - "parameters": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Parameters for the policy assignment if needed." - } - }, - "identity": { - "type": "string", - "defaultValue": "SystemAssigned", - "allowedValues": [ - "SystemAssigned", - "UserAssigned", - "None" - ], - "metadata": { - "description": "Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions." - } - }, - "userAssignedIdentityId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Resource ID for the user assigned identity to assign to the policy assignment." - } - }, - "roleDefinitionIds": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." - } - }, - "metadata": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs." - } - }, - "nonComplianceMessages": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The messages that describe why a resource is non-compliant with the policy." - } - }, - "enforcementMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "DoNotEnforce" - ], - "metadata": { - "description": "Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce." - } - }, - "notScopes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The policy excluded scopes." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "overrides": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition." - } - }, - "resourceSelectors": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. The Target Scope for the Policy. The name of the resource group for the policy assignment. If not provided, will use the current scope for deployment." - } - } - }, - "variables": { - "identityVar": "[if(equals(parameters('identity'), 'SystemAssigned'), createObject('type', parameters('identity')), if(equals(parameters('identity'), 'UserAssigned'), createObject('type', parameters('identity'), 'userAssignedIdentities', createObject(format('{0}', parameters('userAssignedIdentityId')), createObject())), null()))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2022-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "properties": { - "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", - "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "policyDefinitionId": "[parameters('policyDefinitionId')]", - "parameters": "[parameters('parameters')]", - "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), parameters('nonComplianceMessages'), createArray())]", - "enforcementMode": "[parameters('enforcementMode')]", - "notScopes": "[if(not(empty(parameters('notScopes'))), parameters('notScopes'), createArray())]", - "overrides": "[if(not(empty(parameters('overrides'))), parameters('overrides'), createArray())]", - "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), createArray())]" - }, - "identity": "[variables('identityVar')]" - }, - { - "copy": { - "name": "roleAssignment", - "count": "[length(parameters('roleDefinitionIds'))]" - }, - "condition": "[and(not(empty(parameters('roleDefinitionIds'))), equals(parameters('identity'), 'SystemAssigned'))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), parameters('roleDefinitionIds')[copyIndex()], parameters('location'), parameters('name'))]", - "properties": { - "roleDefinitionId": "[parameters('roleDefinitionIds')[copyIndex()]]", - "principalId": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]", - "principalType": "ServicePrincipal" - }, - "dependsOn": [ - "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" - ] - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "Policy Assignment Name." - }, - "value": "[parameters('name')]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Policy Assignment principal ID." - }, - "value": "[coalesce(tryGet(tryGet(reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full'), 'identity'), 'principalId'), '')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Policy Assignment resource ID." - }, - "value": "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the policy was assigned to." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "ztPolicyDefinitions" - ] - }, - { - "copy": { - "name": "ztPolicyServBojRemediationTask", - "count": "[length(variables('varCustomPolicyDefinitions'))]" - }, - "condition": "[parameters('diskZeroTrust')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Remm-ServObj-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, copyIndex())]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, copyIndex())]" - }, - "policyAssignmentId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Pol-Assign-ServObj{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.resourceId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "8141314117626850328" - }, - "name": "Policy Insights Remediations (Resource Group scope)", - "description": "This module deploys a Policy Insights Remediation on a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Specifies the name of the policy remediation." - } - }, - "failureThresholdPercentage": { - "type": "string", - "defaultValue": "1", - "metadata": { - "description": "Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail." - } - }, - "filtersLocations": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The filters that will be applied to determine which resources to remediate." - } - }, - "parallelDeployments": { - "type": "int", - "defaultValue": 10, - "minValue": 1, - "maxValue": 30, - "metadata": { - "description": "Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used." - } - }, - "resourceCount": { - "type": "int", - "defaultValue": 500, - "minValue": 1, - "maxValue": 50000, - "metadata": { - "description": "Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used." - } - }, - "resourceDiscoveryMode": { - "type": "string", - "defaultValue": "ExistingNonCompliant", - "allowedValues": [ - "ExistingNonCompliant", - "ReEvaluateCompliance" - ], - "metadata": { - "description": "Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified." - } - }, - "policyAssignmentId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the policy assignment that should be remediated." - } - }, - "policyDefinitionReferenceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location deployment metadata." - } - } - }, - "resources": [ - { - "type": "Microsoft.PolicyInsights/remediations", - "apiVersion": "2021-10-01", - "name": "[parameters('name')]", - "properties": { - "failureThreshold": { - "percentage": "[json(parameters('failureThresholdPercentage'))]" - }, - "filters": { - "locations": "[parameters('filtersLocations')]" - }, - "parallelDeployments": "[parameters('parallelDeployments')]", - "policyAssignmentId": "[parameters('policyAssignmentId')]", - "policyDefinitionReferenceId": "[parameters('policyDefinitionReferenceId')]", - "resourceCount": "[parameters('resourceCount')]", - "resourceDiscoveryMode": "[parameters('resourceDiscoveryMode')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the remediation." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the remediation." - }, - "value": "[resourceId('Microsoft.PolicyInsights/remediations', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed remediation." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[parameters('location')]" - } - } - } - }, - "dependsOn": [ - "ztPolicyAssignmentServiceObjects" - ] - }, - { - "copy": { - "name": "ztPolicyAssignmentCompute", - "count": "[length(variables('varCustomPolicyDefinitions'))]" - }, - "condition": "[parameters('diskZeroTrust')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Pol-Assign-Comp-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.name]" - }, - "displayName": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.displayName]" - }, - "description": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.description]" - }, - "identity": { - "value": "SystemAssigned" - }, - "location": { - "value": "[parameters('location')]" - }, - "policyDefinitionId": "[if(parameters('diskZeroTrust'), createObject('value', reference(subscriptionResourceId(format('{0}', parameters('subscriptionId')), 'Microsoft.Resources/deployments', format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.resourceId.value), createObject('value', ''))]", - "resourceSelectors": { - "value": [ - { - "name": "VirtualMachineDisks", - "selectors": [ - { - "in": [ - "Microsoft.Compute/disks" - ], - "kind": "resourceType" - } - ] - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "10386382608825992636" - }, - "name": "Policy Assignments (Resource Group scope)", - "description": "This module deploys a Policy Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 64, - "metadata": { - "description": "Required. Specifies the name of the policy assignment. Maximum length is 64 characters for resource group scope." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. This message will be part of response in case of policy violation." - } - }, - "displayName": { - "type": "string", - "defaultValue": "", - "maxLength": 128, - "metadata": { - "description": "Optional. The display name of the policy assignment. Maximum length is 128 characters." - } - }, - "policyDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. Specifies the ID of the policy definition or policy set definition being assigned." - } - }, - "parameters": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Parameters for the policy assignment if needed." - } - }, - "identity": { - "type": "string", - "defaultValue": "SystemAssigned", - "allowedValues": [ - "SystemAssigned", - "UserAssigned", - "None" - ], - "metadata": { - "description": "Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions." - } - }, - "userAssignedIdentityId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Resource ID for the user assigned identity to assign to the policy assignment." - } - }, - "roleDefinitionIds": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." - } - }, - "metadata": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs." - } - }, - "nonComplianceMessages": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The messages that describe why a resource is non-compliant with the policy." - } - }, - "enforcementMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "DoNotEnforce" - ], - "metadata": { - "description": "Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce." - } - }, - "notScopes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The policy excluded scopes." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "overrides": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition." - } - }, - "resourceSelectors": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. The Target Scope for the Policy. The name of the resource group for the policy assignment. If not provided, will use the current scope for deployment." - } - } - }, - "variables": { - "identityVar": "[if(equals(parameters('identity'), 'SystemAssigned'), createObject('type', parameters('identity')), if(equals(parameters('identity'), 'UserAssigned'), createObject('type', parameters('identity'), 'userAssignedIdentities', createObject(format('{0}', parameters('userAssignedIdentityId')), createObject())), null()))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2022-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "properties": { - "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", - "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "policyDefinitionId": "[parameters('policyDefinitionId')]", - "parameters": "[parameters('parameters')]", - "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), parameters('nonComplianceMessages'), createArray())]", - "enforcementMode": "[parameters('enforcementMode')]", - "notScopes": "[if(not(empty(parameters('notScopes'))), parameters('notScopes'), createArray())]", - "overrides": "[if(not(empty(parameters('overrides'))), parameters('overrides'), createArray())]", - "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), createArray())]" - }, - "identity": "[variables('identityVar')]" - }, - { - "copy": { - "name": "roleAssignment", - "count": "[length(parameters('roleDefinitionIds'))]" - }, - "condition": "[and(not(empty(parameters('roleDefinitionIds'))), equals(parameters('identity'), 'SystemAssigned'))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), parameters('roleDefinitionIds')[copyIndex()], parameters('location'), parameters('name'))]", - "properties": { - "roleDefinitionId": "[parameters('roleDefinitionIds')[copyIndex()]]", - "principalId": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]", - "principalType": "ServicePrincipal" - }, - "dependsOn": [ - "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" - ] - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "Policy Assignment Name." - }, - "value": "[parameters('name')]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Policy Assignment principal ID." - }, - "value": "[coalesce(tryGet(tryGet(reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full'), 'identity'), 'principalId'), '')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Policy Assignment resource ID." - }, - "value": "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the policy was assigned to." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "ztPolicyDefinitions", - "ztPolicyServBojRemediationTask" - ] - }, - { - "copy": { - "name": "ztPolicyComputeRemediationTask", - "count": "[length(variables('varCustomPolicyDefinitions'))]" - }, - "condition": "[parameters('diskZeroTrust')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Remm-Comp-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, copyIndex())]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, copyIndex())]" - }, - "policyAssignmentId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('computeObjectsRgName'))), 'Microsoft.Resources/deployments', format('Pol-Assign-Comp-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.resourceId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "8141314117626850328" - }, - "name": "Policy Insights Remediations (Resource Group scope)", - "description": "This module deploys a Policy Insights Remediation on a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Specifies the name of the policy remediation." - } - }, - "failureThresholdPercentage": { - "type": "string", - "defaultValue": "1", - "metadata": { - "description": "Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail." - } - }, - "filtersLocations": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The filters that will be applied to determine which resources to remediate." - } - }, - "parallelDeployments": { - "type": "int", - "defaultValue": 10, - "minValue": 1, - "maxValue": 30, - "metadata": { - "description": "Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used." - } - }, - "resourceCount": { - "type": "int", - "defaultValue": 500, - "minValue": 1, - "maxValue": 50000, - "metadata": { - "description": "Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used." - } - }, - "resourceDiscoveryMode": { - "type": "string", - "defaultValue": "ExistingNonCompliant", - "allowedValues": [ - "ExistingNonCompliant", - "ReEvaluateCompliance" - ], - "metadata": { - "description": "Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified." - } - }, - "policyAssignmentId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the policy assignment that should be remediated." - } - }, - "policyDefinitionReferenceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location deployment metadata." - } - } - }, - "resources": [ - { - "type": "Microsoft.PolicyInsights/remediations", - "apiVersion": "2021-10-01", - "name": "[parameters('name')]", - "properties": { - "failureThreshold": { - "percentage": "[json(parameters('failureThresholdPercentage'))]" - }, - "filters": { - "locations": "[parameters('filtersLocations')]" - }, - "parallelDeployments": "[parameters('parallelDeployments')]", - "policyAssignmentId": "[parameters('policyAssignmentId')]", - "policyDefinitionReferenceId": "[parameters('policyDefinitionReferenceId')]", - "resourceCount": "[parameters('resourceCount')]", - "resourceDiscoveryMode": "[parameters('resourceDiscoveryMode')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the remediation." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the remediation." - }, - "value": "[resourceId('Microsoft.PolicyInsights/remediations', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed remediation." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[parameters('location')]" - } - } - } - }, - "dependsOn": [ - "ztPolicyAssignmentCompute" - ] - }, - { - "copy": { - "name": "ztRoleAssignmentCompute", - "count": "[length(variables('varCustomPolicyDefinitions'))]" - }, - "condition": "[parameters('diskZeroTrust')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('ZT-RA-Comp-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "principalId": "[if(parameters('diskZeroTrust'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('computeObjectsRgName'))), 'Microsoft.Resources/deployments', format('Pol-Assign-Comp-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.principalId.value), createObject('value', ''))]", - "roleDefinitionIdOrName": { - "value": "/providers/Microsoft.Authorization/roleDefinitions/60fc6e62-5479-42d4-8bf4-67625fcc2840" - }, - "principalType": { - "value": "ServicePrincipal" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "298383569508499170" - }, - "name": "Role Assignments (Resource Group scope)", - "description": "This module deploys a Role Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. ID of the delegated managed identity resource." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." - } - }, - "conditionVersion": { - "type": "string", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - }, - "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", - "properties": { - "roleDefinitionId": "[variables('roleDefinitionIdVar')]", - "principalId": "[parameters('principalId')]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - }, - "scope": { - "type": "string", - "metadata": { - "description": "The scope this Role Assignment applies to." - }, - "value": "[resourceGroup().id]" - } - } - } - }, - "dependsOn": [ - "ztPolicyAssignmentCompute", - "ztPolicyComputeRemediationTask" - ] - }, - { - "copy": { - "name": "ztRoleAssignmentServObj", - "count": "[length(variables('varCustomPolicyDefinitions'))]" - }, - "condition": "[parameters('diskZeroTrust')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('ZT-RA-ServObj-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "principalId": "[if(parameters('diskZeroTrust'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Pol-Assign-ServObj{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.principalId.value), createObject('value', ''))]", - "roleDefinitionIdOrName": { - "value": "/providers/Microsoft.Authorization/roleDefinitions/60fc6e62-5479-42d4-8bf4-67625fcc2840" - }, - "principalType": { - "value": "ServicePrincipal" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "298383569508499170" - }, - "name": "Role Assignments (Resource Group scope)", - "description": "This module deploys a Role Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. ID of the delegated managed identity resource." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." - } - }, - "conditionVersion": { - "type": "string", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - }, - "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", - "properties": { - "roleDefinitionId": "[variables('roleDefinitionIdVar')]", - "principalId": "[parameters('principalId')]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - }, - "scope": { - "type": "string", - "metadata": { - "description": "The scope this Role Assignment applies to." - }, - "value": "[resourceGroup().id]" - } - } - } - }, - "dependsOn": [ - "ztPolicyAssignmentServiceObjects", - "ztPolicyServBojRemediationTask" - ] - }, - { - "condition": "[parameters('diskZeroTrust')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('ZT-RA-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "principalId": "[if(parameters('diskZeroTrust'), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('ZT-Key-Vault-{0}', parameters('time'))), '2022-09-01').outputs.ztDiskEncryptionSetPrincipalId.value), createObject('value', ''))]", - "roleDefinitionIdOrName": { - "value": "/providers/Microsoft.Authorization/roleDefinitions/e147488a-f6f5-4113-8e2d-b22465e65bf6" - }, - "principalType": { - "value": "" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "298383569508499170" - }, - "name": "Role Assignments (Resource Group scope)", - "description": "This module deploys a Role Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. You can provide either the display name of the role definition (must be configured in the variable `builtInRoleNames`), or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Name of the Resource Group to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. Subscription ID of the subscription to assign the RBAC role to. If not provided, will use the current scope for deployment." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. ID of the delegated managed identity resource." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to." - } - }, - "conditionVersion": { - "type": "string", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition. Currently accepted value is \"2.0\"." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - }, - "roleDefinitionIdVar": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]", - "properties": { - "roleDefinitionId": "[variables('roleDefinitionIdVar')]", - "principalId": "[parameters('principalId')]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "delegatedManagedIdentityResourceId": "[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]", - "conditionVersion": "[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "condition": "[if(not(empty(parameters('condition'))), parameters('condition'), null())]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The GUID of the Role Assignment." - }, - "value": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Role Assignment." - }, - "value": "[resourceId('Microsoft.Authorization/roleAssignments', guid(parameters('subscriptionId'), parameters('resourceGroupName'), variables('roleDefinitionIdVar'), parameters('principalId')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the role assignment was applied at." - }, - "value": "[resourceGroup().name]" - }, - "scope": { - "type": "string", - "metadata": { - "description": "The scope this Role Assignment applies to." - }, - "value": "[resourceGroup().id]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('ZT-Key-Vault-{0}', parameters('time')))]" - ] - }, - { - "condition": "[parameters('diskZeroTrust')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('ZT-Key-Vault-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "subscriptionId": { - "value": "[parameters('subscriptionId')]" - }, - "rgName": { - "value": "[parameters('serviceObjectsRgName')]" - }, - "kvName": { - "value": "[parameters('ztKvName')]" - }, - "vaultSku": { - "value": "[parameters('vaultSku')]" - }, - "deployPrivateEndpointKeyvaultStorage": { - "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" - }, - "ztKvPrivateEndpointName": { - "value": "[parameters('ztKvPrivateEndpointName')]" - }, - "privateEndpointsubnetResourceId": { - "value": "[parameters('privateEndpointsubnetResourceId')]" - }, - "keyVaultprivateDNSResourceId": { - "value": "[parameters('keyVaultprivateDNSResourceId')]" - }, - "diskEncryptionKeyExpirationInDays": { - "value": "[parameters('diskEncryptionKeyExpirationInDays')]" - }, - "diskEncryptionSetName": { - "value": "[parameters('diskEncryptionSetName')]" - }, - "tags": { - "value": "[union(parameters('tags'), parameters('kvTags'))]" - }, - "enableKvPurgeProtection": { - "value": "[parameters('enableKvPurgeProtection')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "7847524294349175140" - } - }, - "parameters": { - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy compute services." - } - }, - "subscriptionId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "rgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for the service objects." - } - }, - "deployPrivateEndpointKeyvaultStorage": { - "type": "bool", - "metadata": { - "description": "Deploy private endpoints for key vault and storage." - } - }, - "kvName": { - "type": "string", - "metadata": { - "description": "Key vault name" - } - }, - "privateEndpointsubnetResourceId": { - "type": "string", - "metadata": { - "description": "Private endpoint subnet resource ID" - } - }, - "ztKvPrivateEndpointName": { - "type": "string", - "metadata": { - "description": "Key vault private endpoint name." - } - }, - "keyVaultprivateDNSResourceId": { - "type": "string", - "metadata": { - "description": "Private DNS zone for key vault private endpoint" - } - }, - "diskEncryptionKeyExpirationInDays": { - "type": "int", - "metadata": { - "description": "This value is used to set the expiration date on the disk encryption key." - } - }, - "diskEncryptionSetName": { - "type": "string", - "metadata": { - "description": "Encryption set name" - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - }, - "vaultSku": { - "type": "string", - "metadata": { - "description": "Specifies the SKU for the vault." - } - }, - "enableKvPurgeProtection": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Enable purge protection on the key vault" - } - } - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('ZT-KeyVault-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('rgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('kvName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableRbacAuthorization": { - "value": true - }, - "enablePurgeProtection": { - "value": "[parameters('enableKvPurgeProtection')]" - }, - "softDeleteRetentionInDays": { - "value": 7 - }, - "sku": { - "value": "[parameters('vaultSku')]" - }, - "publicNetworkAccess": { - "value": "Disabled" - }, - "networkAcls": { - "value": { - "bypass": "AzureServices", - "defaultAction": "Deny", - "virtualNetworkRules": [], - "ipRules": [] - } - }, - "privateEndpoints": "[if(parameters('deployPrivateEndpointKeyvaultStorage'), createObject('value', createArray(createObject('name', parameters('ztKvPrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointsubnetResourceId'), 'customNetworkInterfaceName', format('nic-01-{0}', parameters('ztKvPrivateEndpointName')), 'service', 'vault', 'privateDnsZoneGroup', createObject('privateDNSResourceIds', createArray(parameters('keyVaultprivateDNSResourceId')))))), createObject('value', createArray()))]", - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "14297043571004129093" - }, - "name": "Key Vaults", - "description": "This module deploys a Key Vault.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "privateEndpointType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "resourceGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "accessPoliciesType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." - } - }, - "objectId": { - "type": "string", - "metadata": { - "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." - } - }, - "applicationId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Application ID of the client making request on behalf of a principal." - } - }, - "permissions": { - "type": "object", - "properties": { - "keys": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "create", - "decrypt", - "delete", - "encrypt", - "get", - "getrotationpolicy", - "import", - "list", - "purge", - "recover", - "release", - "restore", - "rotate", - "setrotationpolicy", - "sign", - "unwrapKey", - "update", - "verify", - "wrapKey" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to keys." - } - }, - "secrets": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "delete", - "get", - "list", - "purge", - "recover", - "restore", - "set" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to secrets." - } - }, - "certificates": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "create", - "delete", - "deleteissuers", - "get", - "getissuers", - "import", - "list", - "listissuers", - "managecontacts", - "manageissuers", - "purge", - "recover", - "restore", - "setissuers", - "update" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to certificates." - } - }, - "storage": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "delete", - "deletesas", - "get", - "getsas", - "list", - "listsas", - "purge", - "recover", - "regeneratekey", - "restore", - "set", - "setsas", - "update" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to storage accounts." - } - } - }, - "metadata": { - "description": "Required. Permissions the identity has for keys, secrets and certificates." - } - } - } - }, - "nullable": true - }, - "secretsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "attributes": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Defines whether the secret is enabled or disabled." - } - }, - "exp": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Defines when the secret will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." - } - }, - "nbf": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. If set, defines the date from which onwards the secret becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Contains attributes of the secret." - } - }, - "contentType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The content type of the secret." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - } - }, - "nullable": true - }, - "keysType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the key." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "attributes": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Defines whether the key is enabled or disabled." - } - }, - "exp": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Defines when the key will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." - } - }, - "nbf": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. If set, defines the date from which onwards the key becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Contains attributes of the key." - } - }, - "curveName": { - "type": "string", - "allowedValues": [ - "P-256", - "P-256K", - "P-384", - "P-521" - ], - "nullable": true, - "metadata": { - "description": "Optional. The elliptic curve name. Only works if \"keySize\" equals \"EC\" or \"EC-HSM\". Default is \"P-256\"." - } - }, - "keyOps": { - "type": "array", - "allowedValues": [ - "decrypt", - "encrypt", - "import", - "release", - "sign", - "unwrapKey", - "verify", - "wrapKey" - ], - "nullable": true, - "metadata": { - "description": "Optional. The allowed operations on this key." - } - }, - "keySize": { - "type": "int", - "allowedValues": [ - 2048, - 3072, - 4096 - ], - "nullable": true, - "metadata": { - "description": "Optional. The key size in bits. Only works if \"keySize\" equals \"RSA\" or \"RSA-HSM\". Default is \"4096\"." - } - }, - "kty": { - "type": "string", - "allowedValues": [ - "EC", - "EC-HSM", - "RSA", - "RSA-HSM" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of the key. Default is \"EC\"." - } - }, - "releasePolicy": { - "type": "object", - "properties": { - "contentType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Content type and version of key release policy." - } - }, - "data": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Blob encoding the policy rules under which the key can be released." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Key release policy." - } - }, - "rotationPolicy": { - "$ref": "#/definitions/rotationPoliciesType", - "nullable": true, - "metadata": { - "description": "Optional. Key rotation policy." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - } - }, - "nullable": true - }, - "rotationPoliciesType": { - "type": "object", - "properties": { - "attributes": { - "type": "object", - "properties": { - "expiryTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The expiration time for the new key version. It should be in ISO8601 format. Eg: \"P90D\", \"P1Y\"." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The attributes of key rotation policy." - } - }, - "lifetimeActions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "action": { - "type": "object", - "properties": { - "type": { - "type": "string", - "allowedValues": [ - "Notify", - "Rotate" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of action." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The action of key rotation policy lifetimeAction." - } - }, - "trigger": { - "type": "object", - "properties": { - "timeAfterCreate": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The time duration after key creation to rotate the key. It only applies to rotate. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." - } - }, - "timeBeforeExpiry": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The time duration before key expiring to rotate or notify. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The trigger of key rotation policy lifetimeAction." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The lifetimeActions for key rotation action." - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. Name of the Key Vault. Must be globally unique." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "accessPolicies": { - "$ref": "#/definitions/accessPoliciesType", - "metadata": { - "description": "Optional. All access policies to create." - } - }, - "secrets": { - "$ref": "#/definitions/secretsType", - "nullable": true, - "metadata": { - "description": "Optional. All secrets to create." - } - }, - "keys": { - "$ref": "#/definitions/keysType", - "nullable": true, - "metadata": { - "description": "Optional. All keys to create." - } - }, - "enableVaultForDeployment": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies if the vault is enabled for deployment by script or compute." - } - }, - "enableVaultForTemplateDeployment": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies if the vault is enabled for a template deployment." - } - }, - "enableVaultForDiskEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies if the azure platform has access to the vault for enabling disk encryption scenarios." - } - }, - "enableSoftDelete": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Switch to enable/disable Key Vault's soft delete feature." - } - }, - "softDeleteRetentionInDays": { - "type": "int", - "defaultValue": 90, - "metadata": { - "description": "Optional. softDelete data retention days. It accepts >=7 and <=90." - } - }, - "enableRbacAuthorization": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC." - } - }, - "createMode": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The vault's create mode to indicate whether the vault need to be recovered or not. - recover or default." - } - }, - "enablePurgeProtection": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Provide 'true' to enable Key Vault's purge protection feature." - } - }, - "sku": { - "type": "string", - "defaultValue": "premium", - "allowedValues": [ - "premium", - "standard" - ], - "metadata": { - "description": "Optional. Specifies the SKU for the vault." - } - }, - "networkAcls": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Rules governing the accessibility of the resource from specific network locations." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "privateEndpoints": { - "$ref": "#/definitions/privateEndpointType", - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedAccessPolicies", - "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", - "input": { - "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", - "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", - "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", - "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" - } - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", - "Key Vault Certificates Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a4417e6f-fecd-4de8-b567-7b0420556985')]", - "Key Vault Certificate User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db79e9a7-68ee-4b58-9aeb-b90e7c24fcba')]", - "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", - "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", - "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", - "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", - "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", - "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", - "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.keyvault-vault.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "keyVault": { - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2022-07-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "enabledForDeployment": "[parameters('enableVaultForDeployment')]", - "enabledForTemplateDeployment": "[parameters('enableVaultForTemplateDeployment')]", - "enabledForDiskEncryption": "[parameters('enableVaultForDiskEncryption')]", - "enableSoftDelete": "[parameters('enableSoftDelete')]", - "softDeleteRetentionInDays": "[parameters('softDeleteRetentionInDays')]", - "enableRbacAuthorization": "[parameters('enableRbacAuthorization')]", - "createMode": "[parameters('createMode')]", - "enablePurgeProtection": "[if(parameters('enablePurgeProtection'), parameters('enablePurgeProtection'), null())]", - "tenantId": "[subscription().tenantId]", - "accessPolicies": "[variables('formattedAccessPolicies')]", - "sku": { - "name": "[parameters('sku')]", - "family": "A" - }, - "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(coalesce(parameters('privateEndpoints'), createArray()))), empty(coalesce(parameters('networkAcls'), createObject()))), 'Disabled', null()))]" - } - }, - "keyVault_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "keyVault" - ] - }, - "keyVault_diagnosticSettings": { - "copy": { - "name": "keyVault_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "keyVault" - ] - }, - "keyVault_roleAssignments": { - "copy": { - "name": "keyVault_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "keyVault" - ] - }, - "keyVault_accessPolicies": { - "condition": "[not(empty(parameters('accessPolicies')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-KeyVault-AccessPolicies', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('name')]" - }, - "accessPolicies": { - "value": "[parameters('accessPolicies')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "17696169708082133914" - }, - "name": "Key Vault Access Policies", - "description": "This module deploys a Key Vault Access Policy.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "accessPoliciesType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." - } - }, - "objectId": { - "type": "string", - "metadata": { - "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." - } - }, - "applicationId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Application ID of the client making request on behalf of a principal." - } - }, - "permissions": { - "type": "object", - "properties": { - "keys": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "create", - "decrypt", - "delete", - "encrypt", - "get", - "getrotationpolicy", - "import", - "list", - "purge", - "recover", - "release", - "restore", - "rotate", - "setrotationpolicy", - "sign", - "unwrapKey", - "update", - "verify", - "wrapKey" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to keys." - } - }, - "secrets": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "delete", - "get", - "list", - "purge", - "recover", - "restore", - "set" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to secrets." - } - }, - "certificates": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "create", - "delete", - "deleteissuers", - "get", - "getissuers", - "import", - "list", - "listissuers", - "managecontacts", - "manageissuers", - "purge", - "recover", - "restore", - "setissuers", - "update" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to certificates." - } - }, - "storage": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "delete", - "deletesas", - "get", - "getsas", - "list", - "listsas", - "purge", - "recover", - "regeneratekey", - "restore", - "set", - "setsas", - "update" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to storage accounts." - } - } - }, - "metadata": { - "description": "Required. Permissions the identity has for keys, secrets and certificates." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." - } - }, - "accessPolicies": { - "$ref": "#/definitions/accessPoliciesType", - "metadata": { - "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedAccessPolicies", - "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", - "input": { - "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", - "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", - "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", - "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" - } - } - ] - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2022-07-01", - "name": "[parameters('keyVaultName')]" - }, - "policies": { - "type": "Microsoft.KeyVault/vaults/accessPolicies", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", - "properties": { - "accessPolicies": "[variables('formattedAccessPolicies')]" - } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the access policies assignment was created in." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the access policies assignment." - }, - "value": "add" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the access policies assignment." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', parameters('keyVaultName'), 'add')]" - } - } - } - }, - "dependsOn": [ - "keyVault" - ] - }, - "keyVault_secrets": { - "copy": { - "name": "keyVault_secrets", - "count": "[length(coalesce(parameters('secrets'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-KeyVault-Secret-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].name]" - }, - "value": { - "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].value]" - }, - "keyVaultName": { - "value": "[parameters('name')]" - }, - "attributesEnabled": { - "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributesEnabled')]" - }, - "attributesExp": { - "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributesExp')]" - }, - "attributesNbf": { - "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributesNbf')]" - }, - "contentType": { - "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'contentType')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12190317675030946449" - }, - "name": "Key Vault Secrets", - "description": "This module deploys a Key Vault Secret.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "attributesEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Determines whether the object is enabled." - } - }, - "attributesExp": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." - } - }, - "attributesNbf": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." - } - }, - "contentType": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. The content type of the secret." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", - "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", - "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", - "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", - "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-07-01", - "name": "[parameters('keyVaultName')]" - }, - "secret": { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2023-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "contentType": "[parameters('contentType')]", - "attributes": { - "enabled": "[parameters('attributesEnabled')]", - "exp": "[parameters('attributesExp')]", - "nbf": "[parameters('attributesNbf')]" - }, - "value": "[parameters('value')]" - } - }, - "secret_roleAssignments": { - "copy": { - "name": "secret_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "secret" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the secret." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the secret." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the secret was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "keyVault" - ] - }, - "keyVault_keys": { - "copy": { - "name": "keyVault_keys", - "count": "[length(coalesce(parameters('keys'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-KeyVault-Key-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('keys'), createArray())[copyIndex()].name]" - }, - "keyVaultName": { - "value": "[parameters('name')]" - }, - "attributesEnabled": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesEnabled')]" - }, - "attributesExp": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesExp')]" - }, - "attributesNbf": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesNbf')]" - }, - "curveName": "[if(and(not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA')), not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM'))), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'curveName'), 'P-256')), createObject('value', null()))]", - "keyOps": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keyOps')]" - }, - "keySize": "[if(or(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA'), equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM')), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keySize'), 4096)), createObject('value', null()))]", - "releasePolicy": { - "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'releasePolicy'), createObject())]" - }, - "kty": { - "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'EC')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "rotationPolicy": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'rotationPolicy')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "1370782359529624908" - }, - "name": "Key Vault Keys", - "description": "This module deploys a Key Vault Key.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the key." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "attributesEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Determines whether the object is enabled." - } - }, - "attributesExp": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." - } - }, - "attributesNbf": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." - } - }, - "curveName": { - "type": "string", - "defaultValue": "P-256", - "allowedValues": [ - "P-256", - "P-256K", - "P-384", - "P-521" - ], - "metadata": { - "description": "Optional. The elliptic curve name." - } - }, - "keyOps": { - "type": "array", - "nullable": true, - "allowedValues": [ - "decrypt", - "encrypt", - "import", - "sign", - "unwrapKey", - "verify", - "wrapKey" - ], - "metadata": { - "description": "Optional. Array of JsonWebKeyOperation." - } - }, - "keySize": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." - } - }, - "kty": { - "type": "string", - "defaultValue": "EC", - "allowedValues": [ - "EC", - "EC-HSM", - "RSA", - "RSA-HSM" - ], - "metadata": { - "description": "Optional. The type of the key." - } - }, - "releasePolicy": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Key release policy." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "rotationPolicy": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Key rotation policy properties object." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", - "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", - "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", - "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", - "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", - "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2022-07-01", - "name": "[parameters('keyVaultName')]" - }, - "key": { - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "attributes": { - "enabled": "[parameters('attributesEnabled')]", - "exp": "[parameters('attributesExp')]", - "nbf": "[parameters('attributesNbf')]" - }, - "curveName": "[parameters('curveName')]", - "keyOps": "[parameters('keyOps')]", - "keySize": "[parameters('keySize')]", - "kty": "[parameters('kty')]", - "rotationPolicy": "[coalesce(parameters('rotationPolicy'), createObject())]", - "release_policy": "[coalesce(parameters('releasePolicy'), createObject())]" - } - }, - "key_roleAssignments": { - "copy": { - "name": "key_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "key" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the key." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the key." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the key was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "keyVault" - ] - }, - "keyVault_privateEndpoints": { - "copy": { - "name": "keyVault_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-keyVault-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroupName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" - }, - "privateDnsZoneResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "4120048060064073955" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "ipConfigurationsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true - }, - "manualPrivateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "privateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "customDnsConfigType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "$ref": "#/definitions/ipConfigurationsType", - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "$ref": "#/definitions/customDnsConfigType", - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", - "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." - } - }, - "privateLinkServiceConnections": { - "$ref": "#/definitions/privateLinkServiceConnectionsType", - "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" - }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "11244630631275470040" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDNSResourceIds": { - "type": "array", - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", - "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" - } - } - } - ] - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" - }, - "groupId": { - "type": "string", - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" - } - } - } - }, - "dependsOn": [ - "keyVault" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the key vault." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the key vault was created in." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the key vault." - }, - "value": "[parameters('name')]" - }, - "uri": { - "type": "string", - "metadata": { - "description": "The URI of the key vault." - }, - "value": "[reference('keyVault').vaultUri]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('keyVault', '2022-07-01', 'full').location]" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('ZT-KeyVaultKey-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('rgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "attributesEnabled": { - "value": true - }, - "keySize": { - "value": 4096 - }, - "keyVaultName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-KeyVault-{0}', parameters('time'))), '2022-09-01').outputs.name.value]" - }, - "kty": { - "value": "RSA" - }, - "name": { - "value": "DiskEncryptionKey" - }, - "rotationPolicy": { - "value": { - "attributes": { - "expiryTime": "[format('P{0}D', string(parameters('diskEncryptionKeyExpirationInDays')))]" - }, - "lifetimeActions": [ - { - "action": { - "type": "notify" - }, - "trigger": { - "timeBeforeExpiry": "P10D" - } - }, - { - "action": { - "type": "rotate" - }, - "trigger": { - "timeAfterCreate": "[format('P{0}D', string(sub(parameters('diskEncryptionKeyExpirationInDays'), 7)))]" - } - } - ] - } - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "1370782359529624908" - }, - "name": "Key Vault Keys", - "description": "This module deploys a Key Vault Key.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the key." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "attributesEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Determines whether the object is enabled." - } - }, - "attributesExp": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." - } - }, - "attributesNbf": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." - } - }, - "curveName": { - "type": "string", - "defaultValue": "P-256", - "allowedValues": [ - "P-256", - "P-256K", - "P-384", - "P-521" - ], - "metadata": { - "description": "Optional. The elliptic curve name." - } - }, - "keyOps": { - "type": "array", - "nullable": true, - "allowedValues": [ - "decrypt", - "encrypt", - "import", - "sign", - "unwrapKey", - "verify", - "wrapKey" - ], - "metadata": { - "description": "Optional. Array of JsonWebKeyOperation." - } - }, - "keySize": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." - } - }, - "kty": { - "type": "string", - "defaultValue": "EC", - "allowedValues": [ - "EC", - "EC-HSM", - "RSA", - "RSA-HSM" - ], - "metadata": { - "description": "Optional. The type of the key." - } - }, - "releasePolicy": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Key release policy." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "rotationPolicy": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Key rotation policy properties object." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", - "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", - "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", - "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", - "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", - "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2022-07-01", - "name": "[parameters('keyVaultName')]" - }, - "key": { - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "attributes": { - "enabled": "[parameters('attributesEnabled')]", - "exp": "[parameters('attributesExp')]", - "nbf": "[parameters('attributesNbf')]" - }, - "curveName": "[parameters('curveName')]", - "keyOps": "[parameters('keyOps')]", - "keySize": "[parameters('keySize')]", - "kty": "[parameters('kty')]", - "rotationPolicy": "[coalesce(parameters('rotationPolicy'), createObject())]", - "release_policy": "[coalesce(parameters('releasePolicy'), createObject())]" - } - }, - "key_roleAssignments": { - "copy": { - "name": "key_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "key" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the key." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the key." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the key was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-KeyVault-{0}', parameters('time')))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('ZT-DiskEncryptionSet-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('rgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyName": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-KeyVaultKey-{0}', parameters('time'))), '2022-09-01').outputs.name.value]" - }, - "keyVaultResourceId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-KeyVault-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" - }, - "location": { - "value": "[parameters('location')]" - }, - "name": { - "value": "[parameters('diskEncryptionSetName')]" - }, - "rotationToLatestKeyVersionEnabled": { - "value": true - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "15993472351338005036" - }, - "name": "Disk Encryption Sets", - "description": "This module deploys a Disk Encryption Set. The module will attempt to set permissions on the provided Key Vault for any used user-assigned identity.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "managedIdentitiesType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the disk encryption set that is being created." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Resource location." - } - }, - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the KeyVault containing the key or secret." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. Key URL (with version) pointing to a key or secret in KeyVault." - } - }, - "keyVersion": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the latest key version is used." - } - }, - "encryptionType": { - "type": "string", - "defaultValue": "EncryptionAtRestWithPlatformAndCustomerKeys", - "allowedValues": [ - "EncryptionAtRestWithCustomerKey", - "EncryptionAtRestWithPlatformAndCustomerKeys" - ], - "metadata": { - "description": "Optional. The type of key used to encrypt the data of the disk. For security reasons, it is recommended to set encryptionType to EncryptionAtRestWithPlatformAndCustomerKeys." - } - }, - "federatedClientId": { - "type": "string", - "defaultValue": "None", - "metadata": { - "description": "Optional. Multi-tenant application client ID to access key vault in a different tenant. Setting the value to \"None\" will clear the property." - } - }, - "rotationToLatestKeyVersionEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Set this flag to true to enable auto-updating of this disk encryption set to the latest key version." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", - "defaultValue": { - "systemAssigned": true - }, - "metadata": { - "description": "Optional. The managed identity definition for this resource. At least one identity type is required." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the disk encryption resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", - "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", - "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", - "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", - "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - } - }, - "resources": { - "keyVault::key": { - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2021-10-01", - "subscriptionId": "[split(parameters('keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(parameters('keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(parameters('keyVaultResourceId'), '/')), parameters('keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.compute-diskencryptionset.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2021-10-01", - "subscriptionId": "[split(parameters('keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(parameters('keyVaultResourceId'), '/')[4]]", - "name": "[last(split(parameters('keyVaultResourceId'), '/'))]" - }, - "diskEncryptionSet": { - "type": "Microsoft.Compute/diskEncryptionSets", - "apiVersion": "2023-10-02", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": { - "activeKey": { - "sourceVault": { - "id": "[parameters('keyVaultResourceId')]" - }, - "keyUrl": "[if(not(empty(parameters('keyVersion'))), format('{0}/{1}', reference('keyVault::key').keyUri, parameters('keyVersion')), reference('keyVault::key').keyUriWithVersion)]" - }, - "encryptionType": "[parameters('encryptionType')]", - "federatedClientId": "[parameters('federatedClientId')]", - "rotationToLatestKeyVersionEnabled": "[parameters('rotationToLatestKeyVersionEnabled')]" - }, - "dependsOn": [ - "keyVault::key", - "keyVaultPermissions" - ] - }, - "keyVaultPermissions": { - "copy": { - "name": "keyVaultPermissions", - "count": "[length(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-DiskEncrSet-KVPermissions-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(parameters('keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(parameters('keyVaultResourceId'), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyName": { - "value": "[parameters('keyName')]" - }, - "keyVaultResourceId": { - "value": "[parameters('keyVaultResourceId')]" - }, - "userAssignedIdentityResourceId": { - "value": "[coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray())[copyIndex()]]" - }, - "rbacAuthorizationEnabled": { - "value": "[reference('keyVault').enableRbacAuthorization]" - }, - "location": { - "value": "[parameters('location')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12732011659166716786" - } - }, - "parameters": { - "rbacAuthorizationEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Required. A boolean to specify whether or not the used Key Vault has RBAC authentication enabled or not." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resourceID of the User Assigned Identity to assign permissions to." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Resource location." - } - }, - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the KeyVault containing the key or secret." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. Name of the key to set the permissions for." - } - } - }, - "resources": [ - { - "condition": "[equals(parameters('rbacAuthorizationEnabled'), true())]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', last(split(parameters('keyVaultResourceId'), '/')), parameters('keyName'))]", - "name": "[guid(format('msi-{0}-{1}-{2}-Key-Reader-RoleAssignment', resourceId('Microsoft.KeyVault/vaults/keys', last(split(parameters('keyVaultResourceId'), '/')), parameters('keyName')), parameters('location'), parameters('userAssignedIdentityResourceId')))]", - "properties": { - "principalId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('userAssignedIdentityResourceId'), '/')[2], split(parameters('userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(parameters('userAssignedIdentityResourceId'), '/'))), '2023-01-31').principalId]", - "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", - "principalType": "ServicePrincipal" - } - }, - { - "condition": "[not(equals(parameters('rbacAuthorizationEnabled'), true()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-DiskEncrSet-KVAccessPolicies', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(parameters('keyVaultResourceId'), '/'))]" - }, - "accessPolicies": { - "value": [ - { - "tenantId": "[subscription().tenantId]", - "objectId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('userAssignedIdentityResourceId'), '/')[2], split(parameters('userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(parameters('userAssignedIdentityResourceId'), '/'))), '2023-01-31').principalId]", - "permissions": { - "keys": [ - "get", - "wrapKey", - "unwrapKey" - ] - } - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "8247309965052145251" - }, - "name": "Key Vault Access Policies", - "description": "This module deploys a Key Vault Access Policy.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "accessPoliciesType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." - } - }, - "objectId": { - "type": "string", - "metadata": { - "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." - } - }, - "applicationId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Application ID of the client making request on behalf of a principal." - } - }, - "permissions": { - "type": "object", - "properties": { - "keys": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "create", - "decrypt", - "delete", - "encrypt", - "get", - "getrotationpolicy", - "import", - "list", - "purge", - "recover", - "release", - "restore", - "rotate", - "setrotationpolicy", - "sign", - "unwrapKey", - "update", - "verify", - "wrapKey" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to keys." - } - }, - "secrets": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "delete", - "get", - "list", - "purge", - "recover", - "restore", - "set" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to secrets." - } - }, - "certificates": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "create", - "delete", - "deleteissuers", - "get", - "getissuers", - "import", - "list", - "listissuers", - "managecontacts", - "manageissuers", - "purge", - "recover", - "restore", - "setissuers", - "update" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to certificates." - } - }, - "storage": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "delete", - "deletesas", - "get", - "getsas", - "list", - "listsas", - "purge", - "recover", - "regeneratekey", - "restore", - "set", - "setsas", - "update" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to storage accounts." - } - } - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." - } - }, - "accessPolicies": { - "$ref": "#/definitions/accessPoliciesType", - "metadata": { - "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedAccessPolicies", - "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", - "input": { - "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", - "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", - "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", - "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" - } - } - ] - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2022-07-01", - "name": "[parameters('keyVaultName')]" - }, - "policies": { - "type": "Microsoft.KeyVault/vaults/accessPolicies", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", - "properties": { - "accessPolicies": "[variables('formattedAccessPolicies')]" - } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the access policies assignment was created in." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the access policies assignment." - }, - "value": "add" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the access policies assignment." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', parameters('keyVaultName'), 'add')]" - } - } - } - } - } - ] - } - }, - "dependsOn": [ - "keyVault" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the disk encryption set." - }, - "value": "[resourceId('Microsoft.Compute/diskEncryptionSets', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the disk encryption set." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the disk encryption set was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[coalesce(tryGet(tryGet(reference('diskEncryptionSet', '2023-10-02', 'full'), 'identity'), 'principalId'), '')]" - }, - "identities": { - "type": "object", - "metadata": { - "description": "The idenities of the disk encryption set." - }, - "value": "[reference('diskEncryptionSet', '2023-10-02', 'full').identity]" - }, - "keyVaultName": { - "type": "string", - "metadata": { - "description": "The name of the key vault with the disk encryption key." - }, - "value": "[last(split(parameters('keyVaultResourceId'), '/'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('diskEncryptionSet', '2023-10-02', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-KeyVault-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-KeyVaultKey-{0}', parameters('time')))]" - ] - } - ], - "outputs": { - "ztDiskEncryptionSetResourceId": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-DiskEncryptionSet-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" - }, - "ztDiskEncryptionSetPrincipalId": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('rgName'))), 'Microsoft.Resources/deployments', format('ZT-DiskEncryptionSet-{0}', parameters('time'))), '2022-09-01').outputs.systemAssignedMIPrincipalId.value]" - } - } - } - } - } - ], - "outputs": { - "ztDiskEncryptionSetResourceId": { - "type": "string", - "value": "[if(parameters('diskZeroTrust'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('serviceObjectsRgName'))), 'Microsoft.Resources/deployments', format('ZT-Key-Vault-{0}', parameters('time'))), '2022-09-01').outputs.ztDiskEncryptionSetResourceId.value, '')]" - } - } - } - }, - "dependsOn": [ - "baselineResourceGroups", - "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Workload-KeyVault-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('avdWorkloadSubsId'))]", - "resourceGroup": "[format('{0}', variables('varServiceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('varWrklKvName')]" - }, - "location": { - "value": "[parameters('avdSessionHostLocation')]" - }, - "enableRbacAuthorization": { - "value": true - }, - "enablePurgeProtection": { - "value": "[parameters('enableKvPurgeProtection')]" - }, - "sku": { - "value": "[variables('varWrklKeyVaultSku')]" - }, - "softDeleteRetentionInDays": { - "value": 7 - }, - "publicNetworkAccess": "[if(parameters('deployPrivateEndpointKeyvaultStorage'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "networkAcls": "[if(parameters('deployPrivateEndpointKeyvaultStorage'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName')), parameters('existingVnetAvdSubnetResourceId')), 'action', 'Allow')), 'ipRules', createArray())))]", - "privateEndpoints": "[if(parameters('deployPrivateEndpointKeyvaultStorage'), createObject('value', createArray(createObject('name', variables('varWrklKvPrivateEndpointName'), 'subnetResourceId', if(parameters('createAvdVnet'), format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName')), parameters('existingVnetPrivateEndpointSubnetResourceId')), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklKvPrivateEndpointName')), 'service', 'vault', 'privateDnsZoneGroupName', if(parameters('createPrivateDnsZones'), split(reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.keyVaultDnsZoneResourceId.value, '/')[8], split(parameters('avdVnetPrivateDnsZoneKeyvaultId'), '/')[8]), 'privateDnsZoneResourceIds', createArray(if(parameters('createPrivateDnsZones'), reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.keyVaultDnsZoneResourceId.value, parameters('avdVnetPrivateDnsZoneKeyvaultId')))))), createObject('value', createArray()))]", - "secrets": "[if(not(contains(parameters('avdIdentityServiceProvider'), 'EntraID')), createObject('value', createArray(createObject('name', 'vmLocalUserPassword', 'value', parameters('avdVmLocalUserPassword'), 'contentType', 'Session host local user credentials'), createObject('name', 'vmLocalUserName', 'value', parameters('avdVmLocalUserName'), 'contentType', 'Session host local user credentials'), createObject('name', 'domainJoinUserName', 'value', parameters('avdDomainJoinUserName'), 'contentType', 'Domain join credentials'), createObject('name', 'domainJoinUserPassword', 'value', parameters('avdDomainJoinUserPassword'), 'contentType', 'Domain join credentials'))), createObject('value', createArray(createObject('name', 'vmLocalUserPassword', 'value', parameters('avdVmLocalUserPassword'), 'contentType', 'Session host local user credentials'), createObject('name', 'vmLocalUserName', 'value', parameters('avdVmLocalUserName'), 'contentType', 'Session host local user credentials'), createObject('name', 'domainJoinUserName', 'value', 'NoUsername', 'contentType', 'Domain join credentials'), createObject('name', 'domainJoinUserPassword', 'value', 'NoPassword', 'contentType', 'Domain join credentials'))))]", - "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'), variables('varWorkloadKeyvaultTag'))), createObject('value', union(variables('varAvdDefaultTags'), variables('varWorkloadKeyvaultTag'))))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "14297043571004129093" - }, - "name": "Key Vaults", - "description": "This module deploys a Key Vault.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "privateEndpointType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "resourceGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "accessPoliciesType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." - } - }, - "objectId": { - "type": "string", - "metadata": { - "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." - } - }, - "applicationId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Application ID of the client making request on behalf of a principal." - } - }, - "permissions": { - "type": "object", - "properties": { - "keys": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "create", - "decrypt", - "delete", - "encrypt", - "get", - "getrotationpolicy", - "import", - "list", - "purge", - "recover", - "release", - "restore", - "rotate", - "setrotationpolicy", - "sign", - "unwrapKey", - "update", - "verify", - "wrapKey" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to keys." - } - }, - "secrets": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "delete", - "get", - "list", - "purge", - "recover", - "restore", - "set" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to secrets." - } - }, - "certificates": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "create", - "delete", - "deleteissuers", - "get", - "getissuers", - "import", - "list", - "listissuers", - "managecontacts", - "manageissuers", - "purge", - "recover", - "restore", - "setissuers", - "update" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to certificates." - } - }, - "storage": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "delete", - "deletesas", - "get", - "getsas", - "list", - "listsas", - "purge", - "recover", - "regeneratekey", - "restore", - "set", - "setsas", - "update" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to storage accounts." - } - } - }, - "metadata": { - "description": "Required. Permissions the identity has for keys, secrets and certificates." - } - } - } - }, - "nullable": true - }, - "secretsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "attributes": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Defines whether the secret is enabled or disabled." - } - }, - "exp": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Defines when the secret will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." - } - }, - "nbf": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. If set, defines the date from which onwards the secret becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Contains attributes of the secret." - } - }, - "contentType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The content type of the secret." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - } - }, - "nullable": true - }, - "keysType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the key." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "attributes": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Defines whether the key is enabled or disabled." - } - }, - "exp": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Defines when the key will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." - } - }, - "nbf": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. If set, defines the date from which onwards the key becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Contains attributes of the key." - } - }, - "curveName": { - "type": "string", - "allowedValues": [ - "P-256", - "P-256K", - "P-384", - "P-521" - ], - "nullable": true, - "metadata": { - "description": "Optional. The elliptic curve name. Only works if \"keySize\" equals \"EC\" or \"EC-HSM\". Default is \"P-256\"." - } - }, - "keyOps": { - "type": "array", - "allowedValues": [ - "decrypt", - "encrypt", - "import", - "release", - "sign", - "unwrapKey", - "verify", - "wrapKey" - ], - "nullable": true, - "metadata": { - "description": "Optional. The allowed operations on this key." - } - }, - "keySize": { - "type": "int", - "allowedValues": [ - 2048, - 3072, - 4096 - ], - "nullable": true, - "metadata": { - "description": "Optional. The key size in bits. Only works if \"keySize\" equals \"RSA\" or \"RSA-HSM\". Default is \"4096\"." - } - }, - "kty": { - "type": "string", - "allowedValues": [ - "EC", - "EC-HSM", - "RSA", - "RSA-HSM" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of the key. Default is \"EC\"." - } - }, - "releasePolicy": { - "type": "object", - "properties": { - "contentType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Content type and version of key release policy." - } - }, - "data": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Blob encoding the policy rules under which the key can be released." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Key release policy." - } - }, - "rotationPolicy": { - "$ref": "#/definitions/rotationPoliciesType", - "nullable": true, - "metadata": { - "description": "Optional. Key rotation policy." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - } - }, - "nullable": true - }, - "rotationPoliciesType": { - "type": "object", - "properties": { - "attributes": { - "type": "object", - "properties": { - "expiryTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The expiration time for the new key version. It should be in ISO8601 format. Eg: \"P90D\", \"P1Y\"." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The attributes of key rotation policy." - } - }, - "lifetimeActions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "action": { - "type": "object", - "properties": { - "type": { - "type": "string", - "allowedValues": [ - "Notify", - "Rotate" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of action." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The action of key rotation policy lifetimeAction." - } - }, - "trigger": { - "type": "object", - "properties": { - "timeAfterCreate": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The time duration after key creation to rotate the key. It only applies to rotate. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." - } - }, - "timeBeforeExpiry": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The time duration before key expiring to rotate or notify. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The trigger of key rotation policy lifetimeAction." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The lifetimeActions for key rotation action." - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. Name of the Key Vault. Must be globally unique." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "accessPolicies": { - "$ref": "#/definitions/accessPoliciesType", - "metadata": { - "description": "Optional. All access policies to create." - } - }, - "secrets": { - "$ref": "#/definitions/secretsType", - "nullable": true, - "metadata": { - "description": "Optional. All secrets to create." - } - }, - "keys": { - "$ref": "#/definitions/keysType", - "nullable": true, - "metadata": { - "description": "Optional. All keys to create." - } - }, - "enableVaultForDeployment": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies if the vault is enabled for deployment by script or compute." - } - }, - "enableVaultForTemplateDeployment": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies if the vault is enabled for a template deployment." - } - }, - "enableVaultForDiskEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies if the azure platform has access to the vault for enabling disk encryption scenarios." - } - }, - "enableSoftDelete": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Switch to enable/disable Key Vault's soft delete feature." - } - }, - "softDeleteRetentionInDays": { - "type": "int", - "defaultValue": 90, - "metadata": { - "description": "Optional. softDelete data retention days. It accepts >=7 and <=90." - } - }, - "enableRbacAuthorization": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC." - } - }, - "createMode": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The vault's create mode to indicate whether the vault need to be recovered or not. - recover or default." - } - }, - "enablePurgeProtection": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Provide 'true' to enable Key Vault's purge protection feature." - } - }, - "sku": { - "type": "string", - "defaultValue": "premium", - "allowedValues": [ - "premium", - "standard" - ], - "metadata": { - "description": "Optional. Specifies the SKU for the vault." - } - }, - "networkAcls": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Rules governing the accessibility of the resource from specific network locations." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "privateEndpoints": { - "$ref": "#/definitions/privateEndpointType", - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedAccessPolicies", - "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", - "input": { - "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", - "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", - "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", - "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" - } - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", - "Key Vault Certificates Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a4417e6f-fecd-4de8-b567-7b0420556985')]", - "Key Vault Certificate User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db79e9a7-68ee-4b58-9aeb-b90e7c24fcba')]", - "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", - "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", - "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", - "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", - "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", - "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", - "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.keyvault-vault.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "keyVault": { - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2022-07-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "enabledForDeployment": "[parameters('enableVaultForDeployment')]", - "enabledForTemplateDeployment": "[parameters('enableVaultForTemplateDeployment')]", - "enabledForDiskEncryption": "[parameters('enableVaultForDiskEncryption')]", - "enableSoftDelete": "[parameters('enableSoftDelete')]", - "softDeleteRetentionInDays": "[parameters('softDeleteRetentionInDays')]", - "enableRbacAuthorization": "[parameters('enableRbacAuthorization')]", - "createMode": "[parameters('createMode')]", - "enablePurgeProtection": "[if(parameters('enablePurgeProtection'), parameters('enablePurgeProtection'), null())]", - "tenantId": "[subscription().tenantId]", - "accessPolicies": "[variables('formattedAccessPolicies')]", - "sku": { - "name": "[parameters('sku')]", - "family": "A" - }, - "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(coalesce(parameters('privateEndpoints'), createArray()))), empty(coalesce(parameters('networkAcls'), createObject()))), 'Disabled', null()))]" - } - }, - "keyVault_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "keyVault" - ] - }, - "keyVault_diagnosticSettings": { - "copy": { - "name": "keyVault_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "keyVault" - ] - }, - "keyVault_roleAssignments": { - "copy": { - "name": "keyVault_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "keyVault" - ] - }, - "keyVault_accessPolicies": { - "condition": "[not(empty(parameters('accessPolicies')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-KeyVault-AccessPolicies', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('name')]" - }, - "accessPolicies": { - "value": "[parameters('accessPolicies')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "17696169708082133914" - }, - "name": "Key Vault Access Policies", - "description": "This module deploys a Key Vault Access Policy.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "accessPoliciesType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." - } - }, - "objectId": { - "type": "string", - "metadata": { - "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." - } - }, - "applicationId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Application ID of the client making request on behalf of a principal." - } - }, - "permissions": { - "type": "object", - "properties": { - "keys": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "create", - "decrypt", - "delete", - "encrypt", - "get", - "getrotationpolicy", - "import", - "list", - "purge", - "recover", - "release", - "restore", - "rotate", - "setrotationpolicy", - "sign", - "unwrapKey", - "update", - "verify", - "wrapKey" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to keys." - } - }, - "secrets": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "delete", - "get", - "list", - "purge", - "recover", - "restore", - "set" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to secrets." - } - }, - "certificates": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "create", - "delete", - "deleteissuers", - "get", - "getissuers", - "import", - "list", - "listissuers", - "managecontacts", - "manageissuers", - "purge", - "recover", - "restore", - "setissuers", - "update" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to certificates." - } - }, - "storage": { - "type": "array", - "allowedValues": [ - "all", - "backup", - "delete", - "deletesas", - "get", - "getsas", - "list", - "listsas", - "purge", - "recover", - "regeneratekey", - "restore", - "set", - "setsas", - "update" - ], - "nullable": true, - "metadata": { - "description": "Optional. Permissions to storage accounts." - } - } - }, - "metadata": { - "description": "Required. Permissions the identity has for keys, secrets and certificates." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." - } - }, - "accessPolicies": { - "$ref": "#/definitions/accessPoliciesType", - "metadata": { - "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedAccessPolicies", - "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", - "input": { - "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", - "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", - "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", - "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" - } - } - ] - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2022-07-01", - "name": "[parameters('keyVaultName')]" - }, - "policies": { - "type": "Microsoft.KeyVault/vaults/accessPolicies", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", - "properties": { - "accessPolicies": "[variables('formattedAccessPolicies')]" - } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the access policies assignment was created in." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the access policies assignment." - }, - "value": "add" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the access policies assignment." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', parameters('keyVaultName'), 'add')]" - } - } - } - }, - "dependsOn": [ - "keyVault" - ] - }, - "keyVault_secrets": { - "copy": { - "name": "keyVault_secrets", - "count": "[length(coalesce(parameters('secrets'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-KeyVault-Secret-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].name]" - }, - "value": { - "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].value]" - }, - "keyVaultName": { - "value": "[parameters('name')]" - }, - "attributesEnabled": { - "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributesEnabled')]" - }, - "attributesExp": { - "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributesExp')]" - }, - "attributesNbf": { - "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributesNbf')]" - }, - "contentType": { - "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'contentType')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12190317675030946449" - }, - "name": "Key Vault Secrets", - "description": "This module deploys a Key Vault Secret.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "attributesEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Determines whether the object is enabled." - } - }, - "attributesExp": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." - } - }, - "attributesNbf": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." - } - }, - "contentType": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. The content type of the secret." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", - "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", - "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", - "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", - "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-07-01", - "name": "[parameters('keyVaultName')]" - }, - "secret": { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2023-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "contentType": "[parameters('contentType')]", - "attributes": { - "enabled": "[parameters('attributesEnabled')]", - "exp": "[parameters('attributesExp')]", - "nbf": "[parameters('attributesNbf')]" - }, - "value": "[parameters('value')]" - } - }, - "secret_roleAssignments": { - "copy": { - "name": "secret_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "secret" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the secret." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the secret." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the secret was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "keyVault" - ] - }, - "keyVault_keys": { - "copy": { - "name": "keyVault_keys", - "count": "[length(coalesce(parameters('keys'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-KeyVault-Key-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('keys'), createArray())[copyIndex()].name]" - }, - "keyVaultName": { - "value": "[parameters('name')]" - }, - "attributesEnabled": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesEnabled')]" - }, - "attributesExp": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesExp')]" - }, - "attributesNbf": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesNbf')]" - }, - "curveName": "[if(and(not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA')), not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM'))), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'curveName'), 'P-256')), createObject('value', null()))]", - "keyOps": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keyOps')]" - }, - "keySize": "[if(or(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA'), equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM')), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keySize'), 4096)), createObject('value', null()))]", - "releasePolicy": { - "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'releasePolicy'), createObject())]" - }, - "kty": { - "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'EC')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "rotationPolicy": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'rotationPolicy')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "1370782359529624908" - }, - "name": "Key Vault Keys", - "description": "This module deploys a Key Vault Key.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the key." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "attributesEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Determines whether the object is enabled." - } - }, - "attributesExp": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." - } - }, - "attributesNbf": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." - } - }, - "curveName": { - "type": "string", - "defaultValue": "P-256", - "allowedValues": [ - "P-256", - "P-256K", - "P-384", - "P-521" - ], - "metadata": { - "description": "Optional. The elliptic curve name." - } - }, - "keyOps": { - "type": "array", - "nullable": true, - "allowedValues": [ - "decrypt", - "encrypt", - "import", - "sign", - "unwrapKey", - "verify", - "wrapKey" - ], - "metadata": { - "description": "Optional. Array of JsonWebKeyOperation." - } - }, - "keySize": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." - } - }, - "kty": { - "type": "string", - "defaultValue": "EC", - "allowedValues": [ - "EC", - "EC-HSM", - "RSA", - "RSA-HSM" - ], - "metadata": { - "description": "Optional. The type of the key." - } - }, - "releasePolicy": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Key release policy." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "rotationPolicy": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Key rotation policy properties object." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", - "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", - "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", - "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", - "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", - "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "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')]" - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2022-07-01", - "name": "[parameters('keyVaultName')]" - }, - "key": { - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "attributes": { - "enabled": "[parameters('attributesEnabled')]", - "exp": "[parameters('attributesExp')]", - "nbf": "[parameters('attributesNbf')]" - }, - "curveName": "[parameters('curveName')]", - "keyOps": "[parameters('keyOps')]", - "keySize": "[parameters('keySize')]", - "kty": "[parameters('kty')]", - "rotationPolicy": "[coalesce(parameters('rotationPolicy'), createObject())]", - "release_policy": "[coalesce(parameters('releasePolicy'), createObject())]" - } - }, - "key_roleAssignments": { - "copy": { - "name": "key_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "key" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the key." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the key." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the key was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "keyVault" - ] - }, - "keyVault_privateEndpoints": { - "copy": { - "name": "keyVault_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-keyVault-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroupName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" - }, - "privateDnsZoneResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "4120048060064073955" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "ipConfigurationsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true - }, - "manualPrivateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "privateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "customDnsConfigType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "$ref": "#/definitions/ipConfigurationsType", - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "$ref": "#/definitions/customDnsConfigType", - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", - "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." - } - }, - "privateLinkServiceConnections": { - "$ref": "#/definitions/privateLinkServiceConnectionsType", - "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" - }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "11244630631275470040" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDNSResourceIds": { - "type": "array", - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", - "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" - } - } - } - ] - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" - }, - "groupId": { - "type": "string", - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" - } - } - } - }, - "dependsOn": [ - "keyVault" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the key vault." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the key vault was created in." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the key vault." - }, - "value": "[parameters('name')]" - }, - "uri": { - "type": "string", - "metadata": { - "description": "The URI of the key vault." - }, - "value": "[reference('keyVault').vaultUri]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('keyVault', '2022-07-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "baselineResourceGroups", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]" - ] - }, - { - "condition": "[variables('varCreateStorageDeployment')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('SMB-Storage-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('avdWorkloadSubsId'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "deploymentPrefix": { - "value": "[variables('varDeploymentPrefixLowercase')]" - }, - "deploymentEnvironment": { - "value": "[variables('varDeploymentEnvironmentLowercase')]" - }, - "storageService": { - "value": "[parameters('storageService')]" - }, - "useCustomNaming": { - "value": "[parameters('avdUseCustomNaming')]" - }, - "storageAvailabilityZones": { - "value": "[parameters('zoneRedundantStorage')]" - }, - "domainJoinUserName": { - "value": "[parameters('avdDomainJoinUserName')]" - }, - "vmLocalUserName": { - "value": "[parameters('avdVmLocalUserName')]" - }, - "identityServiceProvider": { - "value": "[parameters('avdIdentityServiceProvider')]" - }, - "avdSessionHostsOuPath": { - "value": "[parameters('avdOuPath')]" - }, - "storageOuPath": { - "value": "[parameters('storageOuPath')]" - }, - "managementVmSize": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostsSize')), createObject('value', 'Standard_D2ads_v5'))]", - "createResourceTags": { - "value": "[parameters('createResourceTags')]" - }, - "deployPrivateEndpointKeyvaultStorage": { - "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" - }, - "dnsServers": { - "value": "[parameters('customDnsIps')]" - }, - "identityDomainName": { - "value": "[parameters('identityDomainName')]" - }, - "storageObjectsRgName": { - "value": "[variables('varStorageObjectsRgName')]" - }, - "baseScriptUri": { - "value": "[variables('varBaseScriptUri')]" - }, - "securityPrincipalName": { - "value": "[variables('varSecurityPrincipalName')]" - }, - "diskEncryptionSetResourceId": "[if(parameters('diskZeroTrust'), createObject('value', reference(subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time'))), '2022-09-01').outputs.ztDiskEncryptionSetResourceId.value), createObject('value', ''))]", - "sessionHostTimeZone": { - "value": "[variables('varTimeZoneSessionHosts')]" - }, - "createFslogixDeployment": { - "value": "[parameters('createFslogixDeployment')]" - }, - "securityType": "[if(equals(parameters('securityType'), 'Standard'), createObject('value', ''), createObject('value', parameters('securityType')))]", - "secureBootEnabled": { - "value": "[parameters('secureBootEnabled')]" - }, - "vTpmEnabled": { - "value": "[parameters('vTpmEnabled')]" - }, - "encryptionAtHost": { - "value": "[parameters('diskZeroTrust')]" - }, - "storageManagedIdentityResourceId": "[if(and(variables('varCreateStorageDeployment'), not(equals(parameters('avdIdentityServiceProvider'), 'EntraID'))), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time'))), '2022-09-01').outputs.managedIdentityStorageResourceId.value), createObject('value', ''))]", - "applicationSecurityGroupResourceId": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', format('{0}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.applicationSecurityGroupResourceId.value)), createObject('value', ''))]", - "createAppAttachDeployment": { - "value": "[parameters('createAppAttachDeployment')]" - }, - "fslogixFileShareCustomName": { - "value": "[parameters('fslogixFileShareCustomName')]" - }, - "appAttachFileShareCustomName": { - "value": "[parameters('appAttachFileShareCustomName')]" - }, - "storageAccountPrefixCustomName": { - "value": "[parameters('storageAccountPrefixCustomName')]" - }, - "anfAccountCustomName": { - "value": "[parameters('anfAccountCustomName')]" - }, - "managedIdentityClientId": "[if(and(variables('varCreateStorageDeployment'), not(equals(parameters('avdIdentityServiceProvider'), 'EntraID'))), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time'))), '2022-09-01').outputs.managedIdentityStorageClientId.value), createObject('value', ''))]", - "privateDnsZoneFilesResourceId": "[if(parameters('createPrivateDnsZones'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.azureFilesDnsZoneResourceId.value), createObject('value', parameters('avdVnetPrivateDnsZoneFilesId')))]", - "serviceObjectsRgName": { - "value": "[variables('varServiceObjectsRgName')]" - }, - "alaWorkspaceResourceId": "[if(parameters('avdDeployMonitoring'), if(parameters('deployAlaWorkspace'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.avdAlaWorkspaceResourceId.value), createObject('value', parameters('alaExistingWorkspaceResourceId'))), createObject('value', ''))]", - "deploymentEnvironmentOneCharacter": { - "value": "[variables('varDeploymentEnvironmentOneCharacter')]" - }, - "computeStorageResourcesNamingStandard": { - "value": "[variables('varComputeStorageResourcesNamingStandard')]" - }, - "fslogixFileShareQuotaSize": { - "value": "[parameters('fslogixFileShareQuotaSize')]" - }, - "appAttachFileShareQuotaSize": { - "value": "[parameters('appAttachFileShareQuotaSize')]" - }, - "fslogixStoragePerformance": { - "value": "[parameters('fslogixStoragePerformance')]" - }, - "appAttachStoragePerformance": { - "value": "[parameters('appAttachStoragePerformance')]" - }, - "anfSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAnfSubnetName'))), createObject('value', parameters('existingVnetAnfSubnetResourceId')))]", - "vmsSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", - "privateEndpointSubnetResourceId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetPrivateEndpointSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", - "location": "[if(parameters('avdDeploySessionHosts'), createObject('value', parameters('avdSessionHostLocation')), createObject('value', parameters('avdManagementPlaneLocation')))]", - "locationAcronym": "[if(parameters('avdDeploySessionHosts'), createObject('value', variables('varSessionHostLocationAcronym')), createObject('value', parameters('avdManagementPlaneLocation')))]", - "managementVmOsImage": { - "value": "[parameters('managementVmOsImage')]" - }, - "keyVaultResourceId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" - }, - "customResourceTags": { - "value": "[variables('varCustomResourceTags')]" - }, - "defaultTags": { - "value": "[variables('varAvdDefaultTags')]" - }, - "identityDomainGuid": { - "value": "[parameters('identityDomainGuid')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "17332805804383803852" - } - }, - "parameters": { - "subId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "The subscription ID for the AVD workload." - } - }, - "deploymentPrefix": { - "type": "string", - "metadata": { - "description": "The deployment prefix in lowercase." - } - }, - "deploymentEnvironment": { - "type": "string", - "metadata": { - "description": "The deployment environment in lowercase." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "The session host location acronym derived from the resource group location." - } - }, - "locationAcronym": { - "type": "string", - "metadata": { - "description": "The session host or AVD management plane location acronym For example, \"eus\" for East US." - } - }, - "storageService": { - "type": "string", - "metadata": { - "description": "The storage service to use (AzureFiles or ANF)." - } - }, - "useCustomNaming": { - "type": "bool", - "metadata": { - "description": "Indicates whether to use custom naming for AVD." - } - }, - "computeStorageResourcesNamingStandard": { - "type": "string", - "metadata": { - "description": "The naming standard for compute storage resources coming from the main template." - } - }, - "fslogixFileShareCustomName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The custom name for the FSLogix file share." - } - }, - "appAttachFileShareCustomName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The custom name for the App Attach file share." - } - }, - "managementVmOsImage": { - "type": "string", - "metadata": { - "description": "The OS image for the management VM." - } - }, - "storageAccountPrefixCustomName": { - "type": "string", - "defaultValue": "st", - "metadata": { - "description": "AVD FSLogix and App Attach storage account prefix custom name." - } - }, - "anfAccountCustomName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The custom name for the ANF account." - } - }, - "deploymentEnvironmentOneCharacter": { - "type": "string", - "metadata": { - "description": "Deployment prefix one character." - } - }, - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Key Vault." - } - }, - "alaWorkspaceResourceId": { - "type": "string", - "metadata": { - "description": "The Azure Log Analytics workspace resource ID." - } - }, - "privateDnsZoneFilesResourceId": { - "type": "string", - "metadata": { - "description": "The private DNS zone files resource ID." - } - }, - "managedIdentityClientId": { - "type": "string", - "metadata": { - "description": "The client ID of the managed identity." - } - }, - "fslogixFileShareQuotaSize": { - "type": "int", - "metadata": { - "description": "The FSLogix file share quota size in GiBs." - } - }, - "appAttachFileShareQuotaSize": { - "type": "int", - "metadata": { - "description": "The App Attach file share quota size in GiBs." - } - }, - "fslogixStoragePerformance": { - "type": "string", - "metadata": { - "description": "The storage performance level for FSLogix." - } - }, - "appAttachStoragePerformance": { - "type": "string", - "metadata": { - "description": "The storage performance level for App Attach." - } - }, - "anfSubnetResourceId": { - "type": "string", - "metadata": { - "description": "Subnet resource ID for ANF volumes." - } - }, - "vmsSubnetResourceId": { - "type": "string", - "metadata": { - "description": "Subnet resource ID for VMs." - } - }, - "securityType": { - "type": "string", - "metadata": { - "description": "The security type for the VM (e.g., TrustedLaunch, Standard)." - } - }, - "privateEndpointSubnetResourceId": { - "type": "string", - "metadata": { - "description": "Subnet resource ID for private endpoints." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the disk encryption set." - } - }, - "encryptionAtHost": { - "type": "bool", - "metadata": { - "description": "Indicates whether encryption at host is enabled for the VM." - } - }, - "storageManagedIdentityResourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the managed identity for storage." - } - }, - "secureBootEnabled": { - "type": "bool", - "metadata": { - "description": "Indicates whether secure boot is enabled for the VM." - } - }, - "vTpmEnabled": { - "type": "bool", - "metadata": { - "description": "Indicates whether vTPM is enabled for the VM." - } - }, - "sessionHostTimeZone": { - "type": "string", - "metadata": { - "description": "The time zone for the session host." - } - }, - "applicationSecurityGroupResourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the application security group." - } - }, - "storageAvailabilityZones": { - "type": "bool", - "metadata": { - "description": "USe or not zone redundant storage." - } - }, - "dnsServers": { - "type": "string", - "metadata": { - "description": "The custom DNS IPs." - } - }, - "identityServiceProvider": { - "type": "string", - "metadata": { - "description": "The identity service provider (e.g., EntraDS)." - } - }, - "domainJoinUserName": { - "type": "string", - "metadata": { - "description": "The domain join username." - } - }, - "vmLocalUserName": { - "type": "string", - "metadata": { - "description": "The VM local username." - } - }, - "serviceObjectsRgName": { - "type": "string", - "metadata": { - "description": "The service objects resource group name." - } - }, - "storageObjectsRgName": { - "type": "string", - "metadata": { - "description": "The storage objects resource group name." - } - }, - "managementVmSize": { - "type": "string", - "metadata": { - "description": "The VM size for the management VM." - } - }, - "avdSessionHostsOuPath": { - "type": "string", - "metadata": { - "description": "The OU path for AVD session hosts." - } - }, - "storageOuPath": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The storage OU path." - } - }, - "customResourceTags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "The custom resource tags." - } - }, - "defaultTags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "The AVD default tags." - } - }, - "createResourceTags": { - "type": "bool", - "metadata": { - "description": "Indicates whether to create resource tags." - } - }, - "baseScriptUri": { - "type": "string", - "metadata": { - "description": "The base script URI." - } - }, - "securityPrincipalName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The security principal name." - } - }, - "identityDomainName": { - "type": "string", - "metadata": { - "description": "The identity domain name." - } - }, - "identityDomainGuid": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The identity domain GUID." - } - }, - "deployPrivateEndpointKeyvaultStorage": { - "type": "bool", - "metadata": { - "description": "Indicates whether to deploy private endpoints for Key Vault and storage." - } - }, - "createFslogixDeployment": { - "type": "bool", - "metadata": { - "description": "Indicates whether to create FSLogix deployment." - } - }, - "createAppAttachDeployment": { - "type": "bool", - "metadata": { - "description": "Indicates whether to create App Attach deployment." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "The deployment timestamp." - } - } - }, - "variables": { - "$fxv#0": { - "win10_22h2_g2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "windows-10", - "sku": "win10-22h2-avd-g2", - "version": "latest" - }, - "win10_22h2_office_g2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "office-365", - "sku": "win10-22h2-avd-m365-g2", - "version": "latest" - }, - "win11_22h2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "Windows-11", - "sku": "win11-22h2-avd", - "version": "latest" - }, - "win11_22h2_office": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "office-365", - "sku": "win11-22h2-avd-m365", - "version": "latest" - }, - "win11_23h2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "Windows-11", - "sku": "win11-23h2-avd", - "version": "latest" - }, - "win11_23h2_office": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "office-365", - "sku": "win11-23h2-avd-m365", - "version": "latest" - }, - "win11_24h2": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "Windows-11", - "sku": "win11-24h2-avd", - "version": "latest" - }, - "win11_24h2_office": { - "publisher": "MicrosoftWindowsDesktop", - "offer": "office-365", - "sku": "win11-24h2-avd-m365", - "version": "latest" - }, - "winServer_2022_Datacenter": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "2022-datacenter-g2", - "version": "latest" - }, - "winServer_2022_Datacenter_smalldisk_g2": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "2022-datacenter-smalldisk-g2", - "version": "latest" - }, - "winServer_2022_datacenter_core": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "2022-datacenter-core-g2", - "version": "latest" - }, - "winServer_2022_Datacenter_core_smalldisk_g2": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "2022-datacenter-core-smalldisk-g2", - "version": "latest" - } - }, - "varNamingUniqueStringThreeChar": "[take(format('{0}', uniqueString(parameters('subId'), parameters('deploymentPrefix'), parameters('time'))), 3)]", - "varAnfCapacityPoolSize": "[if(greater(add(if(parameters('createFslogixDeployment'), parameters('fslogixFileShareQuotaSize'), 0), if(parameters('createAppAttachDeployment'), parameters('appAttachFileShareQuotaSize'), 0)), 4096), add(if(parameters('createFslogixDeployment'), parameters('fslogixFileShareQuotaSize'), 0), if(parameters('createAppAttachDeployment'), parameters('appAttachFileShareQuotaSize'), 0)), 4096)]", - "varFslogixFileShareName": "[if(equals(parameters('storageService'), 'AzureFiles'), if(parameters('useCustomNaming'), parameters('fslogixFileShareCustomName'), format('fslogix-pc-{0}-{1}-{2}-001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('locationAcronym'))), if(equals(parameters('storageService'), 'ANF'), format('fsl{0}{1}{2}001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('locationAcronym')), ''))]", - "varAnfSmbServerNamePrefix": "[format('anf{0}{1}', parameters('deploymentPrefix'), parameters('deploymentEnvironment'))]", - "varAppAttachFileShareName": "[if(equals(parameters('storageService'), 'AzureFiles'), if(parameters('useCustomNaming'), parameters('appAttachFileShareCustomName'), format('appa-{0}-{1}-{2}-001', parameters('deploymentPrefix'), parameters('deploymentEnvironment'), parameters('locationAcronym'))), if(equals(parameters('storageService'), 'ANF'), format('appa{0}01', parameters('deploymentPrefix')), ''))]", - "varFslogixAnfVolume": "[if(parameters('createFslogixDeployment'), createArray(createObject('name', variables('varFslogixFileShareName'), 'coolAccess', false(), 'encryptionKeySource', 'Microsoft.NetApp', 'zones', createArray(), 'serviceLevel', parameters('fslogixStoragePerformance'), 'networkFeatures', 'Standard', 'usageThreshold', mul(parameters('fslogixFileShareQuotaSize'), 1073741824), 'protocolTypes', createArray('CIFS'), 'subnetResourceId', parameters('anfSubnetResourceId'), 'creationToken', variables('varFslogixFileShareName'), 'smbContinuouslyAvailable', true(), 'securityStyle', 'ntfs')), createArray())]", - "varAppAttchAnfVolume": "[if(parameters('createAppAttachDeployment'), createArray(createObject('name', variables('varAppAttachFileShareName'), 'coolAccess', false(), 'encryptionKeySource', 'Microsoft.NetApp', 'zones', createArray(), 'serviceLevel', parameters('appAttachStoragePerformance'), 'networkFeatures', 'Standard', 'usageThreshold', mul(parameters('appAttachFileShareQuotaSize'), 1073741824), 'protocolTypes', createArray('CIFS'), 'subnetResourceId', parameters('anfSubnetResourceId'), 'creationToken', variables('varAppAttachFileShareName'), 'smbContinuouslyAvailable', true(), 'securityStyle', 'ntfs')), createArray())]", - "varAnfVolumes": "[union(variables('varFslogixAnfVolume'), variables('varAppAttchAnfVolume'))]", - "varFslogixStorageName": "[if(parameters('useCustomNaming'), format('{0}fsl{1}{2}{3}', parameters('storageAccountPrefixCustomName'), parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')), format('stfsl{0}{1}{2}', parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')))]", - "varAnfAccountName": "[if(parameters('useCustomNaming'), parameters('anfAccountCustomName'), format('anf-acc-{0}-001', parameters('computeStorageResourcesNamingStandard')))]", - "varAnfCapacityPoolName": "[format('anf-cpool-{0}-001', parameters('computeStorageResourcesNamingStandard'))]", - "varFslogixStorageFqdn": "[if(parameters('createFslogixDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('{0}.file.{1}', variables('varFslogixStorageName'), environment().suffixes.storage), if(equals(parameters('storageService'), 'ANF'), format('{0}...{1}.netapp.azure.com', variables('varFslogixFileShareName'), parameters('location')), '')), '')]", - "varAppAttachStorageFqdn": "[if(parameters('createAppAttachDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('{0}.file.{1}', variables('varAppAttachStorageName'), environment().suffixes.storage), if(equals(parameters('storageService'), 'ANF'), format('{0}...{1}.netapp.azure.com', variables('varAppAttachFileShareName'), parameters('location')), '')), '')]", - "varAppAttachStorageName": "[if(parameters('useCustomNaming'), format('{0}appa{1}{2}{3}', parameters('storageAccountPrefixCustomName'), parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')), format('stappa{0}{1}{2}', parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), variables('varNamingUniqueStringThreeChar')))]", - "varManagementVmName": "[format('vmmgmt{0}{1}{2}', parameters('deploymentPrefix'), parameters('deploymentEnvironmentOneCharacter'), parameters('locationAcronym'))]", - "varFslogixStoragePerformance": "[if(equals(parameters('fslogixStoragePerformance'), 'Ultra'), 'Premium', parameters('fslogixStoragePerformance'))]", - "varAppAttachStoragePerformance": "[if(equals(parameters('appAttachStoragePerformance'), 'Ultra'), 'Premium', parameters('appAttachStoragePerformance'))]", - "varFslogixStorageSku": "[if(and(parameters('storageAvailabilityZones'), equals(parameters('storageService'), 'AzureFiles')), format('{0}_ZRS', variables('varFslogixStoragePerformance')), format('{0}_LRS', variables('varFslogixStoragePerformance')))]", - "varAppAttachStorageSku": "[if(parameters('storageAvailabilityZones'), format('{0}_ZRS', variables('varAppAttachStoragePerformance')), format('{0}_LRS', variables('varAppAttachStoragePerformance')))]", - "varStorageAzureFilesDscAgentPackageLocation": "https://github.com/Azure/avdaccelerator/raw/main/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip", - "varStorageToDomainScriptUri": "[format('{0}scripts/Manual-DSC-Storage-Scripts.ps1', parameters('baseScriptUri'))]", - "varStorageToDomainScript": "./Manual-DSC-Storage-Scripts.ps1", - "varOuStgPath": "[if(not(empty(parameters('storageOuPath'))), format('\"{0}\"', parameters('storageOuPath')), format('\"{0}\"', variables('varDefaultStorageOuPath')))]", - "varDefaultStorageOuPath": "[if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDC Computers', 'Computers')]", - "varStorageCustomOuPath": "[if(not(empty(parameters('storageOuPath'))), 'true', 'false')]", - "varMarketPlaceGalleryWindows": "[variables('$fxv#0')]" - }, - "resources": [ - { - "condition": "[and(not(equals(parameters('identityServiceProvider'), 'EntraID')), or(parameters('createFslogixDeployment'), parameters('createAppAttachDeployment')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-MGMT-VM-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "diskEncryptionSetResourceId": { - "value": "[parameters('diskEncryptionSetResourceId')]" - }, - "identityServiceProvider": { - "value": "[parameters('identityServiceProvider')]" - }, - "vmName": { - "value": "[variables('varManagementVmName')]" - }, - "computeTimeZone": { - "value": "[parameters('sessionHostTimeZone')]" - }, - "applicationSecurityGroupResourceId": { - "value": "[parameters('applicationSecurityGroupResourceId')]" - }, - "domainJoinUserName": { - "value": "[parameters('domainJoinUserName')]" - }, - "keyVaultResourceId": { - "value": "[parameters('keyVaultResourceId')]" - }, - "serviceObjectsRgName": { - "value": "[parameters('serviceObjectsRgName')]" - }, - "identityDomainName": { - "value": "[parameters('identityDomainName')]" - }, - "ouPath": { - "value": "[parameters('avdSessionHostsOuPath')]" - }, - "osDiskType": { - "value": "Standard_LRS" - }, - "location": { - "value": "[parameters('location')]" - }, - "vmSize": { - "value": "[parameters('managementVmSize')]" - }, - "subnetResourceId": { - "value": "[parameters('vmsSubnetResourceId')]" - }, - "enableAcceleratedNetworking": { - "value": true - }, - "securityType": { - "value": "[parameters('securityType')]" - }, - "secureBootEnabled": { - "value": "[parameters('secureBootEnabled')]" - }, - "vTpmEnabled": { - "value": "[parameters('vTpmEnabled')]" - }, - "vmLocalUserName": { - "value": "[parameters('vmLocalUserName')]" - }, - "subId": { - "value": "[parameters('subId')]" - }, - "encryptionAtHost": { - "value": "[parameters('encryptionAtHost')]" - }, - "storageManagedIdentityResourceId": { - "value": "[parameters('storageManagedIdentityResourceId')]" - }, - "osImage": { - "value": "[variables('varMarketPlaceGalleryWindows')[parameters('managementVmOsImage')]]" - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "8670712661433034722" - }, - "name": "AVD LZA storage management VM", - "description": "This module deploys a management VM to join Azure Files to domain and for tools.", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "diskEncryptionSetResourceId": { - "type": "string", - "metadata": { - "description": "AVD disk encryption set resource ID to enable server side encyption." - } - }, - "subId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "computeTimeZone": { - "type": "string", - "metadata": { - "description": "Virtual machine time zone." - } - }, - "identityServiceProvider": { - "type": "string", - "metadata": { - "description": "Required, The service providing domain services for Azure Virtual Desktop." - } - }, - "serviceObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group Name for Azure Files." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Subnet resource ID." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "metadata": { - "description": "Enable accelerated networking on the session host VMs." - } - }, - "securityType": { - "type": "string", - "metadata": { - "description": "Specifies the securityType of the virtual machine. Must be TrustedLaunch or ConfidentialVM enable UefiSettings." - } - }, - "secureBootEnabled": { - "type": "bool", - "metadata": { - "description": "Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "vTpmEnabled": { - "type": "bool", - "metadata": { - "description": "Specifies whether virtual TPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy compute services." - } - }, - "encryptionAtHost": { - "type": "bool", - "metadata": { - "description": "This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "Session host VM size." - } - }, - "osDiskType": { - "type": "string", - "metadata": { - "description": "OS disk type for session host." - } - }, - "osImage": { - "type": "object", - "metadata": { - "description": "Market Place OS image" - } - }, - "storageManagedIdentityResourceId": { - "type": "string", - "metadata": { - "description": "Storage Managed Identity Resource ID." - } - }, - "vmLocalUserName": { - "type": "string", - "metadata": { - "description": "Local administrator username." - } - }, - "identityDomainName": { - "type": "string", - "metadata": { - "description": "Identity domain name." - } - }, - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Keyvault resource ID to get credentials from." - } - }, - "domainJoinUserName": { - "type": "string", - "metadata": { - "description": "AVD session host domain join credentials." - } - }, - "ouPath": { - "type": "string", - "metadata": { - "description": "OU path to join AVd VMs." - } - }, - "applicationSecurityGroupResourceId": { - "type": "string", - "metadata": { - "description": "Application Security Group (ASG) for the session hosts." - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "vmName": { - "type": "string", - "metadata": { - "description": "Name for management virtual machine. for tools and to join Azure Files to domain." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - } - }, - "variables": { - "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", - "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", - "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]", - "varManagedDisk": "[if(empty(parameters('diskEncryptionSetResourceId')), createObject('storageAccountType', parameters('osDiskType')), createObject('diskEncryptionSet', createObject('id', parameters('diskEncryptionSetResourceId')), 'storageAccountType', parameters('osDiskType')))]" - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('MGMT-VM-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('vmName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "timeZone": { - "value": "[parameters('computeTimeZone')]" - }, - "managedIdentities": { - "value": { - "systemAssigned": false, - "userAssignedResourceIds": [ - "[parameters('storageManagedIdentityResourceId')]" - ] - } - }, - "encryptionAtHost": { - "value": "[parameters('encryptionAtHost')]" - }, - "zone": { - "value": 0 - }, - "osType": { - "value": "Windows" - }, - "vmSize": { - "value": "[parameters('vmSize')]" - }, - "securityType": { - "value": "[parameters('securityType')]" - }, - "secureBootEnabled": { - "value": "[parameters('secureBootEnabled')]" - }, - "vTpmEnabled": { - "value": "[parameters('vTpmEnabled')]" - }, - "imageReference": { - "value": "[parameters('osImage')]" - }, - "osDisk": { - "value": { - "createOption": "FromImage", - "deleteOption": "Delete", - "caching": "ReadWrite", - "managedDisk": "[variables('varManagedDisk')]" - } - }, - "adminUsername": { - "value": "[parameters('vmLocalUserName')]" - }, - "adminPassword": { - "reference": { - "keyVault": { - "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))]" - }, - "secretName": "vmLocalUserPassword" - } - }, - "nicConfigurations": { - "value": [ - { - "name": "[format('nic-01-{0}', parameters('vmName'))]", - "deleteOption": "Delete", - "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", - "ipConfigurations": "[if(not(empty(parameters('applicationSecurityGroupResourceId'))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetResourceId'), 'applicationSecurityGroups', createArray(createObject('id', parameters('applicationSecurityGroupResourceId'))))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetResourceId'))))]" - } - ] - }, - "allowExtensionOperations": { - "value": true - }, - "extensionDomainJoinPassword": { - "reference": { - "keyVault": { - "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))]" - }, - "secretName": "domainJoinUserPassword" - } - }, - "extensionDomainJoinConfig": { - "value": { - "enabled": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), false(), true())]", - "settings": { - "name": "[parameters('identityDomainName')]", - "ouPath": "[if(not(empty(parameters('ouPath'))), parameters('ouPath'), null())]", - "user": "[parameters('domainJoinUserName')]", - "restart": "true", - "options": "3" - } - } - }, - "extensionAadJoinConfig": { - "value": { - "enabled": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), true(), false())]" - } - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13031055217657209142" - }, - "name": "Virtual Machines", - "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "managedIdentitiesType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } - } - }, - "nullable": true - }, - "osDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "metadata": { - "description": "Required. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } - } - }, - "dataDisksType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "lun": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the logical unit number of the data disk." - } - }, - "diskSizeGB": { - "type": "int", - "maxValue": 1023, - "metadata": { - "description": "Required. Specifies the size of an empty data disk in gigabytes." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "metadata": { - "description": "Required. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." - } - }, - "computerName": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "Required. Specifies the size for the VMs." - } - }, - "encryptionAtHost": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "securityType": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the SecurityType of the virtual machine. It is set as TrustedLaunch to enable UefiSettings." - } - }, - "secureBootEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "vTpmEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "imageReference": { - "type": "object", - "metadata": { - "description": "Required. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image." - } - }, - "plan": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." - } - }, - "osDisk": { - "$ref": "#/definitions/osDiskType", - "metadata": { - "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "dataDisks": { - "$ref": "#/definitions/dataDisksType", - "metadata": { - "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "ultraSSDEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." - } - }, - "adminUsername": { - "type": "securestring", - "metadata": { - "description": "Required. Administrator username." - } - }, - "adminPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. When specifying a Windows Virtual Machine, this value should be passed." - } - }, - "customData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." - } - }, - "certificatesToBeInstalled": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." - } - }, - "priority": { - "type": "string", - "defaultValue": "Regular", - "allowedValues": [ - "Regular", - "Low", - "Spot" - ], - "metadata": { - "description": "Optional. Specifies the priority for the virtual machine." - } - }, - "enableEvictionPolicy": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy." - } - }, - "maxPriceForLowPriorityVm": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." - } - }, - "dedicatedHostId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." - } - }, - "licenseType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "RHEL_BYOS", - "SLES_BYOS", - "Windows_Client", - "Windows_Server", - "" - ], - "metadata": { - "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", - "metadata": { - "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." - } - }, - "bootDiagnostics": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." - } - }, - "bootDiagnosticStorageAccountName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." - } - }, - "bootDiagnosticStorageAccountUri": { - "type": "string", - "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", - "metadata": { - "description": "Optional. Storage account boot diagnostic base URI." - } - }, - "proximityPlacementGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a proximity placement group." - } - }, - "virtualMachineScaleSetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." - } - }, - "availabilitySetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." - } - }, - "zone": { - "type": "int", - "allowedValues": [ - 0, - 1, - 2, - 3 - ], - "metadata": { - "description": "Required. If set to 1, 2 or 3, the availability zone for all VMs is hardcoded to that value. If zero, then availability zones is not used. Cannot be used in combination with availability set nor scale set." - } - }, - "nicConfigurations": { - "type": "array", - "metadata": { - "description": "Required. Configures NICs and PIPs." - } - }, - "allowExtensionOperations": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." - } - }, - "extensionDomainJoinPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if name is specified. Password of the user specified in user parameter." - } - }, - "extensionDomainJoinConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAadJoinConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." - } - }, - "extensionAzureDiskEncryptionConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." - } - }, - "extensionDSCConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionCustomScriptConfig": { - "type": "object", - "defaultValue": { - "enabled": false, - "fileData": [] - }, - "metadata": { - "description": "Optional. The configuration for the [Custom Script] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionNvidiaGpuDriverWindows": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionCustomScriptProtectedSetting": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. An object that contains the extension specific protected settings." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "baseTime": { - "type": "string", - "defaultValue": "[utcNow('u')]", - "metadata": { - "description": "Generated. Do not provide a value! This date value is used to generate a registration token." - } - }, - "sasTokenValidityLength": { - "type": "string", - "defaultValue": "PT8H", - "metadata": { - "description": "Optional. SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." - } - }, - "osType": { - "type": "string", - "allowedValues": [ - "Windows", - "Linux" - ], - "metadata": { - "description": "Required. The chosen OS type." - } - }, - "provisionVMAgent": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." - } - }, - "enableAutomaticUpdates": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." - } - }, - "patchMode": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "AutomaticByPlatform", - "AutomaticByOS", - "Manual", - "ImageDefault", - "" - ], - "metadata": { - "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." - } - }, - "bypassPlatformSafetyChecksOnUserSchedule": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enables customer to schedule patching without accidental upgrades." - } - }, - "rebootSetting": { - "type": "string", - "defaultValue": "IfRequired", - "allowedValues": [ - "Always", - "IfRequired", - "Never", - "Unknown" - ], - "metadata": { - "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." - } - }, - "patchAssessmentMode": { - "type": "string", - "defaultValue": "ImageDefault", - "allowedValues": [ - "AutomaticByPlatform", - "ImageDefault" - ], - "metadata": { - "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." - } - }, - "timeZone": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." - } - }, - "additionalUnattendContent": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." - } - }, - "winRM": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object." - } - }, - "configurationProfile": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." - } - } - }, - "variables": { - "windowsConfiguration": { - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting'))), null())]", - "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", - "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), parameters('additionalUnattendContent'))]", - "winRM": "[if(not(empty(parameters('winRM'))), createObject('listeners', parameters('winRM')), null())]" - }, - "accountSasProperties": { - "signedServices": "b", - "signedPermission": "r", - "signedExpiry": "[dateTimeAdd(parameters('baseTime'), parameters('sasTokenValidityLength'))]", - "signedResourceTypes": "o", - "signedProtocol": "https" - }, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "vm": { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2023-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "zones": "[if(not(equals(parameters('zone'), 0)), array(string(parameters('zone'))), null())]", - "plan": "[if(not(empty(parameters('plan'))), parameters('plan'), null())]", - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "securityProfile": { - "encryptionAtHost": "[if(parameters('encryptionAtHost'), parameters('encryptionAtHost'), null())]", - "securityType": "[parameters('securityType')]", - "uefiSettings": "[if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null())]" - }, - "storageProfile": { - "copy": [ - { - "name": "dataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", - "input": { - "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", - "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))]", - "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createoption'), 'Empty')]", - "deleteOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete')]", - "caching": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly')]", - "managedDisk": { - "storageAccountType": "[coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.storageAccountType]", - "diskEncryptionSet": "[coalesce(tryGet(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'managedDisk'), 'diskEncryptionSet'), null())]" - } - } - } - ], - "imageReference": "[parameters('imageReference')]", - "osDisk": { - "name": "[coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name')))]", - "createOption": "[coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage')]", - "deleteOption": "[coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete')]", - "caching": "[coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly')]", - "managedDisk": { - "storageAccountType": "[parameters('osDisk').managedDisk.storageAccountType]", - "diskEncryptionSet": { - "id": "[tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')]" - } - } - } - }, - "additionalCapabilities": { - "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]" - }, - "osProfile": { - "computerName": "[parameters('computerName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]", - "customData": "[if(not(empty(parameters('customData'))), base64(parameters('customData')), null())]", - "windowsConfiguration": "[if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null())]", - "secrets": "[parameters('certificatesToBeInstalled')]", - "allowExtensionOperations": "[parameters('allowExtensionOperations')]" - }, - "networkProfile": { - "copy": [ - { - "name": "networkInterfaces", - "count": "[length(parameters('nicConfigurations'))]", - "input": { - "properties": { - "deleteOption": "[if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].deleteOption, 'Delete')]", - "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" - }, - "id": "[resourceId('Microsoft.Network/networkInterfaces', if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].name, format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].nicSuffix)))]" - } - } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", - "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" - } - }, - "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", - "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", - "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", - "priority": "[parameters('priority')]", - "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", - "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", - "host": "[if(not(empty(parameters('dedicatedHostId'))), createObject('id', parameters('dedicatedHostId')), null())]", - "licenseType": "[if(not(empty(parameters('licenseType'))), parameters('licenseType'), null())]" - }, - "dependsOn": [ - "vm_nic" - ] - }, - "vm_configurationProfileAssignment": { - "condition": "[not(empty(parameters('configurationProfile')))]", - "type": "Microsoft.Automanage/configurationProfileAssignments", - "apiVersion": "2022-05-04", - "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", - "name": "default", - "properties": { - "configurationProfile": "[parameters('configurationProfile')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_nic": { - "copy": { - "name": "vm_nic", - "count": "[length(parameters('nicConfigurations'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "networkInterfaceName": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'name'), createObject('value', parameters('nicConfigurations')[copyIndex()].name), createObject('value', format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex()].nicSuffix)))]", - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableIPForwarding": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableIPForwarding), createObject('value', false()))]", - "enableAcceleratedNetworking": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableAcceleratedNetworking), createObject('value', true()))]", - "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(parameters('nicConfigurations')[copyIndex()].dnsServers)), createObject('value', parameters('nicConfigurations')[copyIndex()].dnsServers), createObject('value', createArray())), createObject('value', createArray()))]", - "networkSecurityGroupResourceId": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('nicConfigurations')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", - "ipConfigurations": { - "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" - }, - "roleAssignments": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4081873631846149092" - } - }, - "definitions": { - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "networkInterfaceName": { - "type": "string" - }, - "virtualMachineName": { - "type": "string" - }, - "ipConfigurations": { - "type": "array" - }, - "location": { - "type": "string", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false - }, - "dnsServers": { - "type": "array", - "defaultValue": [] - }, - "enableTelemetry": { - "type": "bool", - "metadata": { - "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the Network Interface." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "resources": { - "networkInterface_publicIPAddresses": { - "copy": { - "name": "networkInterface_publicIPAddresses", - "count": "[length(parameters('ipConfigurations'))]" - }, - "condition": "[contains(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIpNameSuffix)]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "idleTimeoutInMinutes": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'idleTimeoutInMinutes')]" - }, - "ddosSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'ddosSettings')]" - }, - "dnsSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'dnsSettings')]" - }, - "publicIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressVersion'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAddressVersion), createObject('value', 'IPv4'))]", - "publicIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAllocationMethod'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAllocationMethod), createObject('value', 'Static'))]", - "publicIpPrefixResourceId": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPPrefixResourceId'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPPrefixResourceId), createObject('value', ''))]", - "roleAssignments": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'roleAssignments'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.roleAssignments), createObject('value', createArray()))]", - "skuName": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuName'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuName), createObject('value', 'Standard'))]", - "skuTier": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuTier'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuTier), createObject('value', 'Regional'))]", - "tags": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "zones": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.zones), createObject('value', createArray(1, 2, 3)))]", - "enableTelemetry": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "4718335757080871925" - }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "", - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "metadata": { - "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "metadata": { - "description": "Required. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - } - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "defaultValue": "Static", - "allowedValues": [ - "Dynamic", - "Static" - ], - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "zones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } - }, - "publicIPAddressVersion": { - "type": "string", - "defaultValue": "IPv4", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "metadata": { - "description": "Optional. IP address version." - } - }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Basic", - "Standard" - ], - "metadata": { - "description": "Optional. Name of a public IP address SKU." - } - }, - "skuTier": { - "type": "string", - "defaultValue": "Regional", - "allowedValues": [ - "Global", - "Regional" - ], - "metadata": { - "description": "Optional. Tier of a public IP address SKU." - } - }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "defaultValue": 4, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2023-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" - }, - "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", - "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": null - } - }, - "publicIpAddress_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_roleAssignments": { - "copy": { - "name": "publicIpAddress_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_diagnosticSettings": { - "copy": { - "name": "publicIpAddress_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the public IP address was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the public IP address." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the public IP address." - }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "ipAddress": { - "type": "string", - "metadata": { - "description": "The public IP address of the public IP address resource." - }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-NetworkInterface', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('networkInterfaceName')]" - }, - "ipConfigurations": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('ipConfigurations'))]", - "input": "[createObject('name', if(not(empty(parameters('ipConfigurations')[copyIndex('value')].name)), parameters('ipConfigurations')[copyIndex('value')].name, null()), 'primary', equals(copyIndex('value'), 0), 'privateIPAllocationMethod', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod, null()), null()), 'privateIPAddress', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('value')].privateIPAddress, null()), null()), 'publicIPAddressResourceId', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), resourceId('Microsoft.Network/publicIPAddresses', format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.publicIpNameSuffix)), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerBackendAddressPools, null()), 'applicationSecurityGroups', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('value')].applicationSecurityGroups, null()), 'applicationGatewayBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].applicationGatewayBackendAddressPools, null()), 'gatewayLoadBalancer', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('value')].gatewayLoadBalancer, null()), 'loadBalancerInboundNatRules', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerInboundNatRules, null()), 'privateIPAddressVersion', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('value')].privateIPAddressVersion, null()), 'virtualNetworkTaps', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('value')].virtualNetworkTaps, null()))]" - } - ] - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "dnsServers": "[if(not(empty(parameters('dnsServers'))), createObject('value', parameters('dnsServers')), createObject('value', createArray()))]", - "enableAcceleratedNetworking": { - "value": "[parameters('enableAcceleratedNetworking')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enableIPForwarding": { - "value": "[parameters('enableIPForwarding')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", - "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "1612343535299711142" - }, - "name": "Network Interface", - "description": "This module deploys a Network Interface.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the network interface." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If the network interface is accelerated networking enabled." - } - }, - "dnsServers": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "auxiliaryMode": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "Floating", - "MaxConnections", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "auxiliarySku": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "A1", - "A2", - "A4", - "A8", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "disableTcpStateTracking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "description": "Required. A list of IPConfigurations of the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.2.4', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "ipConfigurations", - "count": "[length(parameters('ipConfigurations'))]", - "input": { - "name": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].name, format('ipconfig0{0}', add(copyIndex('ipConfigurations'), 1)))]", - "properties": { - "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", - "privateIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod, null()), null())]", - "privateIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress, null()), null())]", - "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId, null())), createObject('id', parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId), null()), null())]", - "subnet": { - "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" - }, - "loadBalancerBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerBackendAddressPools, null())]", - "applicationSecurityGroups": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationSecurityGroups, null())]", - "applicationGatewayBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationGatewayBackendAddressPools, null())]", - "gatewayLoadBalancer": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].gatewayLoadBalancer, null())]", - "loadBalancerInboundNatRules": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerInboundNatRules, null())]", - "privateIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddressVersion, null())]", - "virtualNetworkTaps": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].virtualNetworkTaps, null())]" - } - } - } - ], - "auxiliaryMode": "[parameters('auxiliaryMode')]", - "auxiliarySku": "[parameters('auxiliarySku')]", - "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", - "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", - "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", - "enableIPForwarding": "[parameters('enableIPForwarding')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" - } - }, - "networkInterface_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_diagnosticSettings": { - "copy": { - "name": "networkInterface_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_roleAssignments": { - "copy": { - "name": "networkInterface_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "networkInterface" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed resource." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed resource." - }, - "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed resource." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkInterface', '2023-04-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "networkInterface_publicIPAddresses" - ] - } - } - } - } - }, - "vm_aadJoinExtension": { - "condition": "[parameters('extensionAadJoinConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "AADLogin" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.ActiveDirectory" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAadJoinConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.0'), createObject('value', '1.0')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAadJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAadJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": "[if(contains(parameters('extensionAadJoinConfig'), 'settings'), createObject('value', parameters('extensionAadJoinConfig').settings), createObject('value', createObject()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_domainJoinExtension": { - "condition": "[parameters('extensionDomainJoinConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "DomainJoin" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "JsonADDomainExtension" - }, - "typeHandlerVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDomainJoinConfig').typeHandlerVersion), createObject('value', '1.3'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDomainJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDomainJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": { - "value": "[parameters('extensionDomainJoinConfig').settings]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": { - "Password": "[parameters('extensionDomainJoinPassword')]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_aadJoinExtension" - ] - }, - "vm_desiredStateConfigurationExtension": { - "condition": "[parameters('extensionDSCConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "DesiredStateConfiguration" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Powershell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": "[if(contains(parameters('extensionDSCConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDSCConfig').typeHandlerVersion), createObject('value', '2.77'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDSCConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDSCConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": "[if(contains(parameters('extensionDSCConfig'), 'settings'), createObject('value', parameters('extensionDSCConfig').settings), createObject('value', createObject()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": "[if(contains(parameters('extensionDSCConfig'), 'protectedSettings'), createObject('value', parameters('extensionDSCConfig').protectedSettings), createObject('value', createObject()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_customScriptExtension": { - "condition": "[parameters('extensionCustomScriptConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "CustomScriptExtension" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionCustomScriptConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '1.10'), createObject('value', '2.1')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionCustomScriptConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionCustomScriptConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": { - "value": { - "copy": [ - { - "name": "fileUris", - "count": "[length(parameters('extensionCustomScriptConfig').fileData)]", - "input": "[if(contains(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')], 'storageAccountId'), format('{0}?{1}', parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri, listAccountSas(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].storageAccountId, '2019-04-01', variables('accountSasProperties')).accountSasToken), parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri)]" - } - ] - } - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": "[parameters('extensionCustomScriptProtectedSetting')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_desiredStateConfigurationExtension" - ] - }, - "vm_azureDiskEncryptionExtension": { - "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "AzureDiskEncryption" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.2'), createObject('value', '1.1')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "forceUpdateTag": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').forceUpdateTag), createObject('value', '1.0'))]", - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_nvidiaGpuDriverWindowsExtension": { - "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "NvidiaGpuDriverWindows" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.HpcCompute" - }, - "type": { - "value": "NvidiaGpuDriverWindows" - }, - "typeHandlerVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').typeHandlerVersion), createObject('value', '1.4'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').enableAutomaticUpgrade), createObject('value', false()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureDiskEncryptionExtension" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the VM." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the VM." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the VM was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[coalesce(tryGet(tryGet(reference('vm', '2023-09-01', 'full'), 'identity'), 'principalId'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('vm', '2023-09-01', 'full').location]" - } - } - } - } - } - ] - } - } - }, - { - "condition": "[and(equals(parameters('storageService'), 'ANF'), not(contains(parameters('identityServiceProvider'), 'EntraID')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-ANF-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "accountName": { - "value": "[variables('varAnfAccountName')]" - }, - "capacityPoolName": { - "value": "[variables('varAnfCapacityPoolName')]" - }, - "volumes": { - "value": "[variables('varAnfVolumes')]" - }, - "smbServerNamePrefix": { - "value": "[variables('varAnfSmbServerNamePrefix')]" - }, - "capacityPoolSize": { - "value": "[variables('varAnfCapacityPoolSize')]" - }, - "dnsServers": { - "value": "[parameters('dnsServers')]" - }, - "performance": { - "value": "[parameters('fslogixStoragePerformance')]" - }, - "createFslogixStorage": { - "value": "[parameters('createFslogixDeployment')]" - }, - "createAppAttachStorage": { - "value": "[parameters('createAppAttachDeployment')]" - }, - "storageOuPath": "[if(not(empty(parameters('storageOuPath'))), createObject('value', parameters('storageOuPath')), createObject('value', variables('varDefaultStorageOuPath')))]", - "domainJoinUserName": { - "value": "[parameters('domainJoinUserName')]" - }, - "keyVaultResourceId": { - "value": "[parameters('keyVaultResourceId')]" - }, - "identityDomainName": { - "value": "[parameters('identityDomainName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "storageObjectsRgName": { - "value": "[parameters('storageObjectsRgName')]" - }, - "subId": { - "value": "[parameters('subId')]" - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "6273873211710387488" - }, - "name": "AVD LZA storage", - "description": "This module deploys ANF account, capacity pool and volumes", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "subId": { - "type": "string", - "metadata": { - "description": "Workload subscription ID" - } - }, - "storageObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group Name where to deploy Azure NetApp Files." - } - }, - "accountName": { - "type": "string", - "metadata": { - "description": "ANF account name." - } - }, - "capacityPoolName": { - "type": "string", - "metadata": { - "description": "Capacity pool volume name." - } - }, - "createFslogixStorage": { - "type": "bool", - "metadata": { - "description": "Capacity pool volume name." - } - }, - "createAppAttachStorage": { - "type": "bool", - "metadata": { - "description": "Capacity pool volume name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "description": "ANF volumes." - } - }, - "smbServerNamePrefix": { - "type": "string", - "metadata": { - "description": "ANF SMB prefix." - } - }, - "dnsServers": { - "type": "string", - "metadata": { - "description": "DNS servers IPs." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy resources." - } - }, - "identityDomainName": { - "type": "string", - "metadata": { - "description": "Identity domain name." - } - }, - "storageOuPath": { - "type": "string", - "metadata": { - "description": "Organizational Unit (OU) storage path for domain join." - } - }, - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Keyvault resource ID to get credentials from." - } - }, - "domainJoinUserName": { - "type": "string", - "metadata": { - "description": "AVD session host domain join credentials." - } - }, - "performance": { - "type": "string", - "metadata": { - "description": "ANF performance tier." - } - }, - "capacityPoolSize": { - "type": "int", - "defaultValue": 4, - "metadata": { - "description": "ANF capacity pool size in TiBs." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - } - }, - "variables": { - "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", - "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", - "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]" - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-ANF-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subId'))]", - "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('accountName')]" - }, - "adName": { - "value": "[parameters('accountName')]" - }, - "domainName": { - "value": "[parameters('identityDomainName')]" - }, - "domainJoinUser": { - "value": "[parameters('domainJoinUserName')]" - }, - "domainJoinPassword": { - "reference": { - "keyVault": { - "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))]" - }, - "secretName": "domainJoinUserPassword" - } - }, - "domainJoinOU": { - "value": "[format('CN={0}', parameters('storageOuPath'))]" - }, - "dnsServers": { - "value": "[parameters('dnsServers')]" - }, - "smbServerNamePrefix": { - "value": "[parameters('smbServerNamePrefix')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "capacityPools": { - "value": [ - { - "name": "[parameters('capacityPoolName')]", - "serviceLevel": "[parameters('performance')]", - "size": "[mul(parameters('capacityPoolSize'), 1073741824)]", - "volumes": "[parameters('volumes')]" - } - ] - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "943345456492784680" - }, - "name": "Azure NetApp Files", - "description": "This module deploys an Azure NetApp File." - }, - "definitions": { - "backupVaultType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backup vault." - } - }, - "backups": { - "type": "array", - "items": { - "$ref": "#/definitions/backupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of backups to create." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the backup vault." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a backup vault." - } - }, - "capacityPoolType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the capacity pool." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the pool volume." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags for the capcity pool." - } - }, - "serviceLevel": { - "type": "string", - "allowedValues": [ - "Premium", - "Standard", - "StandardZRS", - "Ultra" - ], - "nullable": true, - "metadata": { - "description": "Optional. The pool service level." - } - }, - "size": { - "type": "int", - "metadata": { - "description": "Required. Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104)." - } - }, - "qosType": { - "type": "string", - "allowedValues": [ - "Auto", - "Manual" - ], - "nullable": true, - "metadata": { - "description": "Optional. The qos type of the pool." - } - }, - "volumes": { - "type": "array", - "items": { - "$ref": "#/definitions/volumeType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of volumes to create in the capacity pool." - } - }, - "coolAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "encryptionType": { - "type": "string", - "allowedValues": [ - "Double", - "Single" - ], - "nullable": true, - "metadata": { - "description": "Optional. Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a capacity pool." - } - }, - "snapshotPolicyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the snapshot policy." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the snapshot policy." - } - }, - "dailySchedule": { - "$ref": "#/definitions/dailyScheduleType", - "nullable": true, - "metadata": { - "description": "Optional. Daily schedule for the snapshot policy." - } - }, - "hourlySchedule": { - "$ref": "#/definitions/hourlyScheduleType", - "nullable": true, - "metadata": { - "description": "Optional. Hourly schedule for the snapshot policy." - } - }, - "monthlySchedule": { - "$ref": "#/definitions/monthlyScheduleType", - "nullable": true, - "metadata": { - "description": "Optional. Monthly schedule for the snapshot policy." - } - }, - "weeklySchedule": { - "$ref": "#/definitions/weeklyScheduleType", - "nullable": true, - "metadata": { - "description": "Optional. Weekly schedule for the snapshot policy." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a snapshot policy." - } - }, - "backupPolicyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backup policy." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location of the backup policy." - } - }, - "dailyBackupsToKeep": { - "type": "int", - "nullable": true, - "minValue": 2, - "maxValue": 1019, - "metadata": { - "description": "Optional. The daily backups to keep." - } - }, - "monthlyBackupsToKeep": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The monthly backups to keep." - } - }, - "weeklyBackupsToKeep": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The weekly backups to keep." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether the backup policy is enabled." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a backup policy." - } - }, - "_1.backupType": { - "type": "object", - "properties": { - "backupPolicyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the backup policy to link." - } - }, - "policyEnforced": { - "type": "bool", - "metadata": { - "description": "Required. Enable to enforce the policy." - } - }, - "backupVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Backup Vault." - } - } - }, - "metadata": { - "description": "The type for the backup properties.", - "__bicep_imported_from!": { - "sourceTemplate": "capacity-pool/volume/main.bicep" - } - } - }, - "_1.dataProtectionType": { - "type": "object", - "properties": { - "replication": { - "$ref": "#/definitions/_1.replicationType", - "nullable": true, - "metadata": { - "description": "Optional. Replication properties." - } - }, - "backup": { - "$ref": "#/definitions/_1.backupType", - "nullable": true, - "metadata": { - "description": "Optional. Backup properties." - } - }, - "snapshot": { - "$ref": "#/definitions/_1.snapshotType", - "nullable": true, - "metadata": { - "description": "Optional. Snapshot properties." - } - } - }, - "metadata": { - "description": "The type for the data protection properties.", - "__bicep_imported_from!": { - "sourceTemplate": "capacity-pool/volume/main.bicep" - } - } - }, - "_1.exportPolicyType": { - "type": "object", - "properties": { - "rules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ruleIndex": { - "type": "int", - "metadata": { - "description": "Required. Order index." - } - }, - "allowedClients": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." - } - }, - "chownMode": { - "type": "string", - "allowedValues": [ - "Restricted", - "Unrestricted" - ], - "nullable": true, - "metadata": { - "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." - } - }, - "cifs": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Allows CIFS protocol." - } - }, - "hasRootAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Has root access to volume." - } - }, - "kerberos5ReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5 Read only access." - } - }, - "kerberos5ReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5 Read and write access." - } - }, - "kerberos5iReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5i Read only access." - } - }, - "kerberos5iReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5i Read and write access." - } - }, - "kerberos5pReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5p Read only access." - } - }, - "kerberos5pReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5p Read and write access." - } - }, - "nfsv3": { - "type": "bool", - "metadata": { - "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." - } - }, - "nfsv41": { - "type": "bool", - "metadata": { - "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." - } - }, - "unixReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Read only access." - } - }, - "unixReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Read and write access." - } - } - } - }, - "metadata": { - "description": "Required. The Export policy rules." - } - } - }, - "metadata": { - "description": "The type for export policy rules.", - "__bicep_imported_from!": { - "sourceTemplate": "capacity-pool/volume/main.bicep" - } - } - }, - "_1.replicationType": { - "type": "object", - "properties": { - "endpointType": { - "type": "string", - "allowedValues": [ - "dst", - "src" - ], - "metadata": { - "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." - } - }, - "remoteVolumeRegion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." - } - }, - "remoteVolumeResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." - } - }, - "replicationSchedule": { - "type": "string", - "allowedValues": [ - "_10minutely", - "daily", - "hourly" - ], - "metadata": { - "description": "Required. The replication schedule for the volume." - } - }, - "remotePath": { - "type": "object", - "properties": { - "externalHostName": { - "type": "string", - "metadata": { - "description": "Required. The Path to a ONTAP Host." - } - }, - "serverName": { - "type": "string", - "metadata": { - "description": "Required. The name of a server on the ONTAP Host." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of a volume on the server." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." - } - } - }, - "metadata": { - "description": "The type for the replication properties.", - "__bicep_imported_from!": { - "sourceTemplate": "capacity-pool/volume/main.bicep" - } - } - }, - "_1.snapshotType": { - "type": "object", - "properties": { - "snapshotPolicyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the snapshot policy to link." - } - } - }, - "metadata": { - "description": "The type for the snapshot properties.", - "__bicep_imported_from!": { - "sourceTemplate": "capacity-pool/volume/main.bicep" - } - } - }, - "backupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "label": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Label for backup." - } - }, - "snapshotName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of the volume to backup." - } - }, - "capacityPoolName": { - "type": "string", - "metadata": { - "description": "Required. The name of the capacity pool containing the volume." - } - } - }, - "metadata": { - "description": "The type for a backup.", - "__bicep_imported_from!": { - "sourceTemplate": "backup-vault/main.bicep" - } - } - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" - } - } - }, - "dailyScheduleType": { - "type": "object", - "properties": { - "hour": { - "type": "int", - "minValue": 0, - "maxValue": 23, - "metadata": { - "description": "Required. The daily snapshot hour." - } - }, - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The daily snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, - "metadata": { - "description": "Required. Daily snapshot count to keep." - } - }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." - } - } - }, - "metadata": { - "description": "The type for a daily schedule for the snapshot policy.", - "__bicep_imported_from!": { - "sourceTemplate": "snapshot-policies/main.bicep" - } - } - }, - "hourlyScheduleType": { - "type": "object", - "properties": { - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The hourly snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, - "metadata": { - "description": "Required. Hourly snapshot count to keep." - } - }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." - } - } - }, - "metadata": { - "description": "The type for an hourly schedule for the snapshot policy.", - "__bicep_imported_from!": { - "sourceTemplate": "snapshot-policies/main.bicep" - } - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a lock.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" - } - } - }, - "managedIdentityOnlyUserAssignedType": { - "type": "object", - "properties": { - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if only user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" - } - } - }, - "monthlyScheduleType": { - "type": "object", - "properties": { - "daysOfMonth": { - "type": "string", - "metadata": { - "description": "Required. Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'." - } - }, - "hour": { - "type": "int", - "minValue": 0, - "maxValue": 23, - "metadata": { - "description": "Required. The monthly snapshot hour." - } - }, - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The monthly snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, - "metadata": { - "description": "Required. Monthly snapshot count to keep." - } - }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." - } - } - }, - "metadata": { - "description": "The type for a monthly schedule for the snapshot policy.", - "__bicep_imported_from!": { - "sourceTemplate": "snapshot-policies/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" - } - } - }, - "volumeType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the pool volume." - } - }, - "coolAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." - } - }, - "coolnessPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." - } - }, - "coolAccessRetrievalPolicy": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." - } - }, - "encryptionKeySource": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source of the encryption key." - } - }, - "keyVaultPrivateEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the key vault private endpoint." - } - }, - "dataProtection": { - "$ref": "#/definitions/_1.dataProtectionType", - "nullable": true, - "metadata": { - "description": "Optional. DataProtection type volumes include an object containing details of the replication." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the pool volume." - } - }, - "zones": { - "type": "array", - "items": { - "type": "int" - }, - "nullable": true, - "metadata": { - "description": "Optional. Zone where the volume will be placed." - } - }, - "serviceLevel": { - "type": "string", - "allowedValues": [ - "Premium", - "Standard", - "StandardZRS", - "Ultra" - ], - "nullable": true, - "metadata": { - "description": "Optional. The pool service level. Must match the one of the parent capacity pool." - } - }, - "networkFeatures": { - "type": "string", - "allowedValues": [ - "Basic", - "Basic_Standard", - "Standard", - "Standard_Basic" - ], - "nullable": true, - "metadata": { - "description": "Optional. Network feature for the volume." - } - }, - "creationToken": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." - } - }, - "usageThreshold": { - "type": "int", - "metadata": { - "description": "Required. Maximum storage quota allowed for a file system in bytes." - } - }, - "protocolTypes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Set of protocol types." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." - } - }, - "exportPolicy": { - "$ref": "#/definitions/_1.exportPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Export policy rules." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "smbEncryption": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." - } - }, - "smbContinuouslyAvailable": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." - } - }, - "smbNonBrowsable": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." - } - }, - "kerberosEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Define if a volume is KerberosEnabled." - } - }, - "volumeType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The type of the volume. DataProtection volumes are used for replication." - } - } - }, - "metadata": { - "description": "The type for a volume in the capacity pool.", - "__bicep_imported_from!": { - "sourceTemplate": "capacity-pool/main.bicep" - } - } - }, - "weeklyScheduleType": { - "type": "object", - "properties": { - "day": { - "type": "string", - "allowedValues": [ - "Friday", - "Monday", - "Saturday", - "Sunday", - "Thursday", - "Tuesday", - "Wednesday" - ], - "metadata": { - "description": "Required. The weekly snapshot day." - } - }, - "hour": { - "type": "int", - "minValue": 0, - "maxValue": 23, - "metadata": { - "description": "Required. The weekly snapshot hour." - } - }, - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The weekly snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, - "metadata": { - "description": "Required. Weekly snapshot count to keep." - } - }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." - } - } - }, - "metadata": { - "description": "The type for a weekly schedule for the snapshot policy.", - "__bicep_imported_from!": { - "sourceTemplate": "snapshot-policies/main.bicep" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the NetApp account." - } - }, - "adName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Name of the active directory host as part of Kerberos Realm used for Kerberos authentication." - } - }, - "aesEncryption": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable AES encryption on the SMB Server." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "domainName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Fully Qualified Active Directory DNS Domain Name (e.g. 'contoso.com')." - } - }, - "domainJoinUser": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if domainName is specified. Username of Active Directory domain administrator, with permissions to create SMB server machine account in the AD domain." - } - }, - "domainJoinPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if domainName is specified. Password of the user specified in domainJoinUser parameter." - } - }, - "domainJoinOU": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Used only if domainName is specified. LDAP Path for the Organization Unit (OU) where SMB Server machine accounts will be created (i.e. 'OU=SecondLevel,OU=FirstLevel')." - } - }, - "dnsServers": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if domainName is specified. Comma separated list of DNS server IP addresses (IPv4 only) required for the Active Directory (AD) domain join and SMB authentication operations to succeed." - } - }, - "encryptDCConnections": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether encryption should be used for communication between SMB server and domain controller (DC). SMB3 only." - } - }, - "smbServerNamePrefix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if domainName is specified. NetBIOS name of the SMB server. A computer account with this prefix will be registered in the AD and used to mount volumes." - } - }, - "capacityPools": { - "type": "array", - "items": { - "$ref": "#/definitions/capacityPoolType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Capacity pools to create." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityOnlyUserAssignedType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "kdcIP": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Kerberos Key Distribution Center (KDC) as part of Kerberos Realm used for Kerberos authentication." - } - }, - "ldapOverTLS": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether to use TLS when NFS (with/without Kerberos) and SMB volumes communicate with an LDAP server. A server root CA certificate must be uploaded if enabled (serverRootCACertificate)." - } - }, - "ldapSigning": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether or not the LDAP traffic needs to be signed." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "serverRootCACertificate": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. A server Root certificate is required of ldapOverTLS is enabled." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags for all resources." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "backupVault": { - "$ref": "#/definitions/backupVaultType", - "nullable": true, - "metadata": { - "description": "Optional. The netapp backup vault to create & configure." - } - }, - "snapshotPolicies": { - "type": "array", - "items": { - "$ref": "#/definitions/snapshotPolicyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The snapshot policies to create." - } - }, - "backupPolicies": { - "type": "array", - "items": { - "$ref": "#/definitions/backupPolicyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The backup policies to create." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "activeDirectoryConnectionProperties": [ - { - "adName": "[if(not(empty(parameters('domainName'))), parameters('adName'), null())]", - "aesEncryption": "[if(not(empty(parameters('domainName'))), parameters('aesEncryption'), false())]", - "username": "[if(not(empty(parameters('domainName'))), parameters('domainJoinUser'), null())]", - "password": "[if(not(empty(parameters('domainName'))), parameters('domainJoinPassword'), null())]", - "domain": "[if(not(empty(parameters('domainName'))), parameters('domainName'), null())]", - "dns": "[if(not(empty(parameters('domainName'))), parameters('dnsServers'), null())]", - "encryptDCConnections": "[if(not(empty(parameters('domainName'))), parameters('encryptDCConnections'), false())]", - "kdcIP": "[if(not(empty(parameters('domainName'))), parameters('kdcIP'), null())]", - "ldapOverTLS": "[if(not(empty(parameters('domainName'))), parameters('ldapOverTLS'), false())]", - "ldapSigning": "[if(not(empty(parameters('domainName'))), parameters('ldapSigning'), false())]", - "serverRootCACertificate": "[if(not(empty(parameters('domainName'))), parameters('serverRootCACertificate'), null())]", - "smbServerName": "[if(not(empty(parameters('domainName'))), parameters('smbServerNamePrefix'), null())]", - "organizationalUnit": "[if(not(empty(parameters('domainJoinOU'))), parameters('domainJoinOU'), null())]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None'), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.netapp-netappaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" - }, - "netAppAccount": { - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "location": "[parameters('location')]", - "properties": { - "activeDirectories": "[if(not(empty(parameters('domainName'))), variables('activeDirectoryConnectionProperties'), null())]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('identity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), createObject('userAssignedIdentity', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/')))), null()), 'keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('keyName', parameters('customerManagedKey').keyName, 'keyVaultResourceId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]), 'Microsoft.KeyVault/vaults', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))), 'keyVaultUri', reference('cMKKeyVault').vaultUri)), null())]" - }, - "dependsOn": [ - "cMKKeyVault" - ] - }, - "netAppAccount_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "netAppAccount_roleAssignments": { - "copy": { - "name": "netAppAccount_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "netAppAccount_backupPolicies": { - "copy": { - "name": "netAppAccount_backupPolicies", - "count": "[length(coalesce(parameters('backupPolicies'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-ANFAccount-backupPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'name')]" - }, - "dailyBackupsToKeep": { - "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'dailyBackupsToKeep')]" - }, - "monthlyBackupsToKeep": { - "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'monthlyBackupsToKeep')]" - }, - "weeklyBackupsToKeep": { - "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'weeklyBackupsToKeep')]" - }, - "enabled": { - "value": "[tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'enabled')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('backupPolicies'), createArray())[copyIndex()], 'location'), parameters('location'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "16432727764202874682" - }, - "name": "Azure NetApp Files Backup Policy", - "description": "This module deploys a Backup Policy for Azure NetApp File." - }, - "parameters": { - "netAppAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "backupPolicy", - "metadata": { - "description": "Optional. The name of the backup policy." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup policy." - } - }, - "dailyBackupsToKeep": { - "type": "int", - "defaultValue": 2, - "minValue": 2, - "maxValue": 1019, - "metadata": { - "description": "Optional. The daily backups to keep." - } - }, - "monthlyBackupsToKeep": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. The monthly backups to keep." - } - }, - "weeklyBackupsToKeep": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. The weekly backups to keep." - } - }, - "enabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether the backup policy is enabled." - } - } - }, - "resources": [ - { - "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "enabled": "[parameters('enabled')]", - "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", - "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]", - "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]" - } - } - ], - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource IDs of the backup Policy created within volume." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Backup Policy." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the Backup Policy was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "netAppAccount_snapshotPolicies": { - "copy": { - "name": "netAppAccount_snapshotPolicies", - "count": "[length(coalesce(parameters('snapshotPolicies'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-ANFAccount-snapshotPolicy-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'name')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'location'), parameters('location'))]" - }, - "snapEnabled": { - "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'snapEnabled')]" - }, - "dailySchedule": { - "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'dailySchedule')]" - }, - "hourlySchedule": { - "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'hourlySchedule')]" - }, - "monthlySchedule": { - "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'monthlySchedule')]" - }, - "weeklySchedule": { - "value": "[tryGet(coalesce(parameters('snapshotPolicies'), createArray())[copyIndex()], 'weeklySchedule')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "15408772009434991440" - }, - "name": "Azure NetApp Files Snapshot Policy", - "description": "This module deploys a Snapshot Policy for an Azure NetApp File." - }, - "definitions": { - "dailyScheduleType": { - "type": "object", - "properties": { - "hour": { - "type": "int", - "minValue": 0, - "maxValue": 23, - "metadata": { - "description": "Required. The daily snapshot hour." - } - }, - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The daily snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, - "metadata": { - "description": "Required. Daily snapshot count to keep." - } - }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a daily schedule for the snapshot policy." - } - }, - "hourlyScheduleType": { - "type": "object", - "properties": { - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The hourly snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, - "metadata": { - "description": "Required. Hourly snapshot count to keep." - } - }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an hourly schedule for the snapshot policy." - } - }, - "weeklyScheduleType": { - "type": "object", - "properties": { - "day": { - "type": "string", - "allowedValues": [ - "Friday", - "Monday", - "Saturday", - "Sunday", - "Thursday", - "Tuesday", - "Wednesday" - ], - "metadata": { - "description": "Required. The weekly snapshot day." - } - }, - "hour": { - "type": "int", - "minValue": 0, - "maxValue": 23, - "metadata": { - "description": "Required. The weekly snapshot hour." - } - }, - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The weekly snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, - "metadata": { - "description": "Required. Weekly snapshot count to keep." - } - }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a weekly schedule for the snapshot policy." - } - }, - "monthlyScheduleType": { - "type": "object", - "properties": { - "daysOfMonth": { - "type": "string", - "metadata": { - "description": "Required. Indicates which days of the month snapshot should be taken. A comma delimited string. E.g., '10,11,12'." - } - }, - "hour": { - "type": "int", - "minValue": 0, - "maxValue": 23, - "metadata": { - "description": "Required. The monthly snapshot hour." - } - }, - "minute": { - "type": "int", - "minValue": 0, - "maxValue": 59, - "metadata": { - "description": "Required. The monthly snapshot minute." - } - }, - "snapshotsToKeep": { - "type": "int", - "minValue": 1, - "maxValue": 255, - "metadata": { - "description": "Required. Monthly snapshot count to keep." - } - }, - "usedBytes": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Resource size in bytes, current storage usage for the volume in bytes." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a monthly schedule for the snapshot policy." - } - } - }, - "parameters": { - "netAppAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "snapshotPolicy", - "metadata": { - "description": "Optional. The name of the snapshot policy." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the snapshot policy." - } - }, - "hourlySchedule": { - "$ref": "#/definitions/hourlyScheduleType", - "nullable": true, - "metadata": { - "description": "Optional. Schedule for hourly snapshots." - } - }, - "dailySchedule": { - "$ref": "#/definitions/dailyScheduleType", - "nullable": true, - "metadata": { - "description": "Optional. Schedule for daily snapshots." - } - }, - "monthlySchedule": { - "$ref": "#/definitions/monthlyScheduleType", - "nullable": true, - "metadata": { - "description": "Optional. Schedule for monthly snapshots." - } - }, - "weeklySchedule": { - "$ref": "#/definitions/weeklyScheduleType", - "nullable": true, - "metadata": { - "description": "Optional. Schedule for weekly snapshots." - } - }, - "snapEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether the snapshot policy is enabled." - } - } - }, - "resources": { - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "snapshotPolicies": { - "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "enabled": "[parameters('snapEnabled')]", - "dailySchedule": "[parameters('dailySchedule')]", - "hourlySchedule": "[parameters('hourlySchedule')]", - "monthlySchedule": "[parameters('monthlySchedule')]", - "weeklySchedule": "[parameters('weeklySchedule')]" - } - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource IDs of the snapshot Policy created within volume." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Backup Policy." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the Snapshot was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "netAppAccount_backupVault": { - "condition": "[not(empty(parameters('backupVault')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-ANFAccount-BackupVault', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(parameters('backupVault'), 'name')]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('backupVault'), 'location'), parameters('location'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12673365749567452459" - }, - "name": "Azure NetApp Files Volume Backup Vault", - "description": "This module deploys a NetApp Files Backup Vault." - }, - "definitions": { - "backupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "label": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Label for backup." - } - }, - "snapshotName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of the volume to backup." - } - }, - "capacityPoolName": { - "type": "string", - "metadata": { - "description": "Required. The name of the capacity pool containing the volume." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a backup." - } - } - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "vault", - "metadata": { - "description": "Optional. The name of the backup vault." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location of the backup vault." - } - }, - "netAppAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." - } - }, - "backups": { - "type": "array", - "items": { - "$ref": "#/definitions/backupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of backups to create." - } - } - }, - "resources": { - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "backupVault": { - "type": "Microsoft.NetApp/netAppAccounts/backupVaults", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": {} - }, - "backupVault_backups": { - "copy": { - "name": "backupVault_backups", - "count": "[length(coalesce(parameters('backups'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-ANF-Backup-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('netAppAccountName')]" - }, - "backupVaultName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'name')]" - }, - "label": { - "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'label')]" - }, - "snapshotName": { - "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'snapshotName')]" - }, - "volumeName": { - "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].volumeName]" - }, - "capacityPoolName": { - "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].capacityPoolName]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "2218257802133394577" - }, - "name": "Azure NetApp Files Volume Backup", - "description": "This module deploys a backup of a NetApp Files Volume." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "backup", - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "backupVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent backup vault. Required if the template is used in a standalone deployment." - } - }, - "netAppAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." - } - }, - "label": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Label for backup." - } - }, - "snapshotName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of the volume to backup." - } - }, - "capacityPoolName": { - "type": "string", - "metadata": { - "description": "Required. The name of the capacity pool containing the volume." - } - } - }, - "resources": { - "netAppAccount::remoteCapacityPool::volume": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" - }, - "netAppAccount::backupVault": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/backupVaults", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupVaultName'))]" - }, - "netAppAccount::remoteCapacityPool": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" - }, - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "backup": { - "type": "Microsoft.NetApp/netAppAccounts/backupVaults/backups", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]", - "properties": { - "label": "[parameters('label')]", - "snapshotName": "[parameters('snapshotName')]", - "volumeResourceId": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the backup." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The Resource ID of the backup." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults/backups', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the backup was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "backupVault" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the backup vault." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The Resource ID of the backup vault." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the backup vault was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('backupVault', '2024-07-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "netAppAccount_capacityPools": { - "copy": { - "name": "netAppAccount_capacityPools", - "count": "[length(coalesce(parameters('capacityPools'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-ANFAccount-CapPool-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('capacityPools'), createArray())[copyIndex()].name]" - }, - "size": { - "value": "[coalesce(parameters('capacityPools'), createArray())[copyIndex()].size]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'location'), parameters('location'))]" - }, - "serviceLevel": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'serviceLevel'), 'Standard')]" - }, - "qosType": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'qosType'), 'Auto')]" - }, - "volumes": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'volumes'), createArray())]" - }, - "coolAccess": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'coolAccess'), false())]" - }, - "roleAssignments": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'roleAssignments'), createArray())]" - }, - "encryptionType": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'encryptionType'), 'Single')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('capacityPools'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "8976617662375535030" - }, - "name": "Azure NetApp Files Capacity Pools", - "description": "This module deploys an Azure NetApp Files Capacity Pool." - }, - "definitions": { - "volumeType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the pool volume." - } - }, - "coolAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." - } - }, - "coolnessPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." - } - }, - "coolAccessRetrievalPolicy": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." - } - }, - "encryptionKeySource": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source of the encryption key." - } - }, - "keyVaultPrivateEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the key vault private endpoint." - } - }, - "dataProtection": { - "$ref": "#/definitions/dataProtectionType", - "nullable": true, - "metadata": { - "description": "Optional. DataProtection type volumes include an object containing details of the replication." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Location of the pool volume." - } - }, - "zones": { - "type": "array", - "items": { - "type": "int" - }, - "nullable": true, - "metadata": { - "description": "Optional. Zone where the volume will be placed." - } - }, - "serviceLevel": { - "type": "string", - "allowedValues": [ - "Premium", - "Standard", - "StandardZRS", - "Ultra" - ], - "nullable": true, - "metadata": { - "description": "Optional. The pool service level. Must match the one of the parent capacity pool." - } - }, - "networkFeatures": { - "type": "string", - "allowedValues": [ - "Basic", - "Basic_Standard", - "Standard", - "Standard_Basic" - ], - "nullable": true, - "metadata": { - "description": "Optional. Network feature for the volume." - } - }, - "creationToken": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." - } - }, - "usageThreshold": { - "type": "int", - "metadata": { - "description": "Required. Maximum storage quota allowed for a file system in bytes." - } - }, - "protocolTypes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Set of protocol types." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." - } - }, - "exportPolicy": { - "$ref": "#/definitions/exportPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Export policy rules." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "smbEncryption": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." - } - }, - "smbContinuouslyAvailable": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." - } - }, - "smbNonBrowsable": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." - } - }, - "kerberosEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Define if a volume is KerberosEnabled." - } - }, - "volumeType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The type of the volume. DataProtection volumes are used for replication." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a volume in the capacity pool." - } - }, - "_1.backupType": { - "type": "object", - "properties": { - "backupPolicyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the backup policy to link." - } - }, - "policyEnforced": { - "type": "bool", - "metadata": { - "description": "Required. Enable to enforce the policy." - } - }, - "backupVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Backup Vault." - } - } - }, - "metadata": { - "description": "The type for the backup properties.", - "__bicep_imported_from!": { - "sourceTemplate": "volume/main.bicep" - } - } - }, - "_1.replicationType": { - "type": "object", - "properties": { - "endpointType": { - "type": "string", - "allowedValues": [ - "dst", - "src" - ], - "metadata": { - "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." - } - }, - "remoteVolumeRegion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." - } - }, - "remoteVolumeResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." - } - }, - "replicationSchedule": { - "type": "string", - "allowedValues": [ - "_10minutely", - "daily", - "hourly" - ], - "metadata": { - "description": "Required. The replication schedule for the volume." - } - }, - "remotePath": { - "type": "object", - "properties": { - "externalHostName": { - "type": "string", - "metadata": { - "description": "Required. The Path to a ONTAP Host." - } - }, - "serverName": { - "type": "string", - "metadata": { - "description": "Required. The name of a server on the ONTAP Host." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of a volume on the server." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." - } - } - }, - "metadata": { - "description": "The type for the replication properties.", - "__bicep_imported_from!": { - "sourceTemplate": "volume/main.bicep" - } - } - }, - "_1.snapshotType": { - "type": "object", - "properties": { - "snapshotPolicyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the snapshot policy to link." - } - } - }, - "metadata": { - "description": "The type for the snapshot properties.", - "__bicep_imported_from!": { - "sourceTemplate": "volume/main.bicep" - } - } - }, - "dataProtectionType": { - "type": "object", - "properties": { - "replication": { - "$ref": "#/definitions/_1.replicationType", - "nullable": true, - "metadata": { - "description": "Optional. Replication properties." - } - }, - "backup": { - "$ref": "#/definitions/_1.backupType", - "nullable": true, - "metadata": { - "description": "Optional. Backup properties." - } - }, - "snapshot": { - "$ref": "#/definitions/_1.snapshotType", - "nullable": true, - "metadata": { - "description": "Optional. Snapshot properties." - } - } - }, - "metadata": { - "description": "The type for the data protection properties.", - "__bicep_imported_from!": { - "sourceTemplate": "volume/main.bicep" - } - } - }, - "exportPolicyType": { - "type": "object", - "properties": { - "rules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ruleIndex": { - "type": "int", - "metadata": { - "description": "Required. Order index." - } - }, - "allowedClients": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." - } - }, - "chownMode": { - "type": "string", - "allowedValues": [ - "Restricted", - "Unrestricted" - ], - "nullable": true, - "metadata": { - "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." - } - }, - "cifs": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Allows CIFS protocol." - } - }, - "hasRootAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Has root access to volume." - } - }, - "kerberos5ReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5 Read only access." - } - }, - "kerberos5ReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5 Read and write access." - } - }, - "kerberos5iReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5i Read only access." - } - }, - "kerberos5iReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5i Read and write access." - } - }, - "kerberos5pReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5p Read only access." - } - }, - "kerberos5pReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5p Read and write access." - } - }, - "nfsv3": { - "type": "bool", - "metadata": { - "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." - } - }, - "nfsv41": { - "type": "bool", - "metadata": { - "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." - } - }, - "unixReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Read only access." - } - }, - "unixReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Read and write access." - } - } - } - }, - "metadata": { - "description": "Required. The Export policy rules." - } - } - }, - "metadata": { - "description": "The type for export policy rules.", - "__bicep_imported_from!": { - "sourceTemplate": "volume/main.bicep" - } - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" - } - } - } - }, - "parameters": { - "netAppAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the capacity pool." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location of the pool volume." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags for all resources." - } - }, - "serviceLevel": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Premium", - "Standard", - "StandardZRS", - "Ultra" - ], - "metadata": { - "description": "Optional. The pool service level." - } - }, - "size": { - "type": "int", - "metadata": { - "description": "Required. Provisioned size of the pool (in bytes). Allowed values are in 4TiB chunks (value must be multiply of 4398046511104)." - } - }, - "qosType": { - "type": "string", - "defaultValue": "Auto", - "allowedValues": [ - "Auto", - "Manual" - ], - "metadata": { - "description": "Optional. The qos type of the pool." - } - }, - "volumes": { - "type": "array", - "items": { - "$ref": "#/definitions/volumeType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of volumes to create in the capacity pool." - } - }, - "coolAccess": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If enabled (true) the pool can contain cool Access enabled volumes." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "encryptionType": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Double", - "Single" - ], - "metadata": { - "description": "Optional. Encryption type of the capacity pool, set encryption type for data at rest for this pool and all volumes in it. This value can only be set when creating new pool." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "capacityPool": { - "type": "Microsoft.NetApp/netAppAccounts/capacityPools", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "serviceLevel": "[parameters('serviceLevel')]", - "size": "[parameters('size')]", - "qosType": "[parameters('qosType')]", - "coolAccess": "[parameters('coolAccess')]", - "encryptionType": "[parameters('encryptionType')]" - } - }, - "capacityPool_roleAssignments": { - "copy": { - "name": "capacityPool_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}/capacityPools/{1}', parameters('netAppAccountName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts/capacityPools', parameters('netAppAccountName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "capacityPool" - ] - }, - "capacityPool_volumes": { - "copy": { - "name": "capacityPool_volumes", - "count": "[length(coalesce(parameters('volumes'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Vol-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('netAppAccountName')]" - }, - "capacityPoolName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].name]" - }, - "location": { - "value": "[parameters('location')]" - }, - "serviceLevel": { - "value": "[parameters('serviceLevel')]" - }, - "creationToken": { - "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'creationToken'), coalesce(parameters('volumes'), createArray())[copyIndex()].name)]" - }, - "usageThreshold": { - "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].usageThreshold]" - }, - "protocolTypes": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'protocolTypes')]" - }, - "subnetResourceId": { - "value": "[coalesce(parameters('volumes'), createArray())[copyIndex()].subnetResourceId]" - }, - "exportPolicy": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'exportPolicy')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "networkFeatures": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'networkFeatures')]" - }, - "zones": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'zones')]" - }, - "coolAccess": { - "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolAccess'), false())]" - }, - "coolAccessRetrievalPolicy": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolAccessRetrievalPolicy')]" - }, - "coolnessPeriod": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'coolnessPeriod')]" - }, - "encryptionKeySource": { - "value": "[coalesce(tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'encryptionKeySource'), 'Microsoft.NetApp')]" - }, - "keyVaultPrivateEndpointResourceId": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'keyVaultPrivateEndpointResourceId')]" - }, - "dataProtection": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'dataProtection')]" - }, - "kerberosEnabled": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'kerberosEnabled')]" - }, - "smbContinuouslyAvailable": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbContinuouslyAvailable')]" - }, - "smbEncryption": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbEncryption')]" - }, - "smbNonBrowsable": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'smbNonBrowsable')]" - }, - "volumeType": { - "value": "[tryGet(coalesce(parameters('volumes'), createArray())[copyIndex()], 'volumeType')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "17068369293044189585" - }, - "name": "Azure NetApp Files Capacity Pool Volumes", - "description": "This module deploys an Azure NetApp Files Capacity Pool Volume." - }, - "definitions": { - "dataProtectionType": { - "type": "object", - "properties": { - "replication": { - "$ref": "#/definitions/replicationType", - "nullable": true, - "metadata": { - "description": "Optional. Replication properties." - } - }, - "backup": { - "$ref": "#/definitions/backupType", - "nullable": true, - "metadata": { - "description": "Optional. Backup properties." - } - }, - "snapshot": { - "$ref": "#/definitions/snapshotType", - "nullable": true, - "metadata": { - "description": "Optional. Snapshot properties." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the data protection properties." - } - }, - "replicationType": { - "type": "object", - "properties": { - "endpointType": { - "type": "string", - "allowedValues": [ - "dst", - "src" - ], - "metadata": { - "description": "Required. Indicates whether the local volume is the source or destination for the Volume Replication." - } - }, - "remoteVolumeRegion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The remote region for the other end of the Volume Replication.Required for Data Protection volumes." - } - }, - "remoteVolumeResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the remote volume. Required for Data Protection volumes." - } - }, - "replicationSchedule": { - "type": "string", - "allowedValues": [ - "_10minutely", - "daily", - "hourly" - ], - "metadata": { - "description": "Required. The replication schedule for the volume." - } - }, - "remotePath": { - "type": "object", - "properties": { - "externalHostName": { - "type": "string", - "metadata": { - "description": "Required. The Path to a ONTAP Host." - } - }, - "serverName": { - "type": "string", - "metadata": { - "description": "Required. The name of a server on the ONTAP Host." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of a volume on the server." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The full path to a volume that is to be migrated into ANF. Required for Migration volumes." - } - } - }, - "metadata": { - "description": "The type for the replication properties." - } - }, - "backupType": { - "type": "object", - "properties": { - "backupPolicyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the backup policy to link." - } - }, - "policyEnforced": { - "type": "bool", - "metadata": { - "description": "Required. Enable to enforce the policy." - } - }, - "backupVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Backup Vault." - } - } - }, - "metadata": { - "description": "The type for the backup properties." - } - }, - "snapshotType": { - "type": "object", - "properties": { - "snapshotPolicyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the snapshot policy to link." - } - } - }, - "metadata": { - "description": "The type for the snapshot properties." - } - }, - "exportPolicyType": { - "type": "object", - "properties": { - "rules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ruleIndex": { - "type": "int", - "metadata": { - "description": "Required. Order index." - } - }, - "allowedClients": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Client ingress specification as comma separated string with IPv4 CIDRs, IPv4 host addresses and host names." - } - }, - "chownMode": { - "type": "string", - "allowedValues": [ - "Restricted", - "Unrestricted" - ], - "nullable": true, - "metadata": { - "description": "Optional. This parameter specifies who is authorized to change the ownership of a file. restricted - Only root user can change the ownership of the file. unrestricted - Non-root users can change ownership of files that they own." - } - }, - "cifs": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Allows CIFS protocol." - } - }, - "hasRootAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Has root access to volume." - } - }, - "kerberos5ReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5 Read only access." - } - }, - "kerberos5ReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5 Read and write access." - } - }, - "kerberos5iReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5i Read only access." - } - }, - "kerberos5iReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5i Read and write access." - } - }, - "kerberos5pReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5p Read only access." - } - }, - "kerberos5pReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Kerberos5p Read and write access." - } - }, - "nfsv3": { - "type": "bool", - "metadata": { - "description": "Required. Allows NFSv3 protocol. Enable only for NFSv3 type volumes." - } - }, - "nfsv41": { - "type": "bool", - "metadata": { - "description": "Required. Allows NFSv4.1 protocol. Enable only for NFSv4.1 type volumes." - } - }, - "unixReadOnly": { - "type": "bool", - "metadata": { - "description": "Required. Read only access." - } - }, - "unixReadWrite": { - "type": "bool", - "metadata": { - "description": "Required. Read and write access." - } - } - } - }, - "metadata": { - "description": "Required. The Export policy rules." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for export policy rules." - } - }, - "roleAssignmentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a role assignment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" - } - } - } - }, - "parameters": { - "netAppAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." - } - }, - "capacityPoolName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent capacity pool. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the pool volume." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location of the pool volume." - } - }, - "coolAccess": { - "type": "bool", - "metadata": { - "description": "Required. If enabled (true) the pool can contain cool Access enabled volumes." - } - }, - "coolnessPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the number of days after which data that is not accessed by clients will be tiered." - } - }, - "coolAccessRetrievalPolicy": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Determines the data retrieval behavior from the cool tier to standard storage based on the read pattern for cool access enabled volumes (Default/Never/Read)." - } - }, - "encryptionKeySource": { - "type": "string", - "metadata": { - "description": "Required. The source of the encryption key." - } - }, - "keyVaultPrivateEndpointResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the key vault private endpoint." - } - }, - "volumeType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The type of the volume. DataProtection volumes are used for replication." - } - }, - "zones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. Zone where the volume will be placed." - } - }, - "serviceLevel": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Premium", - "Standard", - "StandardZRS", - "Ultra" - ], - "metadata": { - "description": "Optional. The pool service level. Must match the one of the parent capacity pool." - } - }, - "networkFeatures": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Basic", - "Basic_Standard", - "Standard", - "Standard_Basic" - ], - "metadata": { - "description": "Optional. Network feature for the volume." - } - }, - "creationToken": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. A unique file path for the volume. This is the name of the volume export. A volume is mounted using the export path. File path must start with an alphabetical character and be unique within the subscription." - } - }, - "usageThreshold": { - "type": "int", - "metadata": { - "description": "Required. Maximum storage quota allowed for a file system in bytes." - } - }, - "protocolTypes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Set of protocol types." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Azure Resource URI for a delegated subnet. Must have the delegation Microsoft.NetApp/volumes." - } - }, - "exportPolicy": { - "$ref": "#/definitions/exportPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. The export policy rules." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "dataProtection": { - "$ref": "#/definitions/dataProtectionType", - "nullable": true, - "metadata": { - "description": "Optional. DataProtection type volumes include an object containing details of the replication." - } - }, - "smbEncryption": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables SMB encryption. Only applicable for SMB/DualProtocol volume." - } - }, - "smbContinuouslyAvailable": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables continuously available share property for SMB volume. Only applicable for SMB volume." - } - }, - "smbNonBrowsable": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Enables non-browsable property for SMB Shares. Only applicable for SMB/DualProtocol volume." - } - }, - "kerberosEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Define if a volume is KerberosEnabled." - } - } - }, - "variables": { - "copy": [ - { - "name": "formattedRoleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", - "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" - } - ], - "remoteCapacityPoolName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], '')]", - "remoteNetAppName": "[if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], '')]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "netAppAccount::capacityPool": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" - }, - "netAppAccount::backupVault": { - "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/backupVaults", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))]" - }, - "netAppAccount::backupPolicy": { - "condition": "[not(empty(tryGet(parameters('dataProtection'), 'backup')))]", - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName'))]" - }, - "netAppAccount::snapshotPolicy": { - "condition": "[not(empty(tryGet(parameters('dataProtection'), 'snapshot')))]", - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))]" - }, - "remoteNetAppAccount::remoteCapacityPool::remoteVolume": { - "condition": "[and(and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName'))))), not(empty(tryGet(parameters('dataProtection'), 'replication'))))]", - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", - "apiVersion": "2024-07-01", - "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", - "name": "[format('{0}/{1}/{2}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/')))]" - }, - "remoteNetAppAccount::remoteCapacityPool": { - "condition": "[and(and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName')))), and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteCapacityPoolName'), parameters('capacityPoolName')))))]", - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools", - "apiVersion": "2024-07-01", - "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", - "name": "[format('{0}/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10])]" - }, - "vnet::subnet": { - "existing": true, - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2024-03-01", - "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", - "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/')))]" - }, - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "keyVaultPrivateEndpoint": { - "condition": "[not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp'))]", - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-03-01", - "subscriptionId": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/'))]" - }, - "remoteNetAppAccount": { - "condition": "[and(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), not(equals(variables('remoteNetAppName'), parameters('netAppAccountName'))))]", - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "subscriptionId": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]]", - "name": "[split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8]]" - }, - "vnet": { - "existing": true, - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-03-01", - "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", - "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", - "name": "[split(parameters('subnetResourceId'), '/')[8]]" - }, - "volume": { - "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": "[shallowMerge(createArray(createObject('coolAccess', parameters('coolAccess'), 'coolAccessRetrievalPolicy', parameters('coolAccessRetrievalPolicy'), 'coolnessPeriod', parameters('coolnessPeriod'), 'encryptionKeySource', parameters('encryptionKeySource')), if(not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp')), createObject('keyVaultPrivateEndpointResourceId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '//'), '/')[2], split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), '////'), '/')[4]), 'Microsoft.Network/privateEndpoints', last(split(coalesce(parameters('keyVaultPrivateEndpointResourceId'), 'dummyVault'), '/')))), createObject()), if(not(empty(parameters('volumeType'))), createObject('volumeType', parameters('volumeType')), createObject()), createObject('dataProtection', if(not(empty(parameters('dataProtection'))), createObject('replication', if(not(empty(tryGet(parameters('dataProtection'), 'replication'))), createObject('endpointType', tryGet(parameters('dataProtection'), 'replication', 'endpointType'), 'remoteVolumeRegion', if(not(empty(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[2], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '////'), '/')[4]), 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[8], split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), '//'), '/')[10], last(split(coalesce(tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'dummyvolume'), '/'))), null()), 'remoteVolumeResourceId', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remoteVolumeResourceId'), 'replicationSchedule', tryGet(parameters('dataProtection'), 'replication', 'replicationSchedule'), 'remotePath', tryGet(tryGet(parameters('dataProtection'), 'replication'), 'remotePath')), createObject()), 'backup', if(not(empty(tryGet(parameters('dataProtection'), 'backup'))), createObject('backupPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupPolicyName')), 'policyEnforced', coalesce(tryGet(parameters('dataProtection'), 'backup', 'policyEnforced'), false()), 'backupVaultId', resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'backup', 'backupVaultName'))), createObject()), 'snapshot', if(not(empty(tryGet(parameters('dataProtection'), 'snapshot'))), createObject('snapshotPolicyId', resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), tryGet(parameters('dataProtection'), 'snapshot', 'snapshotPolicyName'))), createObject())), null()), 'networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('subnetResourceId'), '/')[2], split(parameters('subnetResourceId'), '/')[4]), 'Microsoft.Network/virtualNetworks/subnets', split(parameters('subnetResourceId'), '/')[8], last(split(parameters('subnetResourceId'), '/'))), 'exportPolicy', parameters('exportPolicy'), 'smbContinuouslyAvailable', parameters('smbContinuouslyAvailable'), 'smbEncryption', parameters('smbEncryption'), 'smbNonBrowsable', parameters('smbNonBrowsable'), 'kerberosEnabled', parameters('kerberosEnabled'))))]", - "zones": "[map(parameters('zones'), lambda('zone', format('{0}', lambdaVariables('zone'))))]" - }, - "volume_roleAssignments": { - "copy": { - "name": "volume_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.NetApp/netAppAccounts/{0}/capacityPools/{1}/volumes/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", - "properties": { - "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", - "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "volume" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Volume." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The Resource ID of the Volume." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the Volume was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('volume', '2024-07-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "capacityPool" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Capacity Pool." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Capacity Pool." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools', parameters('netAppAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the Capacity Pool was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('capacityPool', '2024-07-01', 'full').location]" - }, - "volumeResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The resource IDs of the volume created in the capacity pool." - }, - "copy": { - "count": "[length(coalesce(parameters('volumes'), createArray()))]", - "input": "[reference(format('capacityPool_volumes[{0}]', copyIndex())).outputs.resourceId.value]" - } - } - } - } - }, - "dependsOn": [ - "netAppAccount", - "netAppAccount_backupPolicies", - "netAppAccount_backupVault", - "netAppAccount_snapshotPolicies" - ] - }, - "netAppAccount_backupVaultBackups": { - "condition": "[not(empty(tryGet(parameters('backupVault'), 'backups')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-ANFAccount-BackupVault-Backups', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(parameters('backupVault'), 'name')]" - }, - "backups": { - "value": "[tryGet(parameters('backupVault'), 'backups')]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('backupVault'), 'location'), parameters('location'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12673365749567452459" - }, - "name": "Azure NetApp Files Volume Backup Vault", - "description": "This module deploys a NetApp Files Backup Vault." - }, - "definitions": { - "backupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "label": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Label for backup." - } - }, - "snapshotName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of the volume to backup." - } - }, - "capacityPoolName": { - "type": "string", - "metadata": { - "description": "Required. The name of the capacity pool containing the volume." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a backup." - } - } - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "vault", - "metadata": { - "description": "Optional. The name of the backup vault." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location of the backup vault." - } - }, - "netAppAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." - } - }, - "backups": { - "type": "array", - "items": { - "$ref": "#/definitions/backupType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of backups to create." - } - } - }, - "resources": { - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "backupVault": { - "type": "Microsoft.NetApp/netAppAccounts/backupVaults", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": {} - }, - "backupVault_backups": { - "copy": { - "name": "backupVault_backups", - "count": "[length(coalesce(parameters('backups'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-ANF-Backup-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppAccountName": { - "value": "[parameters('netAppAccountName')]" - }, - "backupVaultName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'name')]" - }, - "label": { - "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'label')]" - }, - "snapshotName": { - "value": "[tryGet(coalesce(parameters('backups'), createArray())[copyIndex()], 'snapshotName')]" - }, - "volumeName": { - "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].volumeName]" - }, - "capacityPoolName": { - "value": "[coalesce(parameters('backups'), createArray())[copyIndex()].capacityPoolName]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "2218257802133394577" - }, - "name": "Azure NetApp Files Volume Backup", - "description": "This module deploys a backup of a NetApp Files Volume." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "backup", - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "backupVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent backup vault. Required if the template is used in a standalone deployment." - } - }, - "netAppAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." - } - }, - "label": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Label for backup." - } - }, - "snapshotName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. The name of the volume to backup." - } - }, - "capacityPoolName": { - "type": "string", - "metadata": { - "description": "Required. The name of the capacity pool containing the volume." - } - } - }, - "resources": { - "netAppAccount::remoteCapacityPool::volume": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" - }, - "netAppAccount::backupVault": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/backupVaults", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupVaultName'))]" - }, - "netAppAccount::remoteCapacityPool": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts/capacityPools", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('capacityPoolName'))]" - }, - "netAppAccount": { - "existing": true, - "type": "Microsoft.NetApp/netAppAccounts", - "apiVersion": "2024-07-01", - "name": "[parameters('netAppAccountName')]" - }, - "backup": { - "type": "Microsoft.NetApp/netAppAccounts/backupVaults/backups", - "apiVersion": "2024-07-01", - "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]", - "properties": { - "label": "[parameters('label')]", - "snapshotName": "[parameters('snapshotName')]", - "volumeResourceId": "[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools/volumes', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('volumeName'))]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the backup." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The Resource ID of the backup." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults/backups', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the backup was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "backupVault" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the backup vault." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The Resource ID of the backup vault." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupVaults', parameters('netAppAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the backup vault was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('backupVault', '2024-07-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "netAppAccount", - "netAppAccount_capacityPools" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the NetApp account." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The Resource ID of the NetApp account." - }, - "value": "[resourceId('Microsoft.NetApp/netAppAccounts', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the NetApp account was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('netAppAccount', '2024-07-01', 'full').location]" - }, - "capacityPoolResourceIds": { - "type": "array", - "items": { - "type": "object", - "properties": { - "resourceId": { - "type": "string" - }, - "volumeResourceIds": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "metadata": { - "description": "The resource IDs of the created capacity pools & their volumes." - }, - "copy": { - "count": "[length(coalesce(parameters('capacityPools'), createArray()))]", - "input": { - "resourceId": "[reference(format('netAppAccount_capacityPools[{0}]', copyIndex())).outputs.resourceId.value]", - "volumeResourceIds": "[reference(format('netAppAccount_capacityPools[{0}]', copyIndex())).outputs.volumeResourceIds.value]" - } - } - } - } - } - } - } - ], - "outputs": { - "anfFslogixVolumeResourceId": { - "type": "string", - "value": "[if(parameters('createFslogixStorage'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.capacityPoolResourceIds.value[0].volumeResourceIds[0], '')]" - }, - "anfAppAttachVolumeResourceId": { - "type": "string", - "value": "[if(and(parameters('createAppAttachStorage'), parameters('createFslogixStorage')), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.capacityPoolResourceIds.value[1].volumeResourceIds[1], if(and(parameters('createAppAttachStorage'), not(parameters('createFslogixStorage'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.capacityPoolResourceIds.value[0].volumeResourceIds[0], ''))]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]" - ] - }, - { - "condition": "[equals(parameters('storageService'), 'ANF')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Get-ANF-SMB-Server-FQDN-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "netAppVolumeResourceId": "[if(and(parameters('createFslogixDeployment'), equals(parameters('storageService'), 'ANF')), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfFslogixVolumeResourceId.value), if(and(parameters('createAppAttachDeployment'), equals(parameters('storageService'), 'ANF')), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfAppAttachVolumeResourceId.value), createObject('value', '')))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "1092509597594508559" - }, - "name": "AVD LZA storage ANF volume SMB server FQDN", - "description": "This module returns the SMB server FQDN of an ANF volume.", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "netAppVolumeResourceId": { - "type": "string" - } - }, - "resources": [], - "outputs": { - "anfSmbServerFqdn": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('netAppVolumeResourceId'), '/')[2], split(parameters('netAppVolumeResourceId'), '/')[4]), 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', split(parameters('netAppVolumeResourceId'), '/')[8], split(parameters('netAppVolumeResourceId'), '/')[10], last(split(parameters('netAppVolumeResourceId'), '/'))), '2024-09-01').mountTargets[0].smbServerFqdn]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time')))]" - ] - }, - { - "condition": "[and(parameters('createFslogixDeployment'), not(equals(parameters('storageService'), 'ANF')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-FSLogix-ST-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storagePurpose": { - "value": "fslogix" - }, - "vmLocalUserName": { - "value": "[parameters('vmLocalUserName')]" - }, - "fileShareName": { - "value": "[variables('varFslogixFileShareName')]" - }, - "fileShareMultichannel": "[if(equals(variables('varFslogixStoragePerformance'), 'Premium'), createObject('value', true()), createObject('value', false()))]", - "storageSku": { - "value": "[variables('varFslogixStorageSku')]" - }, - "fileShareQuotaSize": { - "value": "[parameters('fslogixFileShareQuotaSize')]" - }, - "storageAccountFqdn": { - "value": "[variables('varFslogixStorageFqdn')]" - }, - "storageAccountName": { - "value": "[variables('varFslogixStorageName')]" - }, - "storageToDomainScript": { - "value": "[variables('varStorageToDomainScript')]" - }, - "storageToDomainScriptUri": { - "value": "[variables('varStorageToDomainScriptUri')]" - }, - "identityServiceProvider": { - "value": "[parameters('identityServiceProvider')]" - }, - "dscAgentPackageLocation": { - "value": "[variables('varStorageAzureFilesDscAgentPackageLocation')]" - }, - "storageCustomOuPath": { - "value": "[variables('varStorageCustomOuPath')]" - }, - "managementVmName": { - "value": "[variables('varManagementVmName')]" - }, - "deployPrivateEndpoint": { - "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" - }, - "keyVaultResourceId": { - "value": "[parameters('keyVaultResourceId')]" - }, - "storageOuPath": { - "value": "[variables('varOuStgPath')]" - }, - "managedIdentityClientId": { - "value": "[parameters('managedIdentityClientId')]" - }, - "securityPrincipalName": { - "value": "[parameters('securityPrincipalName')]" - }, - "domainJoinUserName": { - "value": "[parameters('domainJoinUserName')]" - }, - "serviceObjectsRgName": { - "value": "[parameters('serviceObjectsRgName')]" - }, - "identityDomainName": { - "value": "[parameters('identityDomainName')]" - }, - "identityDomainGuid": { - "value": "[parameters('identityDomainGuid')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "storageObjectsRgName": { - "value": "[parameters('storageObjectsRgName')]" - }, - "privateEndpointSubnetResourceId": { - "value": "[parameters('privateEndpointSubnetResourceId')]" - }, - "vmsSubnetResourceId": { - "value": "[parameters('vmsSubnetResourceId')]" - }, - "privateDnsZoneFilesResourceId": { - "value": "[parameters('privateDnsZoneFilesResourceId')]" - }, - "subId": { - "value": "[parameters('subId')]" - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]", - "alaWorkspaceResourceId": { - "value": "[parameters('alaWorkspaceResourceId')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4958601852198550361" - }, - "name": "AVD LZA storage", - "description": "This module deploys storage account, azure files. domain join logic", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "subId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "storageObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group Name for Azure Files." - } - }, - "identityServiceProvider": { - "type": "string", - "metadata": { - "description": "Required, The service providing domain services for Azure Virtual Desktop." - } - }, - "serviceObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group Name for management VM." - } - }, - "storageAccountName": { - "type": "string", - "metadata": { - "description": "Storage account name." - } - }, - "fileShareName": { - "type": "string", - "metadata": { - "description": "Storage account file share name." - } - }, - "privateEndpointSubnetResourceId": { - "type": "string", - "metadata": { - "description": "Private endpoint subnet ID." - } - }, - "vmsSubnetResourceId": { - "type": "string", - "metadata": { - "description": "VMs subnet ID." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy resources." - } - }, - "fileShareMultichannel": { - "type": "bool", - "metadata": { - "description": "File share SMB multichannel." - } - }, - "identityDomainName": { - "type": "string", - "metadata": { - "description": "Identity domain name." - } - }, - "identityDomainGuid": { - "type": "string", - "metadata": { - "description": "AD domain GUID." - } - }, - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Key Vault Resource ID." - } - }, - "domainJoinUserName": { - "type": "string", - "metadata": { - "description": "AVD session host domain join credentials." - } - }, - "vmLocalUserName": { - "type": "string", - "metadata": { - "description": "AVD session host local admin credentials." - } - }, - "storageSku": { - "type": "string", - "metadata": { - "description": "Azure Files storage account SKU." - } - }, - "fileShareQuotaSize": { - "type": "int", - "metadata": { - "description": "*Azure File share quota" - } - }, - "privateDnsZoneFilesResourceId": { - "type": "string", - "metadata": { - "description": "Use Azure private DNS zones for private endpoints." - } - }, - "storageToDomainScript": { - "type": "string", - "metadata": { - "description": "Script name for adding storage account to Active Directory." - } - }, - "storageToDomainScriptUri": { - "type": "string", - "metadata": { - "description": "URI for the script for adding the storage account to Active Directory." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "managementVmName": { - "type": "string", - "metadata": { - "description": "Name for management virtual machine. for tools and to join Azure Files to domain." - } - }, - "deployPrivateEndpoint": { - "type": "bool", - "metadata": { - "description": "Optional. AVD Accelerator will deploy with private endpoints by default." - } - }, - "alaWorkspaceResourceId": { - "type": "string", - "metadata": { - "description": "Log analytics workspace for diagnostic logs." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - }, - "storagePurpose": { - "type": "string", - "metadata": { - "description": "Sets purpose of the storage account." - } - }, - "dscAgentPackageLocation": { - "type": "string", - "metadata": { - "description": "Sets location of DSC Agent." - } - }, - "storageCustomOuPath": { - "type": "string", - "metadata": { - "description": "Custom OU path for storage." - } - }, - "storageOuPath": { - "type": "string", - "metadata": { - "description": "OU Storage Path" - } - }, - "managedIdentityClientId": { - "type": "string", - "metadata": { - "description": "Managed Identity Client ID" - } - }, - "securityPrincipalName": { - "type": "string", - "metadata": { - "description": "Identity name array to grant RBAC role to access AVD application group and NTFS permissions." - } - }, - "storageAccountFqdn": { - "type": "string", - "metadata": { - "description": "storage account FDQN." - } - } - }, - "variables": { - "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", - "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", - "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]", - "varAzureCloudName": "[environment().name]", - "varWrklStoragePrivateEndpointName": "[format('pe-{0}-file', parameters('storageAccountName'))]", - "varSecurityPrincipalName": "[if(not(empty(parameters('securityPrincipalName'))), parameters('securityPrincipalName'), 'none')]", - "varAdminUserName": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('vmLocalUserName'), parameters('domainJoinUserName'))]", - "varStorageToDomainScriptArgs": "[format('-DscPath {0} -StorageAccountName {1} -StorageAccountRG {2} -StoragePurpose {3} -DomainName {4} -IdentityServiceProvider {5} -AzureCloudEnvironment {6} -SubscriptionId {7} -AdminUserName {8} -CustomOuPath {9} -OUName {10} -ShareName {11} -ClientId {12} -SecurityPrincipalName \"{13}\" -StorageAccountFqdn {14} ', parameters('dscAgentPackageLocation'), parameters('storageAccountName'), parameters('storageObjectsRgName'), parameters('storagePurpose'), parameters('identityDomainName'), parameters('identityServiceProvider'), variables('varAzureCloudName'), parameters('subId'), variables('varAdminUserName'), parameters('storageCustomOuPath'), parameters('storageOuPath'), parameters('fileShareName'), parameters('managedIdentityClientId'), variables('varSecurityPrincipalName'), parameters('storageAccountFqdn'))]", - "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]" - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subId'))]", - "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('storageAccountName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "skuName": { - "value": "[parameters('storageSku')]" - }, - "allowBlobPublicAccess": { - "value": false - }, - "publicNetworkAccess": "[if(parameters('deployPrivateEndpoint'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "kind": "[if(or(equals(parameters('storageSku'), 'Premium_LRS'), equals(parameters('storageSku'), 'Premium_ZRS')), createObject('value', 'FileStorage'), createObject('value', 'StorageV2'))]", - "largeFileSharesState": "[if(or(equals(parameters('storageSku'), 'Standard_LRS'), equals(parameters('storageSku'), 'Standard_ZRS')), createObject('value', 'Enabled'), createObject('value', 'Disabled'))]", - "azureFilesIdentityBasedAuthentication": "[if(not(equals(parameters('identityServiceProvider'), 'EntraID')), createObject('value', createObject('directoryServiceOptions', if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDS', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), 'AADKERB', 'none')), 'activeDirectoryProperties', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), createObject('domainGuid', parameters('identityDomainGuid'), 'domainName', parameters('identityDomainName')), createObject()))), createObject('value', null()))]", - "accessTier": { - "value": "Hot" - }, - "networkAcls": "[if(parameters('deployPrivateEndpoint'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', parameters('vmsSubnetResourceId'), 'action', 'Allow')), 'ipRules', createArray())))]", - "fileServices": { - "value": { - "shares": [ - { - "name": "[parameters('fileShareName')]", - "shareQuota": "[parameters('fileShareQuotaSize')]" - } - ], - "protocolSettings": "[if(parameters('fileShareMultichannel'), createObject('smb', createObject('multichannel', createObject('enabled', parameters('fileShareMultichannel')))), createObject())]", - "diagnosticSettings": "[variables('varDiagnosticSettings')]" - } - }, - "privateEndpoints": "[if(parameters('deployPrivateEndpoint'), createObject('value', createArray(createObject('name', variables('varWrklStoragePrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklStoragePrivateEndpointName')), 'service', 'file', 'privateDnsZoneGroupName', split(parameters('privateDnsZoneFilesResourceId'), '/')[8], 'privateDnsZoneResourceIds', createArray(parameters('privateDnsZoneFilesResourceId'))))), createObject('value', createArray()))]", - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "15994741654178645865" - }, - "name": "Storage Accounts", - "description": "This module deploys a Storage Account.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "managedIdentitiesType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } - } - }, - "nullable": true - }, - "networkAclsType": { - "type": "object", - "properties": { - "resourceAccessRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "metadata": { - "description": "Required. The ID of the tenant in which the resource resides in." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." - } - }, - "bypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "AzureServices, Logging", - "AzureServices, Logging, Metrics", - "AzureServices, Metrics", - "Logging", - "Logging, Metrics", - "Metrics", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." - } - }, - "virtualNetworkRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the virtual network rules." - } - }, - "ipRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the IP ACL rules." - } - }, - "defaultAction": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the default action of allow or deny when no other rules match." - } - } - } - }, - "privateEndpointType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - } - }, - "nullable": true - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. Name of the Storage Account. Must be lower-case." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "kind": { - "type": "string", - "defaultValue": "StorageV2", - "allowedValues": [ - "Storage", - "StorageV2", - "BlobStorage", - "FileStorage", - "BlockBlobStorage" - ], - "metadata": { - "description": "Optional. Type of Storage Account to create." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Standard_GRS", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS", - "Standard_RAGRS", - "Standard_ZRS", - "Premium_LRS", - "Premium_ZRS", - "Standard_GZRS", - "Standard_RAGZRS" - ], - "metadata": { - "description": "Optional. Storage Account Sku Name." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "Hot", - "allowedValues": [ - "Premium", - "Hot", - "Cool" - ], - "metadata": { - "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." - } - }, - "largeFileSharesState": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." - } - }, - "azureFilesIdentityBasedAuthentication": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Provides the identity based authentication settings for Azure Files." - } - }, - "defaultToOAuthAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." - } - }, - "allowSharedKeyAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." - } - }, - "privateEndpoints": { - "$ref": "#/definitions/privateEndpointType", - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "managementPolicyRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The Storage Account ManagementPolicies Rules." - } - }, - "networkAcls": { - "$ref": "#/definitions/networkAclsType", - "nullable": true, - "metadata": { - "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." - } - }, - "requireInfrastructureEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." - } - }, - "allowCrossTenantReplication": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allow or disallow cross AAD tenant object replication." - } - }, - "customDomainName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." - } - }, - "customDomainUseSubDomainName": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." - } - }, - "dnsEndpointType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "AzureDnsZone", - "Standard" - ], - "metadata": { - "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." - } - }, - "blobServices": { - "type": "object", - "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", - "metadata": { - "description": "Optional. Blob service and containers to deploy." - } - }, - "fileServices": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. File service and shares to deploy." - } - }, - "queueServices": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Queue service and queues to create." - } - }, - "tableServices": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Table service and tables to create." - } - }, - "allowBlobPublicAccess": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." - } - }, - "minimumTlsVersion": { - "type": "string", - "defaultValue": "TLS1_2", - "allowedValues": [ - "TLS1_0", - "TLS1_1", - "TLS1_2" - ], - "metadata": { - "description": "Optional. Set the minimum TLS version on request to storage." - } - }, - "enableHierarchicalNamespace": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." - } - }, - "enableSftp": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." - } - }, - "isLocalUserEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables local users feature, if set to true." - } - }, - "enableNfsV3": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "allowedCopyScope": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "AAD", - "PrivateLink" - ], - "metadata": { - "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." - } - }, - "supportsHttpsTrafficOnly": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "sasExpirationPeriod": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The SAS expiration period. DD.HH:MM:SS." - } - }, - "keyType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Account", - "Service" - ], - "metadata": { - "description": "Optional. The keyType to use with Queue & Table services." - } - } - }, - "variables": { - "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" - }, - "storageAccount": { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2022-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "kind": "[parameters('kind')]", - "sku": { - "name": "[parameters('skuName')]" - }, - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "properties": { - "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", - "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", - "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", - "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", - "customDomain": { - "name": "[parameters('customDomainName')]", - "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" - }, - "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", - "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", - "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", - "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", - "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", - "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", - "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", - "isSftpEnabled": "[parameters('enableSftp')]", - "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", - "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", - "minimumTlsVersion": "[parameters('minimumTlsVersion')]", - "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", - "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", - "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" - }, - "dependsOn": [ - "cMKKeyVault", - "cMKKeyVault::cMKKey" - ] - }, - "storageAccount_diagnosticSettings": { - "copy": { - "name": "storageAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_privateEndpoints": { - "copy": { - "name": "storageAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" - }, - "privateDnsZoneGroupName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" - }, - "privateDnsZoneResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "4120048060064073955" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "ipConfigurationsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true - }, - "manualPrivateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "privateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "customDnsConfigType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "$ref": "#/definitions/ipConfigurationsType", - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "$ref": "#/definitions/customDnsConfigType", - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", - "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." - } - }, - "privateLinkServiceConnections": { - "$ref": "#/definitions/privateLinkServiceConnectionsType", - "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" - }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "11244630631275470040" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDNSResourceIds": { - "type": "array", - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", - "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" - } - } - } - ] - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" - }, - "groupId": { - "type": "string", - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_fileServices": { - "condition": "[not(empty(parameters('fileServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" - }, - "protocolSettings": { - "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" - }, - "shareDeleteRetentionPolicy": { - "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" - }, - "shares": { - "value": "[tryGet(parameters('fileServices'), 'shares')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "5572402757180298542" - }, - "name": "Storage Account File Share Services", - "description": "This module deploys a Storage Account File Share Service.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the file service." - } - }, - "protocolSettings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Protocol settings for file service." - } - }, - "shareDeleteRetentionPolicy": { - "type": "object", - "defaultValue": { - "enabled": true, - "days": 7 - }, - "metadata": { - "description": "Optional. The service properties for soft delete." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "shares": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. File shares to create." - } - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-04-01", - "name": "[parameters('storageAccountName')]" - }, - "fileServices": { - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "protocolSettings": "[parameters('protocolSettings')]", - "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" - } - }, - "fileServices_diagnosticSettings": { - "copy": { - "name": "fileServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "fileServices" - ] - }, - "fileServices_shares": { - "copy": { - "name": "fileServices_shares", - "count": "[length(coalesce(parameters('shares'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "fileServicesName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" - }, - "accessTier": { - "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" - }, - "enabledProtocols": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" - }, - "rootSquash": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" - }, - "shareQuota": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "2846593244669729605" - }, - "name": "Storage Account File Shares", - "description": "This module deploys a Storage Account File Share.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "fileServicesName": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share to create." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "TransactionOptimized", - "allowedValues": [ - "Premium", - "Hot", - "Cool", - "TransactionOptimized" - ], - "metadata": { - "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." - } - }, - "shareQuota": { - "type": "int", - "defaultValue": 5120, - "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." - } - }, - "enabledProtocols": { - "type": "string", - "defaultValue": "SMB", - "allowedValues": [ - "NFS", - "SMB" - ], - "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." - } - }, - "rootSquash": { - "type": "string", - "defaultValue": "NoRootSquash", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], - "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "resources": { - "storageAccount::fileService": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" - }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-04-01", - "name": "[parameters('storageAccountName')]" - }, - "fileShare": { - "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2023-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", - "properties": { - "accessTier": "[parameters('accessTier')]", - "shareQuota": "[parameters('shareQuota')]", - "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", - "enabledProtocols": "[parameters('enabledProtocols')]" - } - }, - "fileShare_roleAssignments": { - "condition": "[not(empty(parameters('roleAssignments')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "fileShareResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" - }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "11422901802944437310" - } - }, - "parameters": { - "roleAssignments": { - "type": "array", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "fileShareResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the file share to assign the roles to." - } - } - }, - "variables": { - "$fxv#0": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "scope": { - "type": "string", - "metadata": { - "description": "Required. The scope to deploy the role assignment to." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The role definition Id to assign." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "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\"" - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "defaultValue": "2.0", - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[[parameters('scope')]", - "name": "[[parameters('name')]", - "properties": { - "roleDefinitionId": "[[parameters('roleDefinitionId')]", - "principalId": "[[parameters('principalId')]", - "description": "[[parameters('description')]", - "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", - "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" - } - } - ] - }, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": [ - { - "copy": { - "name": "fileShare_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2021-04-01", - "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "mode": "Incremental", - "expressionEvaluationOptions": { - "scope": "Outer" - }, - "template": "[variables('$fxv#0')]", - "parameters": { - "scope": { - "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" - }, - "name": { - "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" - }, - "roleDefinitionId": { - "value": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]" - }, - "principalId": { - "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" - }, - "principalType": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" - }, - "description": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" - }, - "condition": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" - }, - "conditionVersion": { - "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" - }, - "delegatedManagedIdentityResourceId": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - } - } - } - } - ] - } - }, - "dependsOn": [ - "fileShare" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed file share." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed file share." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed file share." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "fileServices", - "storageAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed file share service." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed file share service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed file share service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed storage account." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed storage account." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed storage account." - }, - "value": "[resourceGroup().name]" - }, - "primaryBlobEndpoint": { - "type": "string", - "metadata": { - "description": "The primary blob endpoint reference if blob services are deployed." - }, - "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('storageAccount', '2022-09-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[not(equals(parameters('identityServiceProvider'), 'EntraID'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Add-{0}-Storage-Setup-{1}', parameters('storagePurpose'), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "virtualMachineName": { - "value": "[parameters('managementVmName')]" - }, - "file": { - "value": "[parameters('storageToDomainScript')]" - }, - "scriptArguments": { - "value": "[variables('varStorageToDomainScriptArgs')]" - }, - "adminUserPassword": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'vmLocalUserPassword')), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'domainJoinUserPassword')))]", - "baseScriptUri": { - "value": "[parameters('storageToDomainScriptUri')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "7337889415739790800" - }, - "name": "AVD LZA storage", - "description": "Configures domain join settings on storage account via VM custom script extension", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Virtual machine name." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy compute services." - } - }, - "baseScriptUri": { - "type": "string", - "metadata": { - "description": "Location for the AVD agent installation package." - } - }, - "file": { - "type": "string" - }, - "scriptArguments": { - "type": "string", - "metadata": { - "description": "Arguments for domain join script." - } - }, - "adminUserPassword": { - "type": "securestring", - "metadata": { - "description": "Domain join user password." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - } - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('VM-Ext-AVM-{0}', parameters('time'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "AzureFilesDomainJoin" - }, - "virtualMachineName": { - "value": "[parameters('virtualMachineName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "CustomScriptExtension" - }, - "typeHandlerVersion": { - "value": "1.10" - }, - "autoUpgradeMinorVersion": { - "value": true - }, - "enableAutomaticUpgrade": { - "value": false - }, - "settings": { - "value": {} - }, - "protectedSettings": { - "value": { - "fileUris": "[array(parameters('baseScriptUri'))]", - "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -File {0} {1} -AdminUserPassword {2} -verbose', parameters('file'), parameters('scriptArguments'), parameters('adminUserPassword'))]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - } - } - ] - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time')))]" - ] - } - ], - "outputs": { - "storageAccountResourceId": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))), '2022-09-01').outputs.resourceId.value]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]" - ] - }, - { - "condition": "[and(parameters('createFslogixDeployment'), not(equals(parameters('storageService'), 'ANF')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-AppA-{0}', parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storagePurpose": { - "value": "AppAttach" - }, - "vmLocalUserName": { - "value": "[parameters('vmLocalUserName')]" - }, - "fileShareName": { - "value": "[variables('varAppAttachFileShareName')]" - }, - "fileShareMultichannel": "[if(equals(variables('varAppAttachStoragePerformance'), 'Premium'), createObject('value', true()), createObject('value', false()))]", - "storageSku": { - "value": "[variables('varAppAttachStorageSku')]" - }, - "fileShareQuotaSize": { - "value": "[parameters('appAttachFileShareQuotaSize')]" - }, - "storageAccountFqdn": { - "value": "[variables('varAppAttachStorageFqdn')]" - }, - "storageAccountName": { - "value": "[variables('varAppAttachStorageName')]" - }, - "storageToDomainScript": { - "value": "[variables('varStorageToDomainScript')]" - }, - "storageToDomainScriptUri": { - "value": "[variables('varStorageToDomainScriptUri')]" - }, - "identityServiceProvider": { - "value": "[parameters('identityServiceProvider')]" - }, - "dscAgentPackageLocation": { - "value": "[variables('varStorageAzureFilesDscAgentPackageLocation')]" - }, - "storageCustomOuPath": { - "value": "[variables('varStorageCustomOuPath')]" - }, - "managementVmName": { - "value": "[variables('varManagementVmName')]" - }, - "deployPrivateEndpoint": { - "value": "[parameters('deployPrivateEndpointKeyvaultStorage')]" - }, - "storageOuPath": { - "value": "[variables('varOuStgPath')]" - }, - "managedIdentityClientId": { - "value": "[parameters('managedIdentityClientId')]" - }, - "securityPrincipalName": { - "value": "[parameters('securityPrincipalName')]" - }, - "domainJoinUserName": { - "value": "[parameters('domainJoinUserName')]" - }, - "keyVaultResourceId": { - "value": "[parameters('keyVaultResourceId')]" - }, - "serviceObjectsRgName": { - "value": "[parameters('serviceObjectsRgName')]" - }, - "identityDomainName": { - "value": "[parameters('identityDomainName')]" - }, - "identityDomainGuid": { - "value": "[parameters('identityDomainGuid')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "storageObjectsRgName": { - "value": "[parameters('storageObjectsRgName')]" - }, - "privateEndpointSubnetResourceId": { - "value": "[parameters('privateEndpointSubnetResourceId')]" - }, - "vmsSubnetResourceId": { - "value": "[parameters('vmsSubnetResourceId')]" - }, - "privateDnsZoneFilesResourceId": { - "value": "[parameters('privateDnsZoneFilesResourceId')]" - }, - "subId": { - "value": "[parameters('subId')]" - }, - "tags": "[if(parameters('createResourceTags'), createObject('value', union(parameters('customResourceTags'), parameters('defaultTags'))), createObject('value', parameters('defaultTags')))]", - "alaWorkspaceResourceId": { - "value": "[parameters('alaWorkspaceResourceId')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4958601852198550361" - }, - "name": "AVD LZA storage", - "description": "This module deploys storage account, azure files. domain join logic", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "subId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "storageObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group Name for Azure Files." - } - }, - "identityServiceProvider": { - "type": "string", - "metadata": { - "description": "Required, The service providing domain services for Azure Virtual Desktop." - } - }, - "serviceObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group Name for management VM." - } - }, - "storageAccountName": { - "type": "string", - "metadata": { - "description": "Storage account name." - } - }, - "fileShareName": { - "type": "string", - "metadata": { - "description": "Storage account file share name." - } - }, - "privateEndpointSubnetResourceId": { - "type": "string", - "metadata": { - "description": "Private endpoint subnet ID." - } - }, - "vmsSubnetResourceId": { - "type": "string", - "metadata": { - "description": "VMs subnet ID." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy resources." - } - }, - "fileShareMultichannel": { - "type": "bool", - "metadata": { - "description": "File share SMB multichannel." - } - }, - "identityDomainName": { - "type": "string", - "metadata": { - "description": "Identity domain name." - } - }, - "identityDomainGuid": { - "type": "string", - "metadata": { - "description": "AD domain GUID." - } - }, - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Key Vault Resource ID." - } - }, - "domainJoinUserName": { - "type": "string", - "metadata": { - "description": "AVD session host domain join credentials." - } - }, - "vmLocalUserName": { - "type": "string", - "metadata": { - "description": "AVD session host local admin credentials." - } - }, - "storageSku": { - "type": "string", - "metadata": { - "description": "Azure Files storage account SKU." - } - }, - "fileShareQuotaSize": { - "type": "int", - "metadata": { - "description": "*Azure File share quota" - } - }, - "privateDnsZoneFilesResourceId": { - "type": "string", - "metadata": { - "description": "Use Azure private DNS zones for private endpoints." - } - }, - "storageToDomainScript": { - "type": "string", - "metadata": { - "description": "Script name for adding storage account to Active Directory." - } - }, - "storageToDomainScriptUri": { - "type": "string", - "metadata": { - "description": "URI for the script for adding the storage account to Active Directory." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "managementVmName": { - "type": "string", - "metadata": { - "description": "Name for management virtual machine. for tools and to join Azure Files to domain." - } - }, - "deployPrivateEndpoint": { - "type": "bool", - "metadata": { - "description": "Optional. AVD Accelerator will deploy with private endpoints by default." - } - }, - "alaWorkspaceResourceId": { - "type": "string", - "metadata": { - "description": "Log analytics workspace for diagnostic logs." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - }, - "storagePurpose": { - "type": "string", - "metadata": { - "description": "Sets purpose of the storage account." - } - }, - "dscAgentPackageLocation": { - "type": "string", - "metadata": { - "description": "Sets location of DSC Agent." - } - }, - "storageCustomOuPath": { - "type": "string", - "metadata": { - "description": "Custom OU path for storage." - } - }, - "storageOuPath": { - "type": "string", - "metadata": { - "description": "OU Storage Path" - } - }, - "managedIdentityClientId": { - "type": "string", - "metadata": { - "description": "Managed Identity Client ID" - } - }, - "securityPrincipalName": { - "type": "string", - "metadata": { - "description": "Identity name array to grant RBAC role to access AVD application group and NTFS permissions." - } - }, - "storageAccountFqdn": { - "type": "string", - "metadata": { - "description": "storage account FDQN." - } - } - }, - "variables": { - "varKeyVaultSubId": "[split(parameters('keyVaultResourceId'), '/')[2]]", - "varKeyVaultRgName": "[split(parameters('keyVaultResourceId'), '/')[4]]", - "varKeyVaultName": "[split(parameters('keyVaultResourceId'), '/')[8]]", - "varAzureCloudName": "[environment().name]", - "varWrklStoragePrivateEndpointName": "[format('pe-{0}-file', parameters('storageAccountName'))]", - "varSecurityPrincipalName": "[if(not(empty(parameters('securityPrincipalName'))), parameters('securityPrincipalName'), 'none')]", - "varAdminUserName": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('vmLocalUserName'), parameters('domainJoinUserName'))]", - "varStorageToDomainScriptArgs": "[format('-DscPath {0} -StorageAccountName {1} -StorageAccountRG {2} -StoragePurpose {3} -DomainName {4} -IdentityServiceProvider {5} -AzureCloudEnvironment {6} -SubscriptionId {7} -AdminUserName {8} -CustomOuPath {9} -OUName {10} -ShareName {11} -ClientId {12} -SecurityPrincipalName \"{13}\" -StorageAccountFqdn {14} ', parameters('dscAgentPackageLocation'), parameters('storageAccountName'), parameters('storageObjectsRgName'), parameters('storagePurpose'), parameters('identityDomainName'), parameters('identityServiceProvider'), variables('varAzureCloudName'), parameters('subId'), variables('varAdminUserName'), parameters('storageCustomOuPath'), parameters('storageOuPath'), parameters('fileShareName'), parameters('managedIdentityClientId'), variables('varSecurityPrincipalName'), parameters('storageAccountFqdn'))]", - "varDiagnosticSettings": "[if(not(empty(parameters('alaWorkspaceResourceId'))), createArray(createObject('workspaceResourceId', parameters('alaWorkspaceResourceId'), 'logCategoriesAndGroups', createArray())), createArray())]" - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subId'))]", - "resourceGroup": "[format('{0}', parameters('storageObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('storageAccountName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "skuName": { - "value": "[parameters('storageSku')]" - }, - "allowBlobPublicAccess": { - "value": false - }, - "publicNetworkAccess": "[if(parameters('deployPrivateEndpoint'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "kind": "[if(or(equals(parameters('storageSku'), 'Premium_LRS'), equals(parameters('storageSku'), 'Premium_ZRS')), createObject('value', 'FileStorage'), createObject('value', 'StorageV2'))]", - "largeFileSharesState": "[if(or(equals(parameters('storageSku'), 'Standard_LRS'), equals(parameters('storageSku'), 'Standard_ZRS')), createObject('value', 'Enabled'), createObject('value', 'Disabled'))]", - "azureFilesIdentityBasedAuthentication": "[if(not(equals(parameters('identityServiceProvider'), 'EntraID')), createObject('value', createObject('directoryServiceOptions', if(equals(parameters('identityServiceProvider'), 'EntraDS'), 'AADDS', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), 'AADKERB', 'none')), 'activeDirectoryProperties', if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), createObject('domainGuid', parameters('identityDomainGuid'), 'domainName', parameters('identityDomainName')), createObject()))), createObject('value', null()))]", - "accessTier": { - "value": "Hot" - }, - "networkAcls": "[if(parameters('deployPrivateEndpoint'), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(), 'ipRules', createArray())), createObject('value', createObject('bypass', 'AzureServices', 'defaultAction', 'Deny', 'virtualNetworkRules', createArray(createObject('id', parameters('vmsSubnetResourceId'), 'action', 'Allow')), 'ipRules', createArray())))]", - "fileServices": { - "value": { - "shares": [ - { - "name": "[parameters('fileShareName')]", - "shareQuota": "[parameters('fileShareQuotaSize')]" - } - ], - "protocolSettings": "[if(parameters('fileShareMultichannel'), createObject('smb', createObject('multichannel', createObject('enabled', parameters('fileShareMultichannel')))), createObject())]", - "diagnosticSettings": "[variables('varDiagnosticSettings')]" - } - }, - "privateEndpoints": "[if(parameters('deployPrivateEndpoint'), createObject('value', createArray(createObject('name', variables('varWrklStoragePrivateEndpointName'), 'subnetResourceId', parameters('privateEndpointSubnetResourceId'), 'customNetworkInterfaceName', format('nic-01-{0}', variables('varWrklStoragePrivateEndpointName')), 'service', 'file', 'privateDnsZoneGroupName', split(parameters('privateDnsZoneFilesResourceId'), '/')[8], 'privateDnsZoneResourceIds', createArray(parameters('privateDnsZoneFilesResourceId'))))), createObject('value', createArray()))]", - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[variables('varDiagnosticSettings')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "15994741654178645865" - }, - "name": "Storage Accounts", - "description": "This module deploys a Storage Account.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "managedIdentitiesType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } - } - }, - "nullable": true - }, - "networkAclsType": { - "type": "object", - "properties": { - "resourceAccessRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tenantId": { - "type": "string", - "metadata": { - "description": "Required. The ID of the tenant in which the resource resides in." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." - } - }, - "bypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "AzureServices, Logging", - "AzureServices, Logging, Metrics", - "AzureServices, Metrics", - "Logging", - "Logging, Metrics", - "Metrics", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." - } - }, - "virtualNetworkRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the virtual network rules." - } - }, - "ipRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Sets the IP ACL rules." - } - }, - "defaultAction": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the default action of allow or deny when no other rules match." - } - } - } - }, - "privateEndpointType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint ip address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private ip addresses of the private endpoint." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private ip address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - } - }, - "nullable": true - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Required. Name of the Storage Account. Must be lower-case." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "kind": { - "type": "string", - "defaultValue": "StorageV2", - "allowedValues": [ - "Storage", - "StorageV2", - "BlobStorage", - "FileStorage", - "BlockBlobStorage" - ], - "metadata": { - "description": "Optional. Type of Storage Account to create." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Standard_GRS", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS", - "Standard_RAGRS", - "Standard_ZRS", - "Premium_LRS", - "Premium_ZRS", - "Standard_GZRS", - "Standard_RAGZRS" - ], - "metadata": { - "description": "Optional. Storage Account Sku Name." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "Hot", - "allowedValues": [ - "Premium", - "Hot", - "Cool" - ], - "metadata": { - "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." - } - }, - "largeFileSharesState": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." - } - }, - "azureFilesIdentityBasedAuthentication": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Provides the identity based authentication settings for Azure Files." - } - }, - "defaultToOAuthAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." - } - }, - "allowSharedKeyAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." - } - }, - "privateEndpoints": { - "$ref": "#/definitions/privateEndpointType", - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "managementPolicyRules": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The Storage Account ManagementPolicies Rules." - } - }, - "networkAcls": { - "$ref": "#/definitions/networkAclsType", - "nullable": true, - "metadata": { - "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." - } - }, - "requireInfrastructureEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." - } - }, - "allowCrossTenantReplication": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allow or disallow cross AAD tenant object replication." - } - }, - "customDomainName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." - } - }, - "customDomainUseSubDomainName": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." - } - }, - "dnsEndpointType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "AzureDnsZone", - "Standard" - ], - "metadata": { - "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." - } - }, - "blobServices": { - "type": "object", - "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", - "metadata": { - "description": "Optional. Blob service and containers to deploy." - } - }, - "fileServices": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. File service and shares to deploy." - } - }, - "queueServices": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Queue service and queues to create." - } - }, - "tableServices": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Table service and tables to create." - } - }, - "allowBlobPublicAccess": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." - } - }, - "minimumTlsVersion": { - "type": "string", - "defaultValue": "TLS1_2", - "allowedValues": [ - "TLS1_0", - "TLS1_1", - "TLS1_2" - ], - "metadata": { - "description": "Optional. Set the minimum TLS version on request to storage." - } - }, - "enableHierarchicalNamespace": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." - } - }, - "enableSftp": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." - } - }, - "isLocalUserEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables local users feature, if set to true." - } - }, - "enableNfsV3": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "allowedCopyScope": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "AAD", - "PrivateLink" - ], - "metadata": { - "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." - } - }, - "supportsHttpsTrafficOnly": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "sasExpirationPeriod": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The SAS expiration period. DD.HH:MM:SS." - } - }, - "keyType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Account", - "Service" - ], - "metadata": { - "description": "Optional. The keyType to use with Queue & Table services." - } - } - }, - "variables": { - "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-02-01", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", - "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", - "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" - }, - "storageAccount": { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2022-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "kind": "[parameters('kind')]", - "sku": { - "name": "[parameters('skuName')]" - }, - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "properties": { - "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", - "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", - "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", - "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", - "customDomain": { - "name": "[parameters('customDomainName')]", - "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" - }, - "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", - "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", - "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", - "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", - "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", - "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", - "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", - "isSftpEnabled": "[parameters('enableSftp')]", - "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", - "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", - "minimumTlsVersion": "[parameters('minimumTlsVersion')]", - "networkAcls": "[if(not(empty(parameters('networkAcls'))), createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", - "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", - "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" - }, - "dependsOn": [ - "cMKKeyVault", - "cMKKeyVault::cMKKey" - ] - }, - "storageAccount_diagnosticSettings": { - "copy": { - "name": "storageAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_privateEndpoints": { - "copy": { - "name": "storageAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2024-03-01', 'Full').location)]" - }, - "privateDnsZoneGroupName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" - }, - "privateDnsZoneResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "4120048060064073955" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "ipConfigurationsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - } - }, - "nullable": true - }, - "manualPrivateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "privateLinkServiceConnectionsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - } - }, - "nullable": true - }, - "customDnsConfigType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "$ref": "#/definitions/ipConfigurationsType", - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroupName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." - } - }, - "privateDnsZoneResourceIds": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "$ref": "#/definitions/customDnsConfigType", - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", - "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." - } - }, - "privateLinkServiceConnections": { - "$ref": "#/definitions/privateLinkServiceConnectionsType", - "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" - }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" - }, - "privateEndpointName": { - "value": "[parameters('name')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "11244630631275470040" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "privateEndpointName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." - } - }, - "privateDNSResourceIds": { - "type": "array", - "minLength": 1, - "maxLength": 5, - "metadata": { - "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", - "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" - } - } - } - ] - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" - }, - "groupId": { - "type": "string", - "metadata": { - "description": "The group Id for the private endpoint Group." - }, - "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - }, - "storageAccount_fileServices": { - "condition": "[not(empty(parameters('fileServices')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('name')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" - }, - "protocolSettings": { - "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" - }, - "shareDeleteRetentionPolicy": { - "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" - }, - "shares": { - "value": "[tryGet(parameters('fileServices'), 'shares')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "5572402757180298542" - }, - "name": "Storage Account File Share Services", - "description": "This module deploys a Storage Account File Share Service.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the file service." - } - }, - "protocolSettings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Protocol settings for file service." - } - }, - "shareDeleteRetentionPolicy": { - "type": "object", - "defaultValue": { - "enabled": true, - "days": 7 - }, - "metadata": { - "description": "Optional. The service properties for soft delete." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "shares": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. File shares to create." - } - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-04-01", - "name": "[parameters('storageAccountName')]" - }, - "fileServices": { - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", - "properties": { - "protocolSettings": "[parameters('protocolSettings')]", - "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" - } - }, - "fileServices_diagnosticSettings": { - "copy": { - "name": "fileServices_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "fileServices" - ] - }, - "fileServices_shares": { - "copy": { - "name": "fileServices_shares", - "count": "[length(coalesce(parameters('shares'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "storageAccountName": { - "value": "[parameters('storageAccountName')]" - }, - "fileServicesName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" - }, - "accessTier": { - "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" - }, - "enabledProtocols": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" - }, - "rootSquash": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" - }, - "shareQuota": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "2846593244669729605" - }, - "name": "Storage Account File Shares", - "description": "This module deploys a Storage Account File Share.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "storageAccountName": { - "type": "string", - "maxLength": 24, - "metadata": { - "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." - } - }, - "fileServicesName": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the file share to create." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "TransactionOptimized", - "allowedValues": [ - "Premium", - "Hot", - "Cool", - "TransactionOptimized" - ], - "metadata": { - "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." - } - }, - "shareQuota": { - "type": "int", - "defaultValue": 5120, - "metadata": { - "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." - } - }, - "enabledProtocols": { - "type": "string", - "defaultValue": "SMB", - "allowedValues": [ - "NFS", - "SMB" - ], - "metadata": { - "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." - } - }, - "rootSquash": { - "type": "string", - "defaultValue": "NoRootSquash", - "allowedValues": [ - "AllSquash", - "NoRootSquash", - "RootSquash" - ], - "metadata": { - "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "resources": { - "storageAccount::fileService": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]" - }, - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-04-01", - "name": "[parameters('storageAccountName')]" - }, - "fileShare": { - "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2023-01-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", - "properties": { - "accessTier": "[parameters('accessTier')]", - "shareQuota": "[parameters('shareQuota')]", - "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", - "enabledProtocols": "[parameters('enabledProtocols')]" - } - }, - "fileShare_roleAssignments": { - "condition": "[not(empty(parameters('roleAssignments')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "fileShareResourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" - }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "11422901802944437310" - } - }, - "parameters": { - "roleAssignments": { - "type": "array", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "fileShareResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of the file share to assign the roles to." - } - } - }, - "variables": { - "$fxv#0": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "scope": { - "type": "string", - "metadata": { - "description": "Required. The scope to deploy the role assignment to." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the role assignment." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. The role definition Id to assign." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User", - "" - ], - "defaultValue": "", - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "defaultValue": "", - "metadata": { - "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\"" - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "defaultValue": "2.0", - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[[parameters('scope')]", - "name": "[[parameters('name')]", - "properties": { - "roleDefinitionId": "[[parameters('roleDefinitionId')]", - "principalId": "[[parameters('principalId')]", - "description": "[[parameters('description')]", - "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", - "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", - "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" - } - } - ] - }, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", - "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", - "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", - "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", - "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": [ - { - "copy": { - "name": "fileShare_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2021-04-01", - "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", - "properties": { - "mode": "Incremental", - "expressionEvaluationOptions": { - "scope": "Outer" - }, - "template": "[variables('$fxv#0')]", - "parameters": { - "scope": { - "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" - }, - "name": { - "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" - }, - "roleDefinitionId": { - "value": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]" - }, - "principalId": { - "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" - }, - "principalType": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" - }, - "description": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" - }, - "condition": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" - }, - "conditionVersion": { - "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" - }, - "delegatedManagedIdentityResourceId": { - "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - } - } - } - } - ] - } - }, - "dependsOn": [ - "fileShare" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed file share." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed file share." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed file share." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "fileServices", - "storageAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed file share service." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed file share service." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed file share service." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "storageAccount" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed storage account." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed storage account." - }, - "value": "[parameters('name')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed storage account." - }, - "value": "[resourceGroup().name]" - }, - "primaryBlobEndpoint": { - "type": "string", - "metadata": { - "description": "The primary blob endpoint reference if blob services are deployed." - }, - "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('storageAccount', '2022-09-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[not(equals(parameters('identityServiceProvider'), 'EntraID'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Add-{0}-Storage-Setup-{1}', parameters('storagePurpose'), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subId'))]", - "resourceGroup": "[format('{0}', parameters('serviceObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "virtualMachineName": { - "value": "[parameters('managementVmName')]" - }, - "file": { - "value": "[parameters('storageToDomainScript')]" - }, - "scriptArguments": { - "value": "[variables('varStorageToDomainScriptArgs')]" - }, - "adminUserPassword": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'vmLocalUserPassword')), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', variables('varKeyVaultSubId')), format('{0}', variables('varKeyVaultRgName'))), 'Microsoft.KeyVault/vaults', variables('varKeyVaultName'))), 'secretName', 'domainJoinUserPassword')))]", - "baseScriptUri": { - "value": "[parameters('storageToDomainScriptUri')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "7337889415739790800" - }, - "name": "AVD LZA storage", - "description": "Configures domain join settings on storage account via VM custom script extension", - "owner": "Azure/avdaccelerator" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Virtual machine name." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy compute services." - } - }, - "baseScriptUri": { - "type": "string", - "metadata": { - "description": "Location for the AVD agent installation package." - } - }, - "file": { - "type": "string" - }, - "scriptArguments": { - "type": "string", - "metadata": { - "description": "Arguments for domain join script." - } - }, - "adminUserPassword": { - "type": "securestring", - "metadata": { - "description": "Domain join user password." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - } - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('VM-Ext-AVM-{0}', parameters('time'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "AzureFilesDomainJoin" - }, - "virtualMachineName": { - "value": "[parameters('virtualMachineName')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "CustomScriptExtension" - }, - "typeHandlerVersion": { - "value": "1.10" - }, - "autoUpgradeMinorVersion": { - "value": true - }, - "enableAutomaticUpgrade": { - "value": false - }, - "settings": { - "value": {} - }, - "protectedSettings": { - "value": { - "fileUris": "[array(parameters('baseScriptUri'))]", - "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -File {0} {1} -AdminUserPassword {2} -verbose', parameters('file'), parameters('scriptArguments'), parameters('adminUserPassword'))]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - } - } - ] - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time')))]" - ] - } - ], - "outputs": { - "storageAccountResourceId": { - "type": "string", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subId')), format('{0}', parameters('storageObjectsRgName'))), 'Microsoft.Resources/deployments', format('Storage-{0}-{1}', parameters('storagePurpose'), parameters('time'))), '2022-09-01').outputs.resourceId.value]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-MGMT-VM-{0}', parameters('time')))]" - ] - } - ], - "outputs": { - "fslogixFileSharePath": { - "type": "string", - "value": "[if(parameters('createFslogixDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('\\\\{0}.file.{1}\\{2}', variables('varFslogixStorageName'), environment().suffixes.storage, variables('varFslogixFileShareName')), if(equals(parameters('storageService'), 'ANF'), format('\\\\{0}\\{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Get-ANF-SMB-Server-FQDN-{0}', parameters('time'))), '2022-09-01').outputs.anfSmbServerFqdn.value, last(split(reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfFslogixVolumeResourceId.value, '/'))), '')), '')]" - }, - "appAttachFileSharePath": { - "type": "string", - "value": "[if(parameters('createAppAttachDeployment'), if(equals(parameters('storageService'), 'AzureFiles'), format('\\\\{0}.file.{1}\\{2}', variables('varAppAttachStorageName'), environment().suffixes.storage, variables('varAppAttachFileShareName')), if(equals(parameters('storageService'), 'ANF'), format('\\\\{0}\\{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Get-ANF-SMB-Server-FQDN-{0}', parameters('time'))), '2022-09-01').outputs.anfSmbServerFqdn.value, last(split(reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-ANF-{0}', parameters('time'))), '2022-09-01').outputs.anfAppAttachVolumeResourceId.value, '/'))), '')), '')]" - }, - "fslogixStorageAccountResourceId": { - "type": "string", - "value": "[if(and(parameters('createFslogixDeployment'), equals(parameters('storageService'), 'AzureFiles')), reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-FSLogix-ST-{0}', parameters('time'))), '2022-09-01').outputs.storageAccountResourceId.value, '')]" - }, - "appAttachStorageAccountResourceId": { - "type": "string", - "value": "[if(and(parameters('createAppAttachDeployment'), equals(parameters('storageService'), 'AzureFiles')), reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Storage-AppA-{0}', parameters('time'))), '2022-09-01').outputs.storageAccountResourceId.value, '')]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Storage-RG-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Identities-And-RoleAssign-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]", - "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time')))]" - ] - }, - { - "copy": { - "name": "sessionHosts", - "count": "[length(range(1, variables('varSessionHostBatchCount')))]", - "mode": "serial", - "batchSize": 3 - }, - "condition": "[parameters('avdDeploySessionHosts')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('SH-Batch-{0}-{1}', range(1, variables('varSessionHostBatchCount'))[copyIndex()], parameters('time'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "asgResourceId": "[if(or(or(parameters('avdDeploySessionHosts'), parameters('createFslogixDeployment')), variables('varCreateAppAttachDeployment')), createObject('value', format('{0}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.applicationSecurityGroupResourceId.value)), createObject('value', ''))]", - "availability": { - "value": "[parameters('availability')]" - }, - "availabilityZones": { - "value": "[parameters('availabilityZones')]" - }, - "batchId": { - "value": "[sub(range(1, variables('varSessionHostBatchCount'))[copyIndex()], 1)]" - }, - "computeObjectsRgName": { - "value": "[variables('varComputeObjectsRgName')]" - }, - "configureFslogix": { - "value": "[parameters('createFslogixDeployment')]" - }, - "count": "[if(and(equals(range(1, variables('varSessionHostBatchCount'))[copyIndex()], variables('varSessionHostBatchCount')), greater(variables('varMaxSessionHostsDivisionRemainderValue'), 0)), createObject('value', variables('varMaxSessionHostsDivisionRemainderValue')), createObject('value', variables('varMaxSessionHostsPerTemplate')))]", - "countIndex": "[if(equals(range(1, variables('varSessionHostBatchCount'))[copyIndex()], 1), createObject('value', parameters('avdSessionHostCountIndex')), createObject('value', add(mul(sub(range(1, variables('varSessionHostBatchCount'))[copyIndex()], 1), variables('varMaxSessionHostsPerTemplate')), parameters('avdSessionHostCountIndex'))))]", - "createIntuneEnrollment": { - "value": "[parameters('createIntuneEnrollment')]" - }, - "customImageDefinitionId": { - "value": "[parameters('avdCustomImageDefinitionId')]" - }, - "dataCollectionRuleId": "[if(parameters('avdDeployMonitoring'), createObject('value', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time'))), '2022-09-01').outputs.dataCollectionRuleId.value), createObject('value', ''))]", - "deployAntiMalwareExt": { - "value": "[parameters('deployAntiMalwareExt')]" - }, - "deployMonitoring": { - "value": "[parameters('avdDeployMonitoring')]" - }, - "diskEncryptionSetResourceId": "[if(parameters('diskZeroTrust'), createObject('value', reference(subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time'))), '2022-09-01').outputs.ztDiskEncryptionSetResourceId.value), createObject('value', ''))]", - "customOsDiskSizeGB": { - "value": "[parameters('customOsDiskSizeGB')]" - }, - "diskType": { - "value": "[parameters('avdSessionHostDiskType')]" - }, - "domainJoinUserPrincipalName": { - "value": "[parameters('avdDomainJoinUserName')]" - }, - "enableAcceleratedNetworking": { - "value": "[parameters('enableAcceleratedNetworking')]" - }, - "encryptionAtHost": { - "value": "[parameters('diskZeroTrust')]" - }, - "fslogixSharePath": "[if(parameters('createFslogixDeployment'), createObject('value', reference(subscriptionResourceId(format('{0}', parameters('avdWorkloadSubsId')), 'Microsoft.Resources/deployments', format('SMB-Storage-{0}', parameters('time'))), '2022-09-01').outputs.fslogixFileSharePath.value), createObject('value', ''))]", - "fslogixStorageAccountResourceId": "[if(and(equals(parameters('avdIdentityServiceProvider'), 'EntraID'), parameters('createFslogixDeployment')), createObject('value', reference(subscriptionResourceId(format('{0}', parameters('avdWorkloadSubsId')), 'Microsoft.Resources/deployments', format('SMB-Storage-{0}', parameters('time'))), '2022-09-01').outputs.fslogixStorageAccountResourceId.value), createObject('value', ''))]", - "hostPoolResourceId": { - "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', format('AVD-MGMT-Plane-{0}', parameters('time'))), '2022-09-01').outputs.hostPoolResourceId.value]" - }, - "identityDomainName": { - "value": "[parameters('identityDomainName')]" - }, - "identityServiceProvider": { - "value": "[parameters('avdIdentityServiceProvider')]" - }, - "keyVaultResourceId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time'))), '2022-09-01').outputs.resourceId.value]" - }, - "location": { - "value": "[parameters('avdSessionHostLocation')]" - }, - "mpImageOffer": { - "value": "[parameters('mpImageOffer')]" - }, - "mpImageSku": { - "value": "[parameters('mpImageSku')]" - }, - "namePrefix": { - "value": "[variables('varSessionHostNamePrefix')]" - }, - "secureBootEnabled": { - "value": "[parameters('secureBootEnabled')]" - }, - "securityType": "[if(equals(parameters('securityType'), 'Standard'), createObject('value', ''), createObject('value', parameters('securityType')))]", - "sessionHostConfigurationScriptUri": { - "value": "[variables('varSessionHostConfigurationScriptUri')]" - }, - "sessionHostConfigurationScript": { - "value": "[variables('varSessionHostConfigurationScript')]" - }, - "sessionHostOuPath": { - "value": "[parameters('avdOuPath')]" - }, - "subscriptionId": { - "value": "[parameters('avdWorkloadSubsId')]" - }, - "subnetId": "[if(parameters('createAvdVnet'), createObject('value', format('{0}/subnets/{1}', reference(subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time'))), '2022-09-01').outputs.virtualNetworkResourceId.value, variables('varVnetAvdSubnetName'))), createObject('value', parameters('existingVnetAvdSubnetResourceId')))]", - "tags": "[if(parameters('createResourceTags'), createObject('value', union(variables('varCustomResourceTags'), variables('varAvdDefaultTags'))), createObject('value', variables('varAvdDefaultTags')))]", - "timeZone": { - "value": "[variables('varTimeZoneSessionHosts')]" - }, - "useSharedImage": { - "value": "[parameters('useSharedImage')]" - }, - "vmSize": { - "value": "[parameters('avdSessionHostsSize')]" - }, - "vTpmEnabled": { - "value": "[parameters('vTpmEnabled')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13361150904998745536" - } - }, - "parameters": { - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy compute services." - } - }, - "computeObjectsRgName": { - "type": "string", - "metadata": { - "description": "Resource Group name for the session hosts." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "metadata": { - "description": "AVD disk encryption set resource ID to enable server side encryption." - } - }, - "subnetId": { - "type": "string", - "metadata": { - "description": "AVD subnet ID." - } - }, - "timeZone": { - "type": "string", - "metadata": { - "description": "Virtual machine time zone." - } - }, - "batchId": { - "type": "int", - "metadata": { - "description": "General session host batch identifier" - } - }, - "namePrefix": { - "type": "string", - "metadata": { - "description": "AVD Session Host prefix." - } - }, - "subscriptionId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "count": { - "type": "int", - "metadata": { - "description": "Quantity of session hosts to deploy." - } - }, - "countIndex": { - "type": "int", - "metadata": { - "description": "The session host number to begin with for the deployment." - } - }, - "availability": { - "type": "string", - "metadata": { - "description": "When true VMs are distributed across availability zones, when set to false, VMs will be deployed at regional level. (Default: true)." - } - }, - "availabilityZones": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Defines the Availability Zones for the VMs." - } - }, - "identityServiceProvider": { - "type": "string", - "metadata": { - "description": "The service providing domain services for Azure Virtual Desktop." - } - }, - "createIntuneEnrollment": { - "type": "bool", - "metadata": { - "description": "Enroll session hosts on Intune." - } - }, - "encryptionAtHost": { - "type": "bool", - "metadata": { - "description": "This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "Session host VM size." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "metadata": { - "description": "Enables accelerated Networking on the session hosts." - } - }, - "securityType": { - "type": "string", - "metadata": { - "description": "Specifies the securityType of the virtual machine. Must be TrustedLaunch or ConfidentialVM enable UefiSettings." - } - }, - "secureBootEnabled": { - "type": "bool", - "metadata": { - "description": "Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "vTpmEnabled": { - "type": "bool", - "metadata": { - "description": "Specifies whether virtual TPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. securityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "diskType": { - "type": "string", - "metadata": { - "description": "OS disk type for session host." - } - }, - "customOsDiskSizeGB": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Define custom OS disk size if larger than image size." - } - }, - "useSharedImage": { - "type": "bool", - "metadata": { - "description": "Set to deploy image from Azure Compute Gallery." - } - }, - "mpImagePublisher": { - "type": "string", - "defaultValue": "MicrosoftWindowsDesktop", - "metadata": { - "description": "AVD OS image publisher." - } - }, - "mpImageOffer": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "AVD OS image SKU." - } - }, - "mpImageSku": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "AVD OS image SKU." - } - }, - "customImageDefinitionId": { - "type": "string", - "metadata": { - "description": "Source custom image ID." - } - }, - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "The Resource ID of keyvault that contains credentials." - } - }, - "identityDomainName": { - "type": "string", - "metadata": { - "description": "Identity domain name." - } - }, - "domainJoinUserPrincipalName": { - "type": "string", - "metadata": { - "description": "AVD session host domain join credentials." - } - }, - "sessionHostOuPath": { - "type": "string", - "metadata": { - "description": "OU path to join AVd VMs." - } - }, - "asgResourceId": { - "type": "string", - "metadata": { - "description": "Application Security Group (ASG) for the session hosts." - } - }, - "configureFslogix": { - "type": "bool", - "metadata": { - "description": "Configure Fslogix on session hosts." - } - }, - "fslogixSharePath": { - "type": "string", - "metadata": { - "description": "Path for the FSlogix share." - } - }, - "fslogixStorageAccountResourceId": { - "type": "string", - "metadata": { - "description": "FSLogix storage account resource ID." - } - }, - "hostPoolResourceId": { - "type": "string", - "metadata": { - "description": "Host pool resource ID." - } - }, - "sessionHostConfigurationScriptUri": { - "type": "string", - "metadata": { - "description": "URI for AVD session host configuration script URI." - } - }, - "sessionHostConfigurationScript": { - "type": "string", - "metadata": { - "description": "URI for AVD session host configuration script." - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Tags to be applied to resources" - } - }, - "deployMonitoring": { - "type": "bool", - "metadata": { - "description": "Deploy AVD monitoring resources and setings." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - }, - "dataCollectionRuleId": { - "type": "string", - "metadata": { - "description": "Data collection rule ID." - } - }, - "deployAntiMalwareExt": { - "type": "bool", - "metadata": { - "description": "Deploys anti malware extension on session hosts." - } - } - }, - "variables": { - "copy": [ - { - "name": "varZones", - "count": "[length(parameters('availabilityZones'))]", - "input": "[int(parameters('availabilityZones')[copyIndex('varZones')])]" - } - ], - "varManagedDisk": "[if(empty(parameters('diskEncryptionSetResourceId')), createObject('storageAccountType', parameters('diskType')), createObject('diskEncryptionSetResourceId', parameters('diskEncryptionSetResourceId'), 'storageAccountType', parameters('diskType')))]", - "varOsDiskProperties": { - "createOption": "FromImage", - "deleteOption": "Delete", - "caching": "ReadWrite", - "managedDisk": "[variables('varManagedDisk')]" - }, - "varCustomOsDiskProperties": { - "createOption": "FromImage", - "deleteOption": "Delete", - "caching": "ReadWrite", - "managedDisk": "[variables('varManagedDisk')]", - "diskSizeGB": "[if(not(equals(parameters('customOsDiskSizeGB'), 0)), parameters('customOsDiskSizeGB'), null())]" - } - }, - "resources": [ - { - "copy": { - "name": "sessionHosts", - "count": "[length(range(0, parameters('count')))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('SH-{0}-{1}-{2}', add(parameters('batchId'), 1), add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}{1}', parameters('namePrefix'), padLeft(add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), 4, '0'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "timeZone": { - "value": "[parameters('timeZone')]" - }, - "zone": "[if(equals(parameters('availability'), 'AvailabilityZones'), createObject('value', variables('varZones')[mod(range(0, parameters('count'))[copyIndex()], length(variables('varZones')))]), createObject('value', 0))]", - "managedIdentities": "[if(or(contains(parameters('identityServiceProvider'), 'EntraID'), parameters('deployMonitoring')), createObject('value', createObject('systemAssigned', true())), createObject('value', null()))]", - "encryptionAtHost": { - "value": "[parameters('encryptionAtHost')]" - }, - "osType": { - "value": "Windows" - }, - "licenseType": { - "value": "Windows_Client" - }, - "vmSize": { - "value": "[parameters('vmSize')]" - }, - "securityType": "[if(equals(parameters('securityType'), 'Standard'), createObject('value', ''), createObject('value', parameters('securityType')))]", - "secureBootEnabled": { - "value": "[parameters('secureBootEnabled')]" - }, - "vTpmEnabled": { - "value": "[parameters('vTpmEnabled')]" - }, - "imageReference": "[if(parameters('useSharedImage'), createObject('value', createObject('id', parameters('customImageDefinitionId'))), createObject('value', createObject('publisher', parameters('mpImagePublisher'), 'offer', parameters('mpImageOffer'), 'sku', parameters('mpImageSku'), 'version', 'latest')))]", - "osDisk": "[if(not(equals(parameters('customOsDiskSizeGB'), 0)), createObject('value', variables('varCustomOsDiskProperties')), createObject('value', variables('varOsDiskProperties')))]", - "adminUsername": { - "reference": { - "keyVault": { - "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('keyVaultResourceId'), '/')[4]), 'Microsoft.KeyVault/vaults', last(split(parameters('keyVaultResourceId'), '/')))]" - }, - "secretName": "vmLocalUserName" - } - }, - "adminPassword": { - "reference": { - "keyVault": { - "id": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('keyVaultResourceId'), '/')[4]), 'Microsoft.KeyVault/vaults', last(split(parameters('keyVaultResourceId'), '/')))]" - }, - "secretName": "vmLocalUserPassword" - } - }, - "nicConfigurations": { - "value": [ - { - "name": "[format('nic-01-{0}{1}', parameters('namePrefix'), padLeft(add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), 4, '0'))]", - "deleteOption": "Delete", - "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", - "ipConfigurations": "[if(not(empty(parameters('asgResourceId'))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetId'), 'applicationSecurityGroups', createArray(createObject('id', parameters('asgResourceId'))))), createArray(createObject('name', 'ipconfig01', 'subnetResourceId', parameters('subnetId'))))]" - } - ] - }, - "extensionDomainJoinPassword": "[if(contains(parameters('identityServiceProvider'), 'DS'), createObject('reference', createObject('keyVault', createObject('id', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('keyVaultResourceId'), '/')[4]), 'Microsoft.KeyVault/vaults', last(split(parameters('keyVaultResourceId'), '/')))), 'secretName', 'domainJoinUserPassword')), createObject('value', null()))]", - "extensionDomainJoinConfig": "[if(contains(parameters('identityServiceProvider'), 'DS'), createObject('value', createObject('enabled', true(), 'settings', createObject('name', parameters('identityDomainName'), 'ouPath', if(not(empty(parameters('sessionHostOuPath'))), parameters('sessionHostOuPath'), null()), 'user', parameters('domainJoinUserPrincipalName'), 'restart', 'true', 'options', '3'))), createObject('value', null()))]", - "extensionAadJoinConfig": "[if(contains(parameters('identityServiceProvider'), 'EntraID'), createObject('value', createObject('enabled', if(contains(parameters('identityServiceProvider'), 'EntraID'), true(), false()), 'settings', if(parameters('createIntuneEnrollment'), createObject('mdmId', '0000000a-0000-0000-c000-000000000000'), createObject()))), createObject('value', null()))]", - "tags": { - "value": "[parameters('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13031055217657209142" - }, - "name": "Virtual Machines", - "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "managedIdentitiesType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } - } - }, - "nullable": true - }, - "osDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "metadata": { - "description": "Required. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } - } - }, - "dataDisksType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "lun": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the logical unit number of the data disk." - } - }, - "diskSizeGB": { - "type": "int", - "maxValue": 1023, - "metadata": { - "description": "Required. Specifies the size of an empty data disk in gigabytes." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "metadata": { - "description": "Required. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." - } - }, - "computerName": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "Required. Specifies the size for the VMs." - } - }, - "encryptionAtHost": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "securityType": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the SecurityType of the virtual machine. It is set as TrustedLaunch to enable UefiSettings." - } - }, - "secureBootEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "vTpmEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "imageReference": { - "type": "object", - "metadata": { - "description": "Required. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image." - } - }, - "plan": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." - } - }, - "osDisk": { - "$ref": "#/definitions/osDiskType", - "metadata": { - "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "dataDisks": { - "$ref": "#/definitions/dataDisksType", - "metadata": { - "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "ultraSSDEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." - } - }, - "adminUsername": { - "type": "securestring", - "metadata": { - "description": "Required. Administrator username." - } - }, - "adminPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. When specifying a Windows Virtual Machine, this value should be passed." - } - }, - "customData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." - } - }, - "certificatesToBeInstalled": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." - } - }, - "priority": { - "type": "string", - "defaultValue": "Regular", - "allowedValues": [ - "Regular", - "Low", - "Spot" - ], - "metadata": { - "description": "Optional. Specifies the priority for the virtual machine." - } - }, - "enableEvictionPolicy": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies the eviction policy for the low priority virtual machine. Will result in 'Deallocate' eviction policy." - } - }, - "maxPriceForLowPriorityVm": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." - } - }, - "dedicatedHostId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." - } - }, - "licenseType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "RHEL_BYOS", - "SLES_BYOS", - "Windows_Client", - "Windows_Server", - "" - ], - "metadata": { - "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", - "metadata": { - "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." - } - }, - "bootDiagnostics": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." - } - }, - "bootDiagnosticStorageAccountName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." - } - }, - "bootDiagnosticStorageAccountUri": { - "type": "string", - "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", - "metadata": { - "description": "Optional. Storage account boot diagnostic base URI." - } - }, - "proximityPlacementGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a proximity placement group." - } - }, - "virtualMachineScaleSetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." - } - }, - "availabilitySetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." - } - }, - "zone": { - "type": "int", - "allowedValues": [ - 0, - 1, - 2, - 3 - ], - "metadata": { - "description": "Required. If set to 1, 2 or 3, the availability zone for all VMs is hardcoded to that value. If zero, then availability zones is not used. Cannot be used in combination with availability set nor scale set." - } - }, - "nicConfigurations": { - "type": "array", - "metadata": { - "description": "Required. Configures NICs and PIPs." - } - }, - "allowExtensionOperations": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." - } - }, - "extensionDomainJoinPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if name is specified. Password of the user specified in user parameter." - } - }, - "extensionDomainJoinConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAadJoinConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." - } - }, - "extensionAzureDiskEncryptionConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." - } - }, - "extensionDSCConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionCustomScriptConfig": { - "type": "object", - "defaultValue": { - "enabled": false, - "fileData": [] - }, - "metadata": { - "description": "Optional. The configuration for the [Custom Script] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionNvidiaGpuDriverWindows": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionCustomScriptProtectedSetting": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. An object that contains the extension specific protected settings." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "baseTime": { - "type": "string", - "defaultValue": "[utcNow('u')]", - "metadata": { - "description": "Generated. Do not provide a value! This date value is used to generate a registration token." - } - }, - "sasTokenValidityLength": { - "type": "string", - "defaultValue": "PT8H", - "metadata": { - "description": "Optional. SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." - } - }, - "osType": { - "type": "string", - "allowedValues": [ - "Windows", - "Linux" - ], - "metadata": { - "description": "Required. The chosen OS type." - } - }, - "provisionVMAgent": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." - } - }, - "enableAutomaticUpdates": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." - } - }, - "patchMode": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "AutomaticByPlatform", - "AutomaticByOS", - "Manual", - "ImageDefault", - "" - ], - "metadata": { - "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." - } - }, - "bypassPlatformSafetyChecksOnUserSchedule": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enables customer to schedule patching without accidental upgrades." - } - }, - "rebootSetting": { - "type": "string", - "defaultValue": "IfRequired", - "allowedValues": [ - "Always", - "IfRequired", - "Never", - "Unknown" - ], - "metadata": { - "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." - } - }, - "patchAssessmentMode": { - "type": "string", - "defaultValue": "ImageDefault", - "allowedValues": [ - "AutomaticByPlatform", - "ImageDefault" - ], - "metadata": { - "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." - } - }, - "timeZone": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." - } - }, - "additionalUnattendContent": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." - } - }, - "winRM": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object." - } - }, - "configurationProfile": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." - } - } - }, - "variables": { - "windowsConfiguration": { - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting'))), null())]", - "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", - "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), parameters('additionalUnattendContent'))]", - "winRM": "[if(not(empty(parameters('winRM'))), createObject('listeners', parameters('winRM')), null())]" - }, - "accountSasProperties": { - "signedServices": "b", - "signedPermission": "r", - "signedExpiry": "[dateTimeAdd(parameters('baseTime'), parameters('sasTokenValidityLength'))]", - "signedResourceTypes": "o", - "signedProtocol": "https" - }, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "vm": { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2023-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "zones": "[if(not(equals(parameters('zone'), 0)), array(string(parameters('zone'))), null())]", - "plan": "[if(not(empty(parameters('plan'))), parameters('plan'), null())]", - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "securityProfile": { - "encryptionAtHost": "[if(parameters('encryptionAtHost'), parameters('encryptionAtHost'), null())]", - "securityType": "[parameters('securityType')]", - "uefiSettings": "[if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null())]" - }, - "storageProfile": { - "copy": [ - { - "name": "dataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", - "input": { - "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", - "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))]", - "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createoption'), 'Empty')]", - "deleteOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete')]", - "caching": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly')]", - "managedDisk": { - "storageAccountType": "[coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.storageAccountType]", - "diskEncryptionSet": "[coalesce(tryGet(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'managedDisk'), 'diskEncryptionSet'), null())]" - } - } - } - ], - "imageReference": "[parameters('imageReference')]", - "osDisk": { - "name": "[coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name')))]", - "createOption": "[coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage')]", - "deleteOption": "[coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete')]", - "caching": "[coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly')]", - "managedDisk": { - "storageAccountType": "[parameters('osDisk').managedDisk.storageAccountType]", - "diskEncryptionSet": { - "id": "[tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')]" - } - } - } - }, - "additionalCapabilities": { - "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]" - }, - "osProfile": { - "computerName": "[parameters('computerName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]", - "customData": "[if(not(empty(parameters('customData'))), base64(parameters('customData')), null())]", - "windowsConfiguration": "[if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null())]", - "secrets": "[parameters('certificatesToBeInstalled')]", - "allowExtensionOperations": "[parameters('allowExtensionOperations')]" - }, - "networkProfile": { - "copy": [ - { - "name": "networkInterfaces", - "count": "[length(parameters('nicConfigurations'))]", - "input": { - "properties": { - "deleteOption": "[if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].deleteOption, 'Delete')]", - "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" - }, - "id": "[resourceId('Microsoft.Network/networkInterfaces', if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].name, format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].nicSuffix)))]" - } - } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", - "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" - } - }, - "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", - "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", - "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", - "priority": "[parameters('priority')]", - "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", - "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", - "host": "[if(not(empty(parameters('dedicatedHostId'))), createObject('id', parameters('dedicatedHostId')), null())]", - "licenseType": "[if(not(empty(parameters('licenseType'))), parameters('licenseType'), null())]" - }, - "dependsOn": [ - "vm_nic" - ] - }, - "vm_configurationProfileAssignment": { - "condition": "[not(empty(parameters('configurationProfile')))]", - "type": "Microsoft.Automanage/configurationProfileAssignments", - "apiVersion": "2022-05-04", - "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", - "name": "default", - "properties": { - "configurationProfile": "[parameters('configurationProfile')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_nic": { - "copy": { - "name": "vm_nic", - "count": "[length(parameters('nicConfigurations'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "networkInterfaceName": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'name'), createObject('value', parameters('nicConfigurations')[copyIndex()].name), createObject('value', format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex()].nicSuffix)))]", - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableIPForwarding": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableIPForwarding), createObject('value', false()))]", - "enableAcceleratedNetworking": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableAcceleratedNetworking), createObject('value', true()))]", - "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(parameters('nicConfigurations')[copyIndex()].dnsServers)), createObject('value', parameters('nicConfigurations')[copyIndex()].dnsServers), createObject('value', createArray())), createObject('value', createArray()))]", - "networkSecurityGroupResourceId": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('nicConfigurations')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", - "ipConfigurations": { - "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" - }, - "roleAssignments": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "4081873631846149092" - } - }, - "definitions": { - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "networkInterfaceName": { - "type": "string" - }, - "virtualMachineName": { - "type": "string" - }, - "ipConfigurations": { - "type": "array" - }, - "location": { - "type": "string", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false - }, - "dnsServers": { - "type": "array", - "defaultValue": [] - }, - "enableTelemetry": { - "type": "bool", - "metadata": { - "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the Network Interface." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "resources": { - "networkInterface_publicIPAddresses": { - "copy": { - "name": "networkInterface_publicIPAddresses", - "count": "[length(parameters('ipConfigurations'))]" - }, - "condition": "[contains(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIpNameSuffix)]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "idleTimeoutInMinutes": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'idleTimeoutInMinutes')]" - }, - "ddosSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'ddosSettings')]" - }, - "dnsSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'dnsSettings')]" - }, - "publicIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressVersion'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAddressVersion), createObject('value', 'IPv4'))]", - "publicIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAllocationMethod'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAllocationMethod), createObject('value', 'Static'))]", - "publicIpPrefixResourceId": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPPrefixResourceId'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPPrefixResourceId), createObject('value', ''))]", - "roleAssignments": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'roleAssignments'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.roleAssignments), createObject('value', createArray()))]", - "skuName": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuName'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuName), createObject('value', 'Standard'))]", - "skuTier": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuTier'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuTier), createObject('value', 'Regional'))]", - "tags": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "zones": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.zones), createObject('value', createArray(1, 2, 3)))]", - "enableTelemetry": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.26.54.24096", - "templateHash": "4718335757080871925" - }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "", - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "metadata": { - "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "metadata": { - "description": "Required. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - } - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "defaultValue": "Static", - "allowedValues": [ - "Dynamic", - "Static" - ], - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "zones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } - }, - "publicIPAddressVersion": { - "type": "string", - "defaultValue": "IPv4", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "metadata": { - "description": "Optional. IP address version." - } - }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Basic", - "Standard" - ], - "metadata": { - "description": "Optional. Name of a public IP address SKU." - } - }, - "skuTier": { - "type": "string", - "defaultValue": "Regional", - "allowedValues": [ - "Global", - "Regional" - ], - "metadata": { - "description": "Optional. Tier of a public IP address SKU." - } - }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "defaultValue": 4, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", - "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2023-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" - }, - "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", - "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": null - } - }, - "publicIpAddress_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_roleAssignments": { - "copy": { - "name": "publicIpAddress_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_diagnosticSettings": { - "copy": { - "name": "publicIpAddress_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the public IP address was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the public IP address." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the public IP address." - }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "ipAddress": { - "type": "string", - "metadata": { - "description": "The public IP address of the public IP address resource." - }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-NetworkInterface', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('networkInterfaceName')]" - }, - "ipConfigurations": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('ipConfigurations'))]", - "input": "[createObject('name', if(not(empty(parameters('ipConfigurations')[copyIndex('value')].name)), parameters('ipConfigurations')[copyIndex('value')].name, null()), 'primary', equals(copyIndex('value'), 0), 'privateIPAllocationMethod', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod, null()), null()), 'privateIPAddress', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('value')].privateIPAddress, null()), null()), 'publicIPAddressResourceId', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), resourceId('Microsoft.Network/publicIPAddresses', format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.publicIpNameSuffix)), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerBackendAddressPools, null()), 'applicationSecurityGroups', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('value')].applicationSecurityGroups, null()), 'applicationGatewayBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].applicationGatewayBackendAddressPools, null()), 'gatewayLoadBalancer', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('value')].gatewayLoadBalancer, null()), 'loadBalancerInboundNatRules', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerInboundNatRules, null()), 'privateIPAddressVersion', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('value')].privateIPAddressVersion, null()), 'virtualNetworkTaps', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('value')].virtualNetworkTaps, null()))]" - } - ] - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "dnsServers": "[if(not(empty(parameters('dnsServers'))), createObject('value', parameters('dnsServers')), createObject('value', createArray()))]", - "enableAcceleratedNetworking": { - "value": "[parameters('enableAcceleratedNetworking')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enableIPForwarding": { - "value": "[parameters('enableIPForwarding')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", - "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "1612343535299711142" - }, - "name": "Network Interface", - "description": "This module deploys a Network Interface.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - } - }, - "nullable": true - }, - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } - }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "condition": { - "type": "string", - "nullable": true, - "metadata": { - "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\"." - } - }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the network interface." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If the network interface is accelerated networking enabled." - } - }, - "dnsServers": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "auxiliaryMode": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "Floating", - "MaxConnections", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "auxiliarySku": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "A1", - "A2", - "A4", - "A8", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "disableTcpStateTracking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "description": "Required. A list of IPConfigurations of the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", - "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.2.4', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "ipConfigurations", - "count": "[length(parameters('ipConfigurations'))]", - "input": { - "name": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].name, format('ipconfig0{0}', add(copyIndex('ipConfigurations'), 1)))]", - "properties": { - "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", - "privateIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod, null()), null())]", - "privateIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress, null()), null())]", - "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId, null())), createObject('id', parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId), null()), null())]", - "subnet": { - "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" - }, - "loadBalancerBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerBackendAddressPools, null())]", - "applicationSecurityGroups": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationSecurityGroups, null())]", - "applicationGatewayBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationGatewayBackendAddressPools, null())]", - "gatewayLoadBalancer": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].gatewayLoadBalancer, null())]", - "loadBalancerInboundNatRules": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerInboundNatRules, null())]", - "privateIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddressVersion, null())]", - "virtualNetworkTaps": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].virtualNetworkTaps, null())]" - } - } - } - ], - "auxiliaryMode": "[parameters('auxiliaryMode')]", - "auxiliarySku": "[parameters('auxiliarySku')]", - "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", - "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", - "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", - "enableIPForwarding": "[parameters('enableIPForwarding')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" - } - }, - "networkInterface_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_diagnosticSettings": { - "copy": { - "name": "networkInterface_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_roleAssignments": { - "copy": { - "name": "networkInterface_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", - "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", - "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", - "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", - "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", - "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", - "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", - "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" - }, - "dependsOn": [ - "networkInterface" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed resource." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed resource." - }, - "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed resource." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkInterface', '2023-04-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "networkInterface_publicIPAddresses" - ] - } - } - } - } - }, - "vm_aadJoinExtension": { - "condition": "[parameters('extensionAadJoinConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "AADLogin" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.ActiveDirectory" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAadJoinConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.0'), createObject('value', '1.0')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAadJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAadJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": "[if(contains(parameters('extensionAadJoinConfig'), 'settings'), createObject('value', parameters('extensionAadJoinConfig').settings), createObject('value', createObject()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_domainJoinExtension": { - "condition": "[parameters('extensionDomainJoinConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "DomainJoin" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "JsonADDomainExtension" - }, - "typeHandlerVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDomainJoinConfig').typeHandlerVersion), createObject('value', '1.3'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDomainJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDomainJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": { - "value": "[parameters('extensionDomainJoinConfig').settings]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": { - "Password": "[parameters('extensionDomainJoinPassword')]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_aadJoinExtension" - ] - }, - "vm_desiredStateConfigurationExtension": { - "condition": "[parameters('extensionDSCConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "DesiredStateConfiguration" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Powershell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": "[if(contains(parameters('extensionDSCConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDSCConfig').typeHandlerVersion), createObject('value', '2.77'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDSCConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDSCConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": "[if(contains(parameters('extensionDSCConfig'), 'settings'), createObject('value', parameters('extensionDSCConfig').settings), createObject('value', createObject()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": "[if(contains(parameters('extensionDSCConfig'), 'protectedSettings'), createObject('value', parameters('extensionDSCConfig').protectedSettings), createObject('value', createObject()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_customScriptExtension": { - "condition": "[parameters('extensionCustomScriptConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "CustomScriptExtension" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionCustomScriptConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '1.10'), createObject('value', '2.1')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionCustomScriptConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionCustomScriptConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": { - "value": { - "copy": [ - { - "name": "fileUris", - "count": "[length(parameters('extensionCustomScriptConfig').fileData)]", - "input": "[if(contains(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')], 'storageAccountId'), format('{0}?{1}', parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri, listAccountSas(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].storageAccountId, '2019-04-01', variables('accountSasProperties')).accountSasToken), parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri)]" - } - ] - } - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": "[parameters('extensionCustomScriptProtectedSetting')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_desiredStateConfigurationExtension" - ] - }, - "vm_azureDiskEncryptionExtension": { - "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "AzureDiskEncryption" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.2'), createObject('value', '1.1')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "forceUpdateTag": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').forceUpdateTag), createObject('value', '1.0'))]", - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_nvidiaGpuDriverWindowsExtension": { - "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "NvidiaGpuDriverWindows" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.HpcCompute" - }, - "type": { - "value": "NvidiaGpuDriverWindows" - }, - "typeHandlerVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').typeHandlerVersion), createObject('value', '1.4'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').enableAutomaticUpgrade), createObject('value', false()))]", - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureDiskEncryptionExtension" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the VM." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the VM." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the VM was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[coalesce(tryGet(tryGet(reference('vm', '2023-09-01', 'full'), 'identity'), 'principalId'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('vm', '2023-09-01', 'full').location]" - } - } - } - } - }, - { - "copy": { - "name": "sessionHostsAntimalwareExtension", - "count": "[length(range(0, parameters('count')))]" - }, - "condition": "[parameters('deployAntiMalwareExt')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('SH-Antimal-{0}-{1}-{2}', add(parameters('batchId'), 1), add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "virtualMachineName": { - "value": "[format('{0}{1}', parameters('namePrefix'), padLeft(add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), 4, '0'))]" - }, - "name": { - "value": "MicrosoftAntiMalware" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": { - "value": "IaaSAntimalware" - }, - "typeHandlerVersion": { - "value": "1.3" - }, - "autoUpgradeMinorVersion": { - "value": true - }, - "enableAutomaticUpgrade": { - "value": false - }, - "settings": { - "value": { - "AntimalwareEnabled": true, - "RealtimeProtectionEnabled": "true", - "ScheduledScanSettings": { - "isEnabled": "true", - "day": "7", - "time": "120", - "scanType": "Quick" - }, - "Exclusions": "[if(parameters('configureFslogix'), createObject('Extensions', '*.vhd;*.vhdx', 'Paths', format('\"%ProgramFiles%\\FSLogix\\Apps\\frxdrv.sys;%ProgramFiles%\\FSLogix\\Apps\\frxccd.sys;%ProgramFiles%\\FSLogix\\Apps\\frxdrvvt.sys;%TEMP%\\*.VHD;%TEMP%\\*.VHDX;%Windir%\\TEMP\\*.VHD;%Windir%\\TEMP\\*.VHDX;{0}\\*\\*.VHD;{1}\\*\\*.VHDX', parameters('fslogixSharePath'), parameters('fslogixSharePath')), 'Processes', '%ProgramFiles%\\FSLogix\\Apps\\frxccd.exe;%ProgramFiles%\\FSLogix\\Apps\\frxccds.exe;%ProgramFiles%\\FSLogix\\Apps\\frxsvc.exe'), createObject())]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "sessionHosts" - ] - }, - { - "copy": { - "name": "ama", - "count": "[length(range(0, parameters('count')))]" - }, - "condition": "[parameters('deployMonitoring')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('SH-Mon-{0}-{1}-{2}', add(parameters('batchId'), 1), add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - }, - "virtualMachineName": { - "value": "[format('{0}{1}', parameters('namePrefix'), padLeft(add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), 4, '0'))]" - }, - "name": { - "value": "AzureMonitorWindowsAgent" - }, - "publisher": { - "value": "Microsoft.Azure.Monitor" - }, - "type": { - "value": "AzureMonitorWindowsAgent" - }, - "typeHandlerVersion": { - "value": "1.0" - }, - "autoUpgradeMinorVersion": { - "value": true - }, - "enableAutomaticUpgrade": { - "value": true - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12041352154594223618" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "sessionHostsAntimalwareExtension" - ] - }, - { - "copy": { - "name": "dataCollectionRuleAssociation", - "count": "[length(range(0, parameters('count')))]" - }, - "condition": "[parameters('deployMonitoring')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('DCR-Asso-{0}-{1}-{2}', add(parameters('batchId'), 1), add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[format('{0}{1}', parameters('namePrefix'), padLeft(add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), 4, '0'))]" - }, - "dataCollectionRuleId": { - "value": "[parameters('dataCollectionRuleId')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "5134409313697181849" - } - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "VM name." - } - }, - "dataCollectionRuleId": { - "type": "string", - "metadata": { - "description": "Data collection rule ID." - } - } - }, - "resources": [ - { - "type": "Microsoft.Insights/dataCollectionRuleAssociations", - "apiVersion": "2022-06-01", - "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('virtualMachineName'))]", - "name": "[parameters('virtualMachineName')]", - "properties": { - "dataCollectionRuleId": "[parameters('dataCollectionRuleId')]", - "description": "AVD Insights data collection rule association" - } - } - ] - } - }, - "dependsOn": [ - "ama", - "sessionHostsAntimalwareExtension" - ] - }, - { - "copy": { - "name": "sessionHostConfiguration", - "count": "[length(range(0, parameters('count')))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('SH-Config-{0}-{1}-{2}', add(parameters('batchId'), 1), add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "baseScriptUri": { - "value": "[parameters('sessionHostConfigurationScriptUri')]" - }, - "fslogix": { - "value": "[parameters('configureFslogix')]" - }, - "fslogixSharePath": { - "value": "[parameters('fslogixSharePath')]" - }, - "fslogixStorageAccountResourceId": { - "value": "[parameters('fslogixStorageAccountResourceId')]" - }, - "hostPoolResourceId": { - "value": "[parameters('hostPoolResourceId')]" - }, - "identityDomainName": { - "value": "[parameters('identityDomainName')]" - }, - "identityServiceProvider": { - "value": "[parameters('identityServiceProvider')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "name": { - "value": "[format('{0}{1}', parameters('namePrefix'), padLeft(add(range(0, parameters('count'))[copyIndex()], parameters('countIndex')), 4, '0'))]" - }, - "scriptName": { - "value": "[parameters('sessionHostConfigurationScript')]" - }, - "vmSize": { - "value": "[parameters('vmSize')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "1149225665070592315" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Extension deployment name." - } - }, - "identityServiceProvider": { - "type": "string", - "metadata": { - "description": "The service providing domain services for Azure Virtual Desktop." - } - }, - "identityDomainName": { - "type": "string", - "metadata": { - "description": "Identity domain name." - } - }, - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy compute services." - } - }, - "baseScriptUri": { - "type": "string", - "metadata": { - "description": "URI for AVD session host configuration URI path." - } - }, - "scriptName": { - "type": "string", - "metadata": { - "description": "URI for AVD session host configuration script." - } - }, - "fslogix": { - "type": "bool", - "metadata": { - "description": "Deploy FSlogix configuration." - } - }, - "fslogixStorageAccountResourceId": { - "type": "string", - "metadata": { - "description": "FSLogix storage account resource ID." - } - }, - "fslogixSharePath": { - "type": "string", - "metadata": { - "description": "File share name for FSlogix storage." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "Session host VM size." - } - }, - "hostPoolResourceId": { - "type": "string", - "metadata": { - "description": "AVD Host Pool Resource Id" - } - } - }, - "variables": { - "fslogixStorageAccountName": "[if(parameters('fslogix'), last(split(parameters('fslogixStorageAccountResourceId'), '/')), '')]", - "varBaseFSLogixScriptArguments": "[format('-FslogixFileShare \"{0}\"', parameters('fslogixSharePath'))]", - "varAmdVmSizes": [ - "Standard_NV4as_v4", - "Standard_NV8as_v4", - "Standard_NV16as_v4", - "Standard_NV32as_v4" - ], - "varAmdVmSize": "[contains(variables('varAmdVmSizes'), parameters('vmSize'))]", - "varNvidiaVmSizes": [ - "Standard_NV6", - "Standard_NV12", - "Standard_NV24", - "Standard_NV12s_v3", - "Standard_NV24s_v3", - "Standard_NV48s_v3", - "Standard_NC4as_T4_v3", - "Standard_NC8as_T4_v3", - "Standard_NC16as_T4_v3", - "Standard_NC64as_T4_v3", - "Standard_NV6ads_A10_v5", - "Standard_NV12ads_A10_v5", - "Standard_NV18ads_A10_v5", - "Standard_NV36ads_A10_v5", - "Standard_NV36adms_A10_v5", - "Standard_NV72ads_A10_v5" - ], - "varNvidiaVmSize": "[contains(variables('varNvidiaVmSizes'), parameters('vmSize'))]" - }, - "resources": [ - { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2023-09-01", - "name": "[format('{0}/SessionHostConfig', parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "publisher": "Microsoft.Compute", - "type": "CustomScriptExtension", - "typeHandlerVersion": "1.10", - "autoUpgradeMinorVersion": true, - "settings": { - "fileUris": "[array(parameters('baseScriptUri'))]" - }, - "protectedSettings": { - "commandToExecute": "[format('powershell -ExecutionPolicy Unrestricted -Command .\\{0} {1}', parameters('scriptName'), if(parameters('fslogix'), format('{0} {1}', format('-IdentityServiceProvider {0} -Fslogix {1} -HostPoolRegistrationToken \"{2}\" -AmdVmSize {3} -NvidiaVmSize {4}', parameters('identityServiceProvider'), parameters('fslogix'), listRegistrationTokens(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('hostPoolResourceId'), '/')[4]), 'Microsoft.DesktopVirtualization/hostPools', last(split(parameters('hostPoolResourceId'), '/'))), '2023-09-05').value[0].token, variables('varAmdVmSize'), variables('varNvidiaVmSize')), if(equals(parameters('identityServiceProvider'), 'EntraID'), format('{0} -FslogixStorageAccountKey \"{1}\"', variables('varBaseFSLogixScriptArguments'), listkeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('fslogixStorageAccountResourceId'), '/')[4]), 'Microsoft.Storage/storageAccounts', variables('fslogixStorageAccountName')), '2023-05-01').keys[0].value), if(equals(parameters('identityServiceProvider'), 'EntraIDKerberos'), format('{0} -IdentityDomainName {1}', variables('varBaseFSLogixScriptArguments'), parameters('identityDomainName')), variables('varBaseFSLogixScriptArguments')))), format('-IdentityServiceProvider {0} -Fslogix {1} -HostPoolRegistrationToken \"{2}\" -AmdVmSize {3} -NvidiaVmSize {4}', parameters('identityServiceProvider'), parameters('fslogix'), listRegistrationTokens(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, split(parameters('hostPoolResourceId'), '/')[4]), 'Microsoft.DesktopVirtualization/hostPools', last(split(parameters('hostPoolResourceId'), '/'))), '2023-09-05').value[0].token, variables('varAmdVmSize'), variables('varNvidiaVmSize'))))]" - } - } - } - ] - } - }, - "dependsOn": [ - "ama", - "sessionHosts" - ] - } - ] - } - }, - "dependsOn": [ - "baselineResourceGroups", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('AVD-MGMT-Plane-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Monitoring-{0}', parameters('time')))]", - "[subscriptionResourceId('Microsoft.Resources/deployments', format('Networking-{0}', parameters('time')))]", - "[subscriptionResourceId(format('{0}', parameters('avdWorkloadSubsId')), 'Microsoft.Resources/deployments', format('SMB-Storage-{0}', parameters('time')))]", - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('avdWorkloadSubsId')), format('{0}', variables('varServiceObjectsRgName'))), 'Microsoft.Resources/deployments', format('Workload-KeyVault-{0}', parameters('time')))]", - "[subscriptionResourceId(parameters('avdWorkloadSubsId'), 'Microsoft.Resources/deployments', format('Zero-Trust-{0}', parameters('time')))]" - ] - }, - { - "condition": "[parameters('deployGpuPolicies')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('GPU-VM-Extensions-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('avdWorkloadSubsId'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "computeObjectsRgName": { - "value": "[variables('varComputeObjectsRgName')]" - }, - "location": { - "value": "[parameters('avdSessionHostLocation')]" - }, - "subscriptionId": { - "value": "[parameters('avdWorkloadSubsId')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12630662508259220166" - } - }, - "parameters": { - "location": { - "type": "string", - "metadata": { - "description": "Location where to deploy compute services." - } - }, - "subscriptionId": { - "type": "string", - "metadata": { - "description": "AVD workload subscription ID, multiple subscriptions scenario." - } - }, - "computeObjectsRgName": { - "type": "string", - "metadata": { - "description": "AVD Resource Group Name for the service objects." - } - }, - "time": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "Do not modify, used to set unique value for resource deployment." - } - } - }, - "variables": { - "$fxv#0": "{\r\n \"name\": \"policy-deploy-amd-gpu-driver\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy AMD GPU Driver Extension\",\r\n \"description\": \"This policy definition deploys the AMD GPU Driver extension on AMD's SKU VMs.\",\r\n \"metadata\": {\r\n \"version\": \"1.1.0\",\r\n \"category\": \"Drivers\"\r\n },\r\n \"parameters\": {\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Compute/virtualMachines\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/sku.name\",\r\n \"in\": [\r\n \"Standard_NV4as_v4\",\r\n \"Standard_NV8as_v4\",\r\n \"Standard_NV16as_v4\",\r\n \"Standard_NV32as_v4\"\r\n ]\r\n }\r\n ]\r\n },\r\n \"then\": {\r\n \"effect\": \"deployIfNotExists\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Compute/virtualMachines/extensions\",\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c\"\r\n ],\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/extensions/publisher\",\r\n \"equals\": \"Microsoft.HpcCompute\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/extensions/type\",\r\n \"equals\": \"AmdGpuDriverWindows\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/extensions/provisioningState\",\r\n \"in\": [\r\n \"Succeeded\"\r\n ]\r\n }\r\n ]\r\n },\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"vmName\": {\r\n \"type\": \"string\"\r\n },\r\n \"location\": {\r\n \"type\": \"string\"\r\n }\r\n },\r\n \"variables\": {\r\n \"vmExtensionName\": \"AmdGpuDriverWindows\",\r\n \"vmExtensionPublisher\": \"Microsoft.HpcCompute\",\r\n \"vmExtensionType\": \"AmdGpuDriverWindows\",\r\n \"vmExtensionTypeHandlerVersion\": \"1.0\"\r\n },\r\n \"resources\": [\r\n {\r\n \"name\": \"[concat(parameters('vmName'), '/', variables('vmExtensionName'))]\",\r\n \"type\": \"Microsoft.Compute/virtualMachines/extensions\",\r\n \"location\": \"[parameters('location')]\",\r\n \"apiVersion\": \"2018-06-01\",\r\n \"properties\": {\r\n \"publisher\": \"[variables('vmExtensionPublisher')]\",\r\n \"type\": \"[variables('vmExtensionType')]\",\r\n \"typeHandlerVersion\": \"[variables('vmExtensionTypeHandlerVersion')]\",\r\n \"autoUpgradeMinorVersion\": true\r\n }\r\n }\r\n ],\r\n \"outputs\": {\r\n \"policy\": {\r\n \"type\": \"string\",\r\n \"value\": \"[concat('Enabled extension for VM', ': ', parameters('vmName'))]\"\r\n }\r\n }\r\n },\r\n \"parameters\": {\r\n \"vmName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}", - "$fxv#1": "{\r\n \"name\": \"policy-deploy-nvidia-gpu-driver\",\r\n \"type\": \"Microsoft.Authorization/policyDefinitions\",\r\n \"apiVersion\": \"2021-06-01\",\r\n \"scope\": null,\r\n \"properties\": {\r\n \"policyType\": \"Custom\",\r\n \"mode\": \"Indexed\",\r\n \"displayName\": \"Custom - Deploy Nvidia GPU Driver Extension\",\r\n \"description\": \"This policy definition deploys the Nvidia GPU Driver extension on Nvidia's SKU VMs.\",\r\n \"metadata\": {\r\n \"version\": \"1.1.0\",\r\n \"category\": \"Drivers\"\r\n },\r\n \"parameters\": {\r\n },\r\n \"policyRule\": {\r\n \"if\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"type\",\r\n \"equals\": \"Microsoft.Compute/virtualMachines\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/sku.name\",\r\n \"in\": [\r\n \"Standard_NV6\",\r\n \"Standard_NV12\",\r\n \"Standard_NV24\",\r\n \"Standard_NV12s_v3\",\r\n \"Standard_NV24s_v3\",\r\n \"Standard_NV48s_v3\",\r\n \"Standard_NC4as_T4_v3\",\r\n \"Standard_NC8as_T4_v3\",\r\n \"Standard_NC16as_T4_v3\",\r\n \"Standard_NC64as_T4_v3\",\r\n \"Standard_NV6ads_A10_v5\",\r\n \"Standard_NV12ads_A10_v5\",\r\n \"Standard_NV18ads_A10_v5\",\r\n \"Standard_NV36ads_A10_v5\",\r\n \"Standard_NV36adms_A10_v5\",\r\n \"Standard_NV72ads_A10_v5\"\r\n ]\r\n }\r\n ]\r\n },\r\n \"then\": {\r\n \"effect\": \"deployIfNotExists\",\r\n \"details\": {\r\n \"type\": \"Microsoft.Compute/virtualMachines/extensions\",\r\n \"roleDefinitionIds\": [\r\n \"/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c\"\r\n ],\r\n \"existenceCondition\": {\r\n \"allOf\": [\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/extensions/publisher\",\r\n \"equals\": \"Microsoft.HpcCompute\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/extensions/type\",\r\n \"equals\": \"NvidiaGpuDriverWindows\"\r\n },\r\n {\r\n \"field\": \"Microsoft.Compute/virtualMachines/extensions/provisioningState\",\r\n \"in\": [\r\n \"Succeeded\"\r\n ]\r\n }\r\n ]\r\n },\r\n \"deployment\": {\r\n \"properties\": {\r\n \"mode\": \"Incremental\",\r\n \"template\": {\r\n \"$schema\": \"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\r\n \"contentVersion\": \"1.0.0.0\",\r\n \"parameters\": {\r\n \"vmName\": {\r\n \"type\": \"string\"\r\n },\r\n \"location\": {\r\n \"type\": \"string\"\r\n }\r\n },\r\n \"variables\": {\r\n \"vmExtensionName\": \"NvidiaGpuDriverWindows\",\r\n \"vmExtensionPublisher\": \"Microsoft.HpcCompute\",\r\n \"vmExtensionType\": \"NvidiaGpuDriverWindows\",\r\n \"vmExtensionTypeHandlerVersion\": \"1.2\"\r\n },\r\n \"resources\": [\r\n {\r\n \"name\": \"[concat(parameters('vmName'), '/', variables('vmExtensionName'))]\",\r\n \"type\": \"Microsoft.Compute/virtualMachines/extensions\",\r\n \"location\": \"[parameters('location')]\",\r\n \"apiVersion\": \"2018-06-01\",\r\n \"properties\": {\r\n \"publisher\": \"[variables('vmExtensionPublisher')]\",\r\n \"type\": \"[variables('vmExtensionType')]\",\r\n \"typeHandlerVersion\": \"[variables('vmExtensionTypeHandlerVersion')]\",\r\n \"autoUpgradeMinorVersion\": true\r\n }\r\n }\r\n ],\r\n \"outputs\": {\r\n \"policy\": {\r\n \"type\": \"string\",\r\n \"value\": \"[concat('Enabled extension for VM', ': ', parameters('vmName'))]\"\r\n }\r\n }\r\n },\r\n \"parameters\": {\r\n \"vmName\": {\r\n \"value\": \"[field('name')]\"\r\n },\r\n \"location\": {\r\n \"value\": \"[field('location')]\"\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}", - "varCustomPolicyDefinitions": [ - { - "deploymentName": "AMD-Policy", - "libDefinition": "[json(variables('$fxv#0'))]" - }, - { - "deploymentName": "Nvidia-Policy", - "libDefinition": "[json(variables('$fxv#1'))]" - } - ] - }, - "resources": [ - { - "copy": { - "name": "gpuPolicyDefinitions", - "count": "[length(variables('varCustomPolicyDefinitions'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "description": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.description]" - }, - "displayName": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.displayName]" - }, - "name": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.name]" - }, - "metadata": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.metadata]" - }, - "mode": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.mode]" - }, - "parameters": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.parameters]" - }, - "policyRule": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.policyRule]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "15296566503434303805" - } - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 64, - "metadata": { - "description": "Required. Specifies the name of the policy definition. Maximum length is 64 characters." - } - }, - "displayName": { - "type": "string", - "defaultValue": "", - "maxLength": 128, - "metadata": { - "description": "Optional. The display name of the policy definition. Maximum length is 128 characters." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The policy definition description." - } - }, - "mode": { - "type": "string", - "defaultValue": "All", - "allowedValues": [ - "All", - "Indexed", - "Microsoft.KeyVault.Data", - "Microsoft.ContainerService.Data", - "Microsoft.Kubernetes.Data", - "Microsoft.Network.Data" - ], - "metadata": { - "description": "Optional. The policy definition mode. Default is All, Some examples are All, Indexed, Microsoft.KeyVault.Data." - } - }, - "metadata": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The policy Definition metadata. Metadata is an open ended object and is typically a collection of key-value pairs." - } - }, - "parameters": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The policy definition parameters that can be used in policy definition references." - } - }, - "policyRule": { - "type": "object", - "metadata": { - "description": "Required. The Policy Rule details for the Policy Definition." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/policyDefinitions", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "properties": { - "policyType": "Custom", - "mode": "[parameters('mode')]", - "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", - "parameters": "[if(not(empty(parameters('parameters'))), parameters('parameters'), null())]", - "policyRule": "[parameters('policyRule')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "Policy Definition Name." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Policy Definition resource ID." - }, - "value": "[subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name'))]" - }, - "roleDefinitionIds": { - "type": "array", - "metadata": { - "description": "Policy Definition Role Definition IDs." - }, - "value": "[if(contains(reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then, 'details'), if(contains(reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then.details, 'roleDefinitionIds'), reference(subscriptionResourceId('Microsoft.Authorization/policyDefinitions', parameters('name')), '2023-04-01').policyRule.then.details.roleDefinitionIds, createArray()), createArray())]" - } - } - } - } - }, - { - "copy": { - "name": "gpuPolicyAssignmentsCompute", - "count": "[length(variables('varCustomPolicyDefinitions'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Policy-Assign-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.name]" - }, - "displayName": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.displayName]" - }, - "description": { - "value": "[variables('varCustomPolicyDefinitions')[copyIndex()].libDefinition.properties.description]" - }, - "identity": { - "value": "SystemAssigned" - }, - "location": { - "value": "[parameters('location')]" - }, - "policyDefinitionId": { - "value": "[reference(subscriptionResourceId(format('{0}', parameters('subscriptionId')), 'Microsoft.Resources/deployments', format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.resourceId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "10386382608825992636" - }, - "name": "Policy Assignments (Resource Group scope)", - "description": "This module deploys a Policy Assignment at a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "maxLength": 64, - "metadata": { - "description": "Required. Specifies the name of the policy assignment. Maximum length is 64 characters for resource group scope." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. This message will be part of response in case of policy violation." - } - }, - "displayName": { - "type": "string", - "defaultValue": "", - "maxLength": 128, - "metadata": { - "description": "Optional. The display name of the policy assignment. Maximum length is 128 characters." - } - }, - "policyDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. Specifies the ID of the policy definition or policy set definition being assigned." - } - }, - "parameters": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Parameters for the policy assignment if needed." - } - }, - "identity": { - "type": "string", - "defaultValue": "SystemAssigned", - "allowedValues": [ - "SystemAssigned", - "UserAssigned", - "None" - ], - "metadata": { - "description": "Optional. The managed identity associated with the policy assignment. Policy assignments must include a resource identity when assigning 'Modify' policy definitions." - } - }, - "userAssignedIdentityId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Resource ID for the user assigned identity to assign to the policy assignment." - } - }, - "roleDefinitionIds": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The IDs Of the Azure Role Definition list that is used to assign permissions to the identity. You need to provide either the fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles for the list IDs for built-in Roles. They must match on what is on the policy definition." - } - }, - "metadata": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The policy assignment metadata. Metadata is an open ended object and is typically a collection of key-value pairs." - } - }, - "nonComplianceMessages": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The messages that describe why a resource is non-compliant with the policy." - } - }, - "enforcementMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "DoNotEnforce" - ], - "metadata": { - "description": "Optional. The policy assignment enforcement mode. Possible values are Default and DoNotEnforce. - Default or DoNotEnforce." - } - }, - "notScopes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The policy excluded scopes." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "overrides": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The policy property value override. Allows changing the effect of a policy definition without modifying the underlying policy definition or using a parameterized effect in the policy definition." - } - }, - "resourceSelectors": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The resource selector list to filter policies by resource properties. Facilitates safe deployment practices (SDP) by enabling gradual roll out policy assignments based on factors like resource location, resource type, or whether a resource has a location." - } - }, - "subscriptionId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "Optional. The Target Scope for the Policy. The subscription ID of the subscription for the policy assignment. If not provided, will use the current scope for deployment." - } - }, - "resourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. The Target Scope for the Policy. The name of the resource group for the policy assignment. If not provided, will use the current scope for deployment." - } - } - }, - "variables": { - "identityVar": "[if(equals(parameters('identity'), 'SystemAssigned'), createObject('type', parameters('identity')), if(equals(parameters('identity'), 'UserAssigned'), createObject('type', parameters('identity'), 'userAssignedIdentities', createObject(format('{0}', parameters('userAssignedIdentityId')), createObject())), null()))]" - }, - "resources": [ - { - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2022-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "properties": { - "displayName": "[if(not(empty(parameters('displayName'))), parameters('displayName'), null())]", - "metadata": "[if(not(empty(parameters('metadata'))), parameters('metadata'), null())]", - "description": "[if(not(empty(parameters('description'))), parameters('description'), null())]", - "policyDefinitionId": "[parameters('policyDefinitionId')]", - "parameters": "[parameters('parameters')]", - "nonComplianceMessages": "[if(not(empty(parameters('nonComplianceMessages'))), parameters('nonComplianceMessages'), createArray())]", - "enforcementMode": "[parameters('enforcementMode')]", - "notScopes": "[if(not(empty(parameters('notScopes'))), parameters('notScopes'), createArray())]", - "overrides": "[if(not(empty(parameters('overrides'))), parameters('overrides'), createArray())]", - "resourceSelectors": "[if(not(empty(parameters('resourceSelectors'))), parameters('resourceSelectors'), createArray())]" - }, - "identity": "[variables('identityVar')]" - }, - { - "copy": { - "name": "roleAssignment", - "count": "[length(parameters('roleDefinitionIds'))]" - }, - "condition": "[and(not(empty(parameters('roleDefinitionIds'))), equals(parameters('identity'), 'SystemAssigned'))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "name": "[guid(parameters('subscriptionId'), parameters('resourceGroupName'), parameters('roleDefinitionIds')[copyIndex()], parameters('location'), parameters('name'))]", - "properties": { - "roleDefinitionId": "[parameters('roleDefinitionIds')[copyIndex()]]", - "principalId": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').identity.principalId]", - "principalType": "ServicePrincipal" - }, - "dependsOn": [ - "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" - ] - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "Policy Assignment Name." - }, - "value": "[parameters('name')]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "Policy Assignment principal ID." - }, - "value": "[coalesce(tryGet(tryGet(reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full'), 'identity'), 'principalId'), '')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Policy Assignment resource ID." - }, - "value": "[resourceId('Microsoft.Authorization/policyAssignments', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the policy was assigned to." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference(resourceId('Microsoft.Authorization/policyAssignments', parameters('name')), '2022-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId(format('{0}', parameters('subscriptionId')), 'Microsoft.Resources/deployments', format('Policy-Defin-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time')))]" - ] - }, - { - "copy": { - "name": "policySetRemediationCompute", - "count": "[length(variables('varCustomPolicyDefinitions'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('remediate-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, copyIndex())]", - "subscriptionId": "[format('{0}', parameters('subscriptionId'))]", - "resourceGroup": "[format('{0}', parameters('computeObjectsRgName'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, copyIndex())]" - }, - "policyAssignmentId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('computeObjectsRgName'))), 'Microsoft.Resources/deployments', format('Policy-Assign-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time'))), '2022-09-01').outputs.resourceId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "8141314117626850328" - }, - "name": "Policy Insights Remediations (Resource Group scope)", - "description": "This module deploys a Policy Insights Remediation on a Resource Group scope.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Specifies the name of the policy remediation." - } - }, - "failureThresholdPercentage": { - "type": "string", - "defaultValue": "1", - "metadata": { - "description": "Optional. The remediation failure threshold settings. A number between 0.0 to 1.0 representing the percentage failure threshold. The remediation will fail if the percentage of failed remediation operations (i.e. failed deployments) exceeds this threshold. 0 means that the remediation will stop after the first failure. 1 means that the remediation will not stop even if all deployments fail." - } - }, - "filtersLocations": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The filters that will be applied to determine which resources to remediate." - } - }, - "parallelDeployments": { - "type": "int", - "defaultValue": 10, - "minValue": 1, - "maxValue": 30, - "metadata": { - "description": "Optional. Determines how many resources to remediate at any given time. Can be used to increase or reduce the pace of the remediation. Can be between 1-30. Higher values will cause the remediation to complete more quickly, but increase the risk of throttling. If not provided, the default parallel deployments value is used." - } - }, - "resourceCount": { - "type": "int", - "defaultValue": 500, - "minValue": 1, - "maxValue": 50000, - "metadata": { - "description": "Optional. Determines the max number of resources that can be remediated by the remediation job. Can be between 1-50000. If not provided, the default resource count is used." - } - }, - "resourceDiscoveryMode": { - "type": "string", - "defaultValue": "ExistingNonCompliant", - "allowedValues": [ - "ExistingNonCompliant", - "ReEvaluateCompliance" - ], - "metadata": { - "description": "Optional. The way resources to remediate are discovered. Defaults to ExistingNonCompliant if not specified." - } - }, - "policyAssignmentId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the policy assignment that should be remediated." - } - }, - "policyDefinitionReferenceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The policy definition reference ID of the individual definition that should be remediated. Required when the policy assignment being remediated assigns a policy set definition." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location deployment metadata." - } - } - }, - "resources": [ - { - "type": "Microsoft.PolicyInsights/remediations", - "apiVersion": "2021-10-01", - "name": "[parameters('name')]", - "properties": { - "failureThreshold": { - "percentage": "[json(parameters('failureThresholdPercentage'))]" - }, - "filters": { - "locations": "[parameters('filtersLocations')]" - }, - "parallelDeployments": "[parameters('parallelDeployments')]", - "policyAssignmentId": "[parameters('policyAssignmentId')]", - "policyDefinitionReferenceId": "[parameters('policyDefinitionReferenceId')]", - "resourceCount": "[parameters('resourceCount')]", - "resourceDiscoveryMode": "[parameters('resourceDiscoveryMode')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the remediation." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the remediation." - }, - "value": "[resourceId('Microsoft.PolicyInsights/remediations', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed remediation." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[parameters('location')]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', format('{0}', parameters('subscriptionId')), format('{0}', parameters('computeObjectsRgName'))), 'Microsoft.Resources/deployments', format('Policy-Assign-{0}-{1}', variables('varCustomPolicyDefinitions')[copyIndex()].deploymentName, parameters('time')))]" - ] - } - ] - } - }, - "dependsOn": [ - "sessionHosts" - ] - }, - { - "condition": "[parameters('deployDefender')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('Defender-Policies-{0}', parameters('time'))]", - "subscriptionId": "[format('{0}', parameters('avdWorkloadSubsId'))]", - "location": "[deployment().location]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "enableDefForServers": { - "value": "[parameters('enableDefForServers')]" - }, - "enableDefForStorage": { - "value": "[parameters('enableDefForStorage')]" - }, - "enableDefForKeyVault": { - "value": "[parameters('enableDefForKeyVault')]" - }, - "enableDefForArm": { - "value": "[parameters('enableDefForArm')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "17973539529965183406" - } - }, - "parameters": { - "initiativeName": { - "type": "string", - "defaultValue": "Custom - Deploy Microsoft Defender for Cloud Security - AVD", - "metadata": { - "description": "Name of the initiative definition." - } - }, - "initiativeDisplayName": { - "type": "string", - "defaultValue": "Custom - Deploy Microsoft Defender for Cloud Security - AVD", - "metadata": { - "description": "Display name of the initiative." - } - }, - "initiativeDescription": { - "type": "string", - "defaultValue": "This initiative deploys Microsoft Defender for Cloud Security for AVD.", - "metadata": { - "description": "Description of the initiative." - } - }, - "initiativeCategory": { - "type": "string", - "defaultValue": "Security Center", - "metadata": { - "description": "Category of the initiative." - } - }, - "effect": { - "type": "string", - "defaultValue": "DeployIfNotExists", - "allowedValues": [ - "DeployIfNotExists", - "Disabled" - ], - "metadata": { - "description": "Effect for the policy." - } - }, - "isOnUploadMalwareScanningEnabled": { - "type": "string", - "defaultValue": "true", - "allowedValues": [ - "true", - "false" - ], - "metadata": { - "description": "Enable or disable the Malware Scanning add-on feature." - } - }, - "capGBPerMonthPerStorageAccount": { - "type": "int", - "defaultValue": 5000, - "metadata": { - "description": "Cap GB scanned per month per storage account." - } - }, - "isSensitiveDataDiscoveryEnabled": { - "type": "string", - "defaultValue": "true", - "allowedValues": [ - "true", - "false" - ], - "metadata": { - "description": "Enable or disable the Sensitive Data Threat Detection add-on feature." - } - }, - "keyVaultSubPlan": { - "type": "string", - "defaultValue": "PerTransaction", - "allowedValues": [ - "PerTransaction", - "PerKeyVault" - ], - "metadata": { - "description": "Select a Defender for Key Vault plan." - } - }, - "resourceManagerSubPlan": { - "type": "string", - "defaultValue": "PerApiCall", - "allowedValues": [ - "PerSubscription", - "PerApiCall" - ], - "metadata": { - "description": "Select a Defender for Resource Manager plan." - } - }, - "enableDefForServers": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable or disable the \"Configure Azure Defender for servers to be enabled\" policy." - } - }, - "enableDefForStorage": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable or disable the \"Configure Microsoft Defender for Storage to be enabled\" policy." - } - }, - "enableDefForKeyVault": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable or disable the \"Configure Microsoft Defender for Key Vault plan\" policy." - } - }, - "enableDefForArm": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable or disable the \"Configure Azure Defender for Resource Manager to be enabled\" policy." - } - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/policySetDefinitions", - "apiVersion": "2023-04-01", - "name": "[parameters('initiativeName')]", - "properties": { - "displayName": "[parameters('initiativeDisplayName')]", - "description": "[parameters('initiativeDescription')]", - "version": "1.0.0", - "metadata": { - "category": "[parameters('initiativeCategory')]", - "version": "1.0.0" - }, - "policyDefinitions": "[concat(createArray(createObject('policyDefinitionReferenceId', 'EnsureContactEmail', 'policyDefinitionId', tenantResourceId('Microsoft.Authorization/policyDefinitions', '4f4f78b8-e367-4b10-a341-d9a4ad5cf1c7'), 'parameters', createObject('effect', createObject('value', 'AuditIfNotExists')))), if(parameters('enableDefForServers'), createArray(createObject('policyDefinitionReferenceId', 'DefenderForServers', 'policyDefinitionId', tenantResourceId('Microsoft.Authorization/policyDefinitions', '8e86a5b6-b9bd-49d1-8e21-4bb8a0862222'), 'parameters', createObject('effect', createObject('value', parameters('effect'))))), createArray()), if(parameters('enableDefForStorage'), createArray(createObject('policyDefinitionReferenceId', 'DefenderForStorage', 'policyDefinitionId', tenantResourceId('Microsoft.Authorization/policyDefinitions', 'cfdc5972-75b3-4418-8ae1-7f5c36839390'), 'parameters', createObject('effect', createObject('value', parameters('effect')), 'isOnUploadMalwareScanningEnabled', createObject('value', parameters('isOnUploadMalwareScanningEnabled')), 'capGBPerMonthPerStorageAccount', createObject('value', parameters('capGBPerMonthPerStorageAccount')), 'isSensitiveDataDiscoveryEnabled', createObject('value', parameters('isSensitiveDataDiscoveryEnabled'))))), createArray()), if(parameters('enableDefForKeyVault'), createArray(createObject('policyDefinitionReferenceId', 'DefenderForKeyVault', 'policyDefinitionId', tenantResourceId('Microsoft.Authorization/policyDefinitions', '1f725891-01c0-420a-9059-4fa46cb770b7'), 'parameters', createObject('effect', createObject('value', parameters('effect')), 'subPlan', createObject('value', parameters('keyVaultSubPlan'))))), createArray()), if(parameters('enableDefForArm'), createArray(createObject('policyDefinitionReferenceId', 'DefenderForARM', 'policyDefinitionId', tenantResourceId('Microsoft.Authorization/policyDefinitions', 'b7021b2b-08fd-4dc0-9de7-3c6ece09faf9'), 'parameters', createObject('effect', createObject('value', parameters('effect')), 'subPlan', createObject('value', parameters('resourceManagerSubPlan'))))), createArray()))]" - } - } - ] - } - }, - "dependsOn": [ - "sessionHosts" - ] - } - ] -} \ No newline at end of file diff --git a/workload/bicep/deploy-custom-image.bicep b/workload/bicep/deploy-custom-image.bicep index 478f2953d..37f55dc4f 100644 --- a/workload/bicep/deploy-custom-image.bicep +++ b/workload/bicep/deploy-custom-image.bicep @@ -30,8 +30,8 @@ param automationAccountCustomName string = 'aa-avd' // param avdContainerCustomName string = 'avd-artifacts' @allowed([ - 'OneTime' - 'Recurring' + 'OneTime' + 'Recurring' ]) @sys.description('Determine whether to build the image template one time or check daily for a new marketplace image and auto build when found. (Default: Recurring)') param buildSchedule string = 'Recurring' @@ -43,11 +43,11 @@ param costCenterTag string = 'Contoso-CC' param criticalityCustomTag string = 'Contoso-Critical' @allowed([ - 'Low' - 'Medium' - 'High' - 'Mission-critical' - 'Custom' + 'Low' + 'Medium' + 'High' + 'Mission-critical' + 'Custom' ]) @sys.description('criticality of each workload. (Default: Low)') param criticalityTag string = 'Low' @@ -56,11 +56,11 @@ param criticalityTag string = 'Low' param customNaming bool = false @allowed([ - 'Non-business' - 'Public' - 'General' - 'Confidential' - 'Highly Confidential' + 'Non-business' + 'Public' + 'General' + 'Confidential' + 'Highly Confidential' ]) @sys.description('Sensitivity of data hosted (Default: Non-business)') param dataClassificationTag string = 'Non-business' @@ -69,40 +69,40 @@ param dataClassificationTag string = 'Non-business' param departmentTag string = 'Contoso-AVD' @allowed([ - 'australiaeast' - 'australiasoutheast' - 'brazilsouth' - 'canadacentral' - 'centralindia' - 'centralus' - 'eastasia' - 'eastus' - 'eastus2' - 'francecentral' - 'germanywestcentral' - 'japaneast' - 'jioindiawest' - 'koreacentral' - 'northcentralus' - 'northeurope' - 'norwayeast' - 'qatarcentral' - 'southafricanorth' - 'southcentralus' - 'southeastasia' - 'switzerlandnorth' - 'uaenorth' - 'uksouth' - 'ukwest' - 'usgovarizona' - 'usgoviowa' - 'usgovtexas' - 'usgovvirginia' - 'westcentralus' - 'westeurope' - 'westus' - 'westus2' - 'westus3' + 'australiaeast' + 'australiasoutheast' + 'brazilsouth' + 'canadacentral' + 'centralindia' + 'centralus' + 'eastasia' + 'eastus' + 'eastus2' + 'francecentral' + 'germanywestcentral' + 'japaneast' + 'jioindiawest' + 'koreacentral' + 'northcentralus' + 'northeurope' + 'norwayeast' + 'qatarcentral' + 'southafricanorth' + 'southcentralus' + 'southeastasia' + 'switzerlandnorth' + 'uaenorth' + 'uksouth' + 'ukwest' + 'usgovarizona' + 'usgoviowa' + 'usgovtexas' + 'usgovvirginia' + 'westcentralus' + 'westeurope' + 'westus' + 'westus2' + 'westus3' ]) @sys.description('Location to deploy the resources in this solution, except the image template. (Default: eastus)') param deploymentLocation string = 'eastus' @@ -117,9 +117,9 @@ param enableResourceTags bool = false param enableTelemetry bool = true @allowed([ - 'Prod' - 'Dev' - 'Staging' + 'Prod' + 'Dev' + 'Staging' ]) @sys.description('Deployment environment of the application, workload. (Default: Dev)') param environmentTag string = 'Dev' @@ -151,10 +151,10 @@ param imageDefinitionAcceleratedNetworkSupported bool = true param imageDefinitionHibernateSupported bool = false @allowed([ - 'Standard' - 'TrustedLaunch' - 'ConfidentialVM' - 'ConfidentialVMSupported' + 'Standard' + 'TrustedLaunch' + 'ConfidentialVM' + 'ConfidentialVMSupported' ]) @sys.description('Choose the Security Type of the Image Definition. (Default: Standard)') param imageDefinitionSecurityType string = 'Standard' @@ -174,9 +174,9 @@ param imageVersionDisasterRecoveryLocation string = '' param imageVersionPrimaryLocation string @allowed([ - //'Premium_LRS' supported by Image Versions but not Image Templates yet - 'Standard_LRS' - 'Standard_ZRS' + //'Premium_LRS' supported by Image Versions but not Image Templates yet + 'Standard_LRS' + 'Standard_ZRS' ]) @sys.description('Determine the Storage Account Type for the Image Version distributed by the Image Template. (Default: Standard_LRS)') param imageVersionStorageAccountType string = 'Standard_LRS' @@ -189,18 +189,17 @@ param logAnalyticsWorkspaceCustomName string = 'log-avd' @sys.description('Set the data retention in the number of days for the Log Analytics Workspace. (Default: 30)') param logAnalyticsWorkspaceDataRetention int = 30 -@allowed([ - 'win10_22h2_g2' - 'win10_22h2_office_g2' - 'win11_22h2' - 'win11_22h2_office' - 'win11_23h2' - 'win11_23h2_office' - 'win11_24h2' - 'win11_24h2_office' -]) -@sys.description('AVD OS image source. (Default: win11_23h2)') -param operatingSystemImage string = 'win11_23h2' +@sys.description('Market place AVD OS image offer. (Default: Office-365)') +param mpImageOffer string = 'Office-365' + +@sys.description('Market place AVD OS image SKU. (Default: win11-24h2-avd-m365)') +param mpImageSku string = 'win11-24h2-avd-m365' + +@sys.description('Market place AVD OS image publisher.') +param mpImagePublisher string = 'MicrosoftWindowsDesktop' + +@sys.description('Market place AVD OS image version.') +param mpImageVersion string = 'latest' @sys.description('Team accountable for day-to-day operations. (Contoso-Ops)') param operationsTeamTag string = 'workload-admins@Contoso.com' @@ -254,274 +253,209 @@ param workloadNameTag string = 'Contoso-Workload' var varActionGroupName = customNaming ? alertsActionGroupCustomName : 'ag-avd-${varNamingStandard}' // Placeholder for future feature // var varAibContainerName = customNaming ? aibContainerCustomName : 'aib-artifacts' -var varAlerts = enableMonitoringAlerts ? [ - { +var varAlerts = enableMonitoringAlerts + ? [ + { name: 'Azure Image Builder - Build Failure' description: 'Sends an error alert when a build fails on an image template for Azure Image Builder.' severity: 0 evaluationFrequency: 'PT5M' windowSize: 'PT5M' criterias: { - allOf: [ + allOf: [ + { + query: 'AzureDiagnostics\n| where ResourceProvider == "MICROSOFT.AUTOMATION"\n| where Category == "JobStreams"\n| where ResultDescription has "Image Template build failed"' + timeAggregation: 'Count' + dimensions: [ { - query: 'AzureDiagnostics\n| where ResourceProvider == "MICROSOFT.AUTOMATION"\n| where Category == "JobStreams"\n| where ResultDescription has "Image Template build failed"' - timeAggregation: 'Count' - dimensions: [ - { - name: 'ResultDescription' - operator: 'Include' - values: [ - '*' - ] - } - ] - operator: 'GreaterThanOrEqual' - threshold: 1 - failingPeriods: { - numberOfEvaluationPeriods: 1 - minFailingPeriodsToAlert: 1 - } + name: 'ResultDescription' + operator: 'Include' + values: [ + '*' + ] } - ] + ] + operator: 'GreaterThanOrEqual' + threshold: 1 + failingPeriods: { + numberOfEvaluationPeriods: 1 + minFailingPeriodsToAlert: 1 + } + } + ] } - } - { + } + { name: 'Azure Image Builder - Build Success' description: 'Sends an informational alert when a build succeeds on an image template for Azure Image Builder.' severity: 3 evaluationFrequency: 'PT5M' windowSize: 'PT5M' criterias: { - allOf: [ + allOf: [ + { + query: 'AzureDiagnostics\n| where ResourceProvider == "MICROSOFT.AUTOMATION"\n| where Category == "JobStreams"\n| where ResultDescription has "Image Template build succeeded"' + timeAggregation: 'Count' + dimensions: [ { - query: 'AzureDiagnostics\n| where ResourceProvider == "MICROSOFT.AUTOMATION"\n| where Category == "JobStreams"\n| where ResultDescription has "Image Template build succeeded"' - timeAggregation: 'Count' - dimensions: [ - { - name: 'ResultDescription' - operator: 'Include' - values: [ - '*' - ] - } - ] - operator: 'GreaterThanOrEqual' - threshold: 1 - failingPeriods: { - numberOfEvaluationPeriods: 1 - minFailingPeriodsToAlert: 1 - } + name: 'ResultDescription' + operator: 'Include' + values: [ + '*' + ] } - ] + ] + operator: 'GreaterThanOrEqual' + threshold: 1 + failingPeriods: { + numberOfEvaluationPeriods: 1 + minFailingPeriodsToAlert: 1 + } + } + ] } - } -] : [] + } + ] + : [] var varAutomationAccountName = customNaming ? automationAccountCustomName : 'aa-avd-${varNamingStandard}' // Placeholder for future feature // var varAvdContainerName = customNaming ? avdContainerCustomName : 'avd-artifacts' var varAzureCloudName = environment().name var varBaseScriptUri = 'https://raw.githubusercontent.com/Azure/avdaccelerator/main/workload/' -var varCommonResourceTags = enableResourceTags ? { - ImageBuildName: imageBuildNameTag - WorkloadName: workloadNameTag - DataClassification: dataClassificationTag - Department: departmentTag - Criticality: (criticalityTag == 'Custom') ? criticalityCustomTag : criticalityTag - ApplicationName: applicationNameTag - OpsTeam: operationsTeamTag - Owner: ownerTag - CostCenter: costCenterTag - Environment: environmentTag - -} : {} +var varCommonResourceTags = enableResourceTags + ? { + ImageBuildName: imageBuildNameTag + WorkloadName: workloadNameTag + DataClassification: dataClassificationTag + Department: departmentTag + Criticality: (criticalityTag == 'Custom') ? criticalityCustomTag : criticalityTag + ApplicationName: applicationNameTag + OpsTeam: operationsTeamTag + Owner: ownerTag + CostCenter: costCenterTag + Environment: environmentTag + } + : {} var varCustomizationSteps = union(varScriptCustomizers, varRemainingCustomizers) -var varImageDefinitionName = customNaming ? imageDefinitionCustomName : 'avd-${operatingSystemImage}' +var varImageDefinitionName = customNaming ? imageDefinitionCustomName : 'avd-${mpImageOffer}-${mpImageSku}' var varImageGalleryName = customNaming ? imageGalleryCustomName : 'gal_avd_${varNamingStandard}' -var varImageReplicationRegions = empty(imageVersionDisasterRecoveryLocation) ? [ - imageVersionPrimaryLocation -] : [ - imageVersionPrimaryLocation - imageVersionDisasterRecoveryLocation -] +var varImageReplicationRegions = empty(imageVersionDisasterRecoveryLocation) + ? [ + imageVersionPrimaryLocation + ] + : [ + imageVersionPrimaryLocation + imageVersionDisasterRecoveryLocation + ] // Image template permissions are currently (1/6/23) not supported in Azure US Government var varImageTemplateBuildAutomationName = 'Image Template Build Automation' -var varImageTemplateBuildAutomation = varAzureCloudName == 'AzureCloud' ? [ - { +var varImageTemplateBuildAutomation = varAzureCloudName == 'AzureCloud' + ? [ + { resourceGroup: varResourceGroupName name: varImageTemplateBuildAutomationName description: 'Allow Image Template build automation using a Managed Identity on an Automation Account.' actions: [ - 'Microsoft.VirtualMachineImages/imageTemplates/run/action' - 'Microsoft.VirtualMachineImages/imageTemplates/read' - 'Microsoft.Compute/locations/publishers/artifacttypes/offers/skus/versions/read' - 'Microsoft.Compute/locations/publishers/artifacttypes/offers/skus/read' - 'Microsoft.Compute/locations/publishers/artifacttypes/offers/read' - 'Microsoft.Compute/locations/publishers/read' + 'Microsoft.VirtualMachineImages/imageTemplates/run/action' + 'Microsoft.VirtualMachineImages/imageTemplates/read' + 'Microsoft.Compute/locations/publishers/artifacttypes/offers/skus/versions/read' + 'Microsoft.Compute/locations/publishers/artifacttypes/offers/skus/read' + 'Microsoft.Compute/locations/publishers/artifacttypes/offers/read' + 'Microsoft.Compute/locations/publishers/read' ] - } -] : [] + } + ] + : [] var varImageTemplateContributorRoleName = 'Image Template Contributor' var varImageTemplateContributorRole = [ - { - resourceGroup: varResourceGroupName - name: varImageTemplateContributorRoleName - description: 'Allow the creation and management of images' - actions: [ - 'Microsoft.Compute/galleries/read' - 'Microsoft.Compute/galleries/images/read' - 'Microsoft.Compute/galleries/images/versions/read' - 'Microsoft.Compute/galleries/images/versions/write' - 'Microsoft.Compute/images/read' - 'Microsoft.Compute/images/write' - 'Microsoft.Compute/images/delete' - ] - } + { + resourceGroup: varResourceGroupName + name: varImageTemplateContributorRoleName + description: 'Allow the creation and management of images' + actions: [ + 'Microsoft.Compute/galleries/read' + 'Microsoft.Compute/galleries/images/read' + 'Microsoft.Compute/galleries/images/versions/read' + 'Microsoft.Compute/galleries/images/versions/write' + 'Microsoft.Compute/images/read' + 'Microsoft.Compute/images/write' + 'Microsoft.Compute/images/delete' + ] + } ] -var varImageTemplateName = customNaming ? imageTemplateCustomName : 'it-avd-${operatingSystemImage}' +var varImageTemplateName = customNaming ? imageTemplateCustomName : 'it-avd-${mpImageOffer}' var varLocationAcronym = varLocations[varLocation].acronym var varLocation = toLower(replace(deploymentLocation, ' ', '')) var varLocations = loadJsonContent('../variables/locations.json') var varLogAnalyticsWorkspaceName = customNaming ? logAnalyticsWorkspaceCustomName : 'log-avd-${varNamingStandard}' var varModules = [ - { - name: 'Az.Accounts' - uri: 'https://www.powershellgallery.com/api/v2/package' - version: '2.12.1' - } - { - name: 'Az.ImageBuilder' - uri: 'https://www.powershellgallery.com/api/v2/package' - version: '0.3.0' - } + { + name: 'Az.Accounts' + uri: 'https://www.powershellgallery.com/api/v2/package' + version: '4.0.2' + } + { + name: 'Az.ImageBuilder' + uri: 'https://www.powershellgallery.com/api/v2/package' + version: '0.4.1' + } ] var varNamingStandard = '${varLocationAcronym}' -var varOperatingSystemImageDefinitions = { - win10_22h2_g2: { - osType: 'Windows' - osState: 'Generalized' - offer: 'windows-10' - publisher: 'MicrosoftWindowsDesktop' - sku: 'win10-22h2-avd-g2' - hyperVGeneration: 'V2' - version: 'latest' - } - win10_22h2_office_g2: { - osType: 'Windows' - osState: 'Generalized' - offer: 'office-365' - publisher: 'MicrosoftWindowsDesktop' - sku: 'win10-22h2-avd-m365-g2' - hyperVGeneration: 'V2' - version: 'latest' - } - win11_22h2: { - osType: 'Windows' - osState: 'Generalized' - offer: 'windows-11' - publisher: 'MicrosoftWindowsDesktop' - sku: 'win11-22h2-avd' - hyperVGeneration: 'V2' - version: 'latest' - } - win11_22h2_office: { - osType: 'Windows' - osState: 'Generalized' - offer: 'office-365' - publisher: 'MicrosoftWindowsDesktop' - sku: 'win11-22h2-avd-m365' - hyperVGeneration: 'V2' - version: 'latest' - } - win11_23h2: { - osType: 'Windows' - osState: 'Generalized' - offer: 'windows-11' - publisher: 'MicrosoftWindowsDesktop' - sku: 'win11-23h2-avd' - hyperVGeneration: 'V2' - version: 'latest' - } - win11_23h2_office: { - osType: 'Windows' - osState: 'Generalized' - offer: 'office-365' - publisher: 'MicrosoftWindowsDesktop' - sku: 'win11-23h2-avd-m365' - hyperVGeneration: 'V2' - version: 'latest' - } - win11_24h2: { - osType: 'Windows' - osState: 'Generalized' - offer: 'windows-11' - publisher: 'MicrosoftWindowsDesktop' - sku: 'win11-24h2-avd' - hyperVGeneration: 'V2' - version: 'latest' - } - win11_24h2_office: { - osType: 'Windows' - osState: 'Generalized' - offer: 'office-365' - publisher: 'MicrosoftWindowsDesktop' - sku: 'win11-24h2-avd-m365' - hyperVGeneration: 'V2' - version: 'latest' - } -} -var varRdpShortPathCustomizer = rdpShortPathManagedNetworks ? [ - { +var varRdpShortPathCustomizer = rdpShortPathManagedNetworks + ? [ + { type: 'PowerShell' name: 'rdpShortPath' runElevated: true runAsSystem: true scriptUri: '${varBaseScriptUri}scripts/Set-RdpShortpath.ps1' - } -] : [] + } + ] + : [] var varRemainingCustomizers = [ - { - type: 'WindowsRestart' - restartCheckCommand: 'Write-Host "Restarting post script customizers"' - restarttimeout: '10m' - } - { - type: 'WindowsUpdate' - searchCriteria: 'IsInstalled=0' - filters: [ - 'exclude:$_.Title -like \'*Preview*\'' - 'include:$true' - ] - updateLimit: 40 - } - { - type: 'PowerShell' - name: 'Sleep for 5 minutes' - runElevated: true - runAsSystem: true - inline: [ - 'Write-Host "Sleep for 5 min"' - 'Start-Sleep -Seconds 300' - ] - } - { - type: 'WindowsRestart' - restartCheckCommand: 'Write-Host "restarting post Windows updates"' - restarttimeout: '10m' - } - { - type: 'PowerShell' - name: 'Sleep for a min' - runElevated: true - runAsSystem: true - inline: [ - 'Write-Host "Sleep for a min"' - 'Start-Sleep -Seconds 60' - ] - } - { - type: 'WindowsRestart' - restarttimeout: '10m' - } + { + type: 'WindowsRestart' + restartCheckCommand: 'Write-Host "Restarting post script customizers"' + restartTimeout: '10m' + } + { + type: 'WindowsUpdate' + searchCriteria: 'IsInstalled=0' + filters: [ + 'exclude:$_.Title -like \'*Preview*\'' + 'include:$true' + ] + updateLimit: 40 + } + { + type: 'PowerShell' + name: 'Sleep for 5 minutes' + runElevated: true + runAsSystem: true + inline: [ + 'Write-Host "Sleep for 5 min"' + 'Start-Sleep -Seconds 300' + ] + } + { + type: 'WindowsRestart' + restartCheckCommand: 'Write-Host "restarting post Windows updates"' + restartTimeout: '10m' + } + { + type: 'PowerShell' + name: 'Sleep for a min' + runElevated: true + runAsSystem: true + inline: [ + 'Write-Host "Sleep for a min"' + 'Start-Sleep -Seconds 60' + ] + } + { + type: 'WindowsRestart' + restartTimeout: '10m' + } ] var varResourceGroupName = customNaming ? resourceGroupCustomName : 'rg-avd-${varNamingStandard}-shared-services' //var varRoles = union(varVirtualNetworkJoinRoleExistingRoleCheck, varRolesimageTemplateBuildAutomationExistingRoleCheck, varImageTemplateContributorRoleExistingRoleCheck) @@ -529,15 +463,17 @@ var varRoles = union(varVirtualNetworkJoinRole, varImageTemplateBuildAutomation, //var varRolesimageTemplateBuildAutomationExistingRoleCheck = empty(imageTemplateBuildAutomationExistingRoleCheck.id) ? varImageTemplateBuildAutomation : [] //var varImageTemplateContributorRoleExistingRoleCheck = empty(imageTemplateContributorExistingRoleCheck.id) ? varImageTemplateContributorRole : [] //var varVirtualNetworkJoinRoleExistingRoleCheck = empty(virtualNetworkJoinExistingRoleCheck.id) ? varVirtualNetworkJoinRole : [] -var varScreenCaptureProtectionCustomizer = screenCaptureProtection ? [ - { +var varScreenCaptureProtectionCustomizer = screenCaptureProtection + ? [ + { type: 'PowerShell' name: 'screenCaptureProtection' runElevated: true runAsSystem: true scriptUri: '${varBaseScriptUri}scripts/Set-ScreenCaptureProtection.ps1' - } -] : [] + } + ] + : [] var varScriptCustomizers = union(varRdpShortPathCustomizer, varScreenCaptureProtectionCustomizer) // Placeholder for future feature // var varStorageAccountName = customNaming ? storageAccountCustomName : 'stavd${varNamingStandard}${varUniqueStringSixChar}' @@ -546,20 +482,24 @@ var varTimeZone = varLocations[varLocation].timeZone // Placeholder for future feature // var varUniqueStringSixChar = take('${uniqueString(sharedServicesSubId, time)}', 6) -var varUserAssignedManagedIdentityName = customNaming ? userAssignedManagedIdentityCustomName : 'id-aib-${varNamingStandard}' +var varUserAssignedManagedIdentityName = customNaming + ? userAssignedManagedIdentityCustomName + : 'id-aib-${varNamingStandard}' var varVirtualNetworkJoinRoleName = 'Virtual Network Join' -var varVirtualNetworkJoinRole = useExistingVirtualNetwork ? [ - { +var varVirtualNetworkJoinRole = useExistingVirtualNetwork + ? [ + { resourceGroup: split(existingVirtualNetworkResourceId, '/')[4] name: varVirtualNetworkJoinRoleName description: 'Allow resources to join a subnet' actions: [ - 'Microsoft.Network/virtualNetworks/read' - 'Microsoft.Network/virtualNetworks/subnets/read' - 'Microsoft.Network/virtualNetworks/subnets/join/action' + 'Microsoft.Network/virtualNetworks/read' + 'Microsoft.Network/virtualNetworks/subnets/read' + 'Microsoft.Network/virtualNetworks/subnets/join/action' ] - } -] : [] + } + ] + : [] var varVmSize = 'Standard_D4s_v3' // =========== // @@ -568,27 +508,27 @@ var varVmSize = 'Standard_D4s_v3' // Telemetry Deployment. resource telemetryDeployment 'Microsoft.Resources/deployments@2021-04-01' = if (enableTelemetry) { - name: varTelemetryId - location: deploymentLocation - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - } - } + name: varTelemetryId + location: deploymentLocation + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } } // AVD Shared Services Resource Group. -module avdSharedResourcesRg '../../avm/1.0.0/res/resources/resource-group/main.bicep' = { - scope: subscription(sharedServicesSubId) - name: 'RG-${time}' - params: { - name: varResourceGroupName - location: deploymentLocation - tags: enableResourceTags ? varCommonResourceTags : {} - } +module avdSharedResourcesRg '../../avm/1.1.0/res/resources/resource-group/main.bicep' = { + scope: subscription(sharedServicesSubId) + name: 'RG-${time}' + params: { + name: varResourceGroupName + location: deploymentLocation + tags: enableResourceTags ? varCommonResourceTags : {} + } } /* // Role definition check Image Template Build Automation. @@ -608,289 +548,311 @@ resource virtualNetworkJoinExistingRoleCheck 'Microsoft.Authorization/roleDefini */ // Role definition deployment. -module roleDefinitions './modules/rbacRoles/roleDefinitionsSubscriptions.bicep' = [for i in range(0, length(varRoles)): { +module roleDefinitions './modules/rbacRoles/roleDefinitionsSubscriptions.bicep' = [ + for i in range(0, length(varRoles)): { scope: subscription(sharedServicesSubId) name: 'Role-Definition-${i}-${time}' params: { - subscriptionId: sharedServicesSubId - description: varRoles[i].description - roleName: varRoles[i].name - actions: varRoles[i].actions - assignableScopes: [ - '/subscriptions/${sharedServicesSubId}' - ] - } -}] + subscriptionId: sharedServicesSubId + description: varRoles[i].description + roleName: varRoles[i].name + actions: varRoles[i].actions + assignableScopes: [ + '/subscriptions/${sharedServicesSubId}' + ] + } + } +] // Managed identity. -module userAssignedManagedIdentity '../../avm/1.0.0/res/managed-identity/user-assigned-identity/main.bicep' = { - scope: resourceGroup(sharedServicesSubId, varResourceGroupName) - name: 'User-Assigned-Managed-Identity-${time}' - params: { - name: varUserAssignedManagedIdentityName - location: deploymentLocation - tags: enableResourceTags ? varCommonResourceTags : {} - } - dependsOn: [ - avdSharedResourcesRg - ] +module userAssignedManagedIdentity '../../avm/1.1.0/res/managed-identity/user-assigned-identity/main.bicep' = { + scope: resourceGroup(sharedServicesSubId, varResourceGroupName) + name: 'User-Assigned-Managed-Identity-${time}' + params: { + name: varUserAssignedManagedIdentityName + location: deploymentLocation + tags: enableResourceTags ? varCommonResourceTags : {} + } + dependsOn: [ + avdSharedResourcesRg + ] } // Role assignments. -module roleAssignments '../../avm/1.0.0/ptn/authorization/role-assignment/modules/resource-group.bicep' = [for i in range(0, length(varRoles)): { +module roleAssignments '../../avm/1.0.0/ptn/authorization/role-assignment/modules/resource-group.bicep' = [ + for i in range(0, length(varRoles)): { name: 'Role-Assignment-${i}-${time}' scope: resourceGroup(sharedServicesSubId, varRoles[i].resourceGroup) params: { - roleDefinitionIdOrName: roleDefinitions[i].outputs.resourceId - principalId: userAssignedManagedIdentity.outputs.principalId - principalType: 'ServicePrincipal' + roleDefinitionIdOrName: roleDefinitions[i].outputs.resourceId + principalId: userAssignedManagedIdentity.outputs.principalId + principalType: 'ServicePrincipal' } -}] + } +] //// Unique role assignment for Azure US Government since it does not support image template permissions -module roleAssignment_AzureUSGovernment '../../avm/1.0.0/ptn/authorization/role-assignment/modules/resource-group.bicep' = if (varAzureCloudName != 'AzureCloud') { - name: 'Role-Assignment-MAG-${time}' - scope: resourceGroup(sharedServicesSubId, varResourceGroupName) - params: { - roleDefinitionIdOrName: 'Contributor' - principalId: userAssignedManagedIdentity.outputs.principalId - principalType: 'ServicePrincipal' - } +module roleAssignment_AzureUSGovernment '../../avm/1.1.0/ptn/authorization/role-assignment/modules/resource-group.bicep' = if (varAzureCloudName != 'AzureCloud') { + name: 'Role-Assignment-MAG-${time}' + scope: resourceGroup(sharedServicesSubId, varResourceGroupName) + params: { + roleDefinitionIdOrName: 'Contributor' + principalId: userAssignedManagedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + } } // Compute Gallery. -module gallery '../../avm/1.0.0/res/compute/gallery/main.bicep' = { - scope: resourceGroup(sharedServicesSubId, varResourceGroupName) - name: 'Compute-Gallery-${time}' - params: { - name: varImageGalleryName - location: imageVersionPrimaryLocation - description: 'Azure Virtual Desktops Images' - tags: enableResourceTags ? varCommonResourceTags : {} - } - dependsOn: [ - avdSharedResourcesRg - ] +module gallery '../../avm/1.1.0/res/compute/gallery/main.bicep' = { + scope: resourceGroup(sharedServicesSubId, varResourceGroupName) + name: 'Compute-Gallery-${time}' + params: { + name: varImageGalleryName + location: imageVersionPrimaryLocation + description: 'Azure Virtual Desktops Images' + tags: enableResourceTags ? varCommonResourceTags : {} + } + dependsOn: [ + avdSharedResourcesRg + ] } // Image Definition. -module image '../../avm/1.0.0/res/compute/gallery/image/main.bicep' = { - scope: resourceGroup(sharedServicesSubId, varResourceGroupName) - name: 'Image-Definition-${time}' - params: { - galleryName: varImageGalleryName - name: varImageDefinitionName - osState: varOperatingSystemImageDefinitions[operatingSystemImage].osState - osType: varOperatingSystemImageDefinitions[operatingSystemImage].osType - publisher: varOperatingSystemImageDefinitions[operatingSystemImage].publisher - offer: varOperatingSystemImageDefinitions[operatingSystemImage].offer - sku: varOperatingSystemImageDefinitions[operatingSystemImage].sku - location: imageVersionPrimaryLocation - hyperVGeneration: varOperatingSystemImageDefinitions[operatingSystemImage].hyperVGeneration - isAcceleratedNetworkSupported: imageDefinitionAcceleratedNetworkSupported - isHibernateSupported: imageDefinitionHibernateSupported - securityType: imageDefinitionSecurityType - //productName: operatingSystemImage - //planName: varOperatingSystemImageDefinitions[operatingSystemImage].offer - //planPublisherName: varOperatingSystemImageDefinitions[operatingSystemImage].publisher - tags: enableResourceTags ? varCommonResourceTags : {} - } - dependsOn: [ - gallery - avdSharedResourcesRg - ] +module image '../../avm/1.1.0/res/compute/gallery/image/main.bicep' = { + scope: resourceGroup(sharedServicesSubId, varResourceGroupName) + name: 'Image-Definition-${time}' + params: { + galleryName: varImageGalleryName + name: varImageDefinitionName + osState: 'Generalized' + osType: 'Windows' + identifier: { + publisher: mpImagePublisher + offer: mpImageOffer + sku: mpImageSku + } + location: imageVersionPrimaryLocation + hyperVGeneration: 'V2' + isAcceleratedNetworkSupported: imageDefinitionAcceleratedNetworkSupported + isHibernateSupported: imageDefinitionHibernateSupported + securityType: imageDefinitionSecurityType + tags: enableResourceTags ? varCommonResourceTags : {} + } + dependsOn: [ + gallery + avdSharedResourcesRg + ] } - - // Image template. -module imageTemplate '../../avm/1.0.0/res/virtual-machine-images/image-template/main.bicep' = { - scope: resourceGroup(sharedServicesSubId, varResourceGroupName) - name: 'Image-Template-${time}' - params: { - name: varImageTemplateName - subnetResourceId: !empty(existingVirtualNetworkResourceId) && !empty(existingSubnetName) ? '${existingVirtualNetworkResourceId}/subnets/${existingSubnetName}' : '' - managedIdentities: { - userAssignedResourceIds: [ - userAssignedManagedIdentity.outputs.resourceId - ] - } - location: deploymentLocation - distributions: [ - { - type: 'SharedImage' - replicationRegions: varImageReplicationRegions - storageAccountType: imageVersionStorageAccountType - sharedImageGalleryImageDefinitionResourceId: image.outputs.resourceId - } - ] - vmSize: varVmSize - customizationSteps: varCustomizationSteps - imageSource: { - type: 'PlatformImage' - publisher: varOperatingSystemImageDefinitions[operatingSystemImage].publisher - offer: varOperatingSystemImageDefinitions[operatingSystemImage].offer - sku: varOperatingSystemImageDefinitions[operatingSystemImage].sku - version: varOperatingSystemImageDefinitions[operatingSystemImage].version - } - tags: enableResourceTags ? varCommonResourceTags : {} +module imageTemplate '../../avm/1.1.0/res/virtual-machine-images/image-template/main.bicep' = { + scope: resourceGroup(sharedServicesSubId, varResourceGroupName) + name: 'Image-Template-${time}' + params: { + name: varImageTemplateName + subnetResourceId: !empty(existingVirtualNetworkResourceId) && !empty(existingSubnetName) + ? '${existingVirtualNetworkResourceId}/subnets/${existingSubnetName}' + : '' + managedIdentities: { + userAssignedResourceIds: [ + userAssignedManagedIdentity.outputs.resourceId + ] } - dependsOn: [ - image - gallery - avdSharedResourcesRg - roleAssignments + location: deploymentLocation + distributions: [ + { + type: 'SharedImage' + replicationRegions: varImageReplicationRegions + storageAccountType: imageVersionStorageAccountType + sharedImageGalleryImageDefinitionResourceId: image.outputs.resourceId + } ] + vmSize: varVmSize + customizationSteps: varCustomizationSteps + imageSource: { + type: 'PlatformImage' + publisher: mpImagePublisher + offer: mpImageOffer + sku: mpImageSku + version: mpImageVersion + } + tags: enableResourceTags ? varCommonResourceTags : {} + } + dependsOn: [ + gallery + avdSharedResourcesRg + roleAssignments + ] } // Log Analytics Workspace. -module workspace '../../avm/1.0.0/res/operational-insights/workspace/main.bicep' = if (enableMonitoringAlerts && empty(existingLogAnalyticsWorkspaceResourceId)) { - scope: resourceGroup(sharedServicesSubId, varResourceGroupName) - name: 'Log-Analytics-Workspace-${time}' - params: { - location: deploymentLocation - name: varLogAnalyticsWorkspaceName - dataRetention: logAnalyticsWorkspaceDataRetention - useResourcePermissions: true - tags: enableResourceTags ? varCommonResourceTags : {} - } - dependsOn: [ - avdSharedResourcesRg - ] +module workspace '../../avm/1.1.0/res/operational-insights/workspace/main.bicep' = if (enableMonitoringAlerts && empty(existingLogAnalyticsWorkspaceResourceId)) { + scope: resourceGroup(sharedServicesSubId, varResourceGroupName) + name: 'Log-Analytics-Workspace-${time}' + params: { + location: deploymentLocation + name: varLogAnalyticsWorkspaceName + dataRetention: logAnalyticsWorkspaceDataRetention + features: { + enableLogAccessUsingOnlyResourcePermissions: true + } + tags: enableResourceTags ? varCommonResourceTags : {} + } + dependsOn: [ + avdSharedResourcesRg + ] } // Automation account. -module automationAccount '../../avm/1.0.0/res/automation/automation-account/main.bicep' = { - scope: resourceGroup(sharedServicesSubId, varResourceGroupName) - name: 'Automation-Account-${time}' - params: { - diagnosticSettings: enableMonitoringAlerts ? [ - { - workspaceResourceId: empty(alertsDistributionGroup) ? '' : empty(existingLogAnalyticsWorkspaceResourceId) ? workspace.outputs.resourceId : existingLogAnalyticsWorkspaceResourceId - } - ] : [ - +module automationAccount '../../avm/1.1.0/res/automation/automation-account/main.bicep' = { + scope: resourceGroup(sharedServicesSubId, varResourceGroupName) + name: 'Automation-Account-${time}' + params: { + diagnosticSettings: enableMonitoringAlerts + ? [ + { + workspaceResourceId: empty(alertsDistributionGroup) + ? '' + : empty(existingLogAnalyticsWorkspaceResourceId) + ? workspace.outputs.resourceId + : existingLogAnalyticsWorkspaceResourceId + } ] - name: varAutomationAccountName - jobSchedules: [ - { - parameters: { - ClientId: userAssignedManagedIdentity.outputs.clientId - EnvironmentName: varAzureCloudName - ImageOffer: varOperatingSystemImageDefinitions[operatingSystemImage].offer - ImagePublisher: varOperatingSystemImageDefinitions[operatingSystemImage].publisher - ImageSku: varOperatingSystemImageDefinitions[operatingSystemImage].sku - Location: deploymentLocation - SubscriptionId: sharedServicesSubId - TemplateName: imageTemplate.outputs.name - TemplateResourceGroupName: varResourceGroupName - TenantId: subscription().tenantId - } - runbookName: 'aib-build-automation' - scheduleName: varImageTemplateName - } - ] - location: deploymentLocation - runbooks: [ - { - name: 'aib-build-automation' - description: 'When this runbook is triggered, last build date is checked on the AIB image template. If a new marketplace image has been released since that date, a new build is initiated. If a build has never been initiated then it will be start one.' - type: 'PowerShell' - // ToDo: Update URL before PR merge - uri: 'https://raw.githubusercontent.com/Azure/avdaccelerator/main/workload/scripts/New-AzureImageBuilderBuild.ps1' - version: '1.0.0.0' - } - ] - schedules: [ - { - name: varImageTemplateName - frequency: buildSchedule == 'OneTime' ? 'OneTime' : 'Day' - interval: buildSchedule == 'OneTime' ? 0 : 1 - starttime: dateTimeAdd(time, 'PT15M') - varTimeZone: varTimeZone - advancedSchedule: {} // required to prevent deployment failure - } - ] - skuName: 'Free' - tags: enableResourceTags ? varCommonResourceTags : {} - managedIdentities: { - systemAssigned: false - userAssignedResourceIds: [ - userAssignedManagedIdentity.outputs.resourceId - ] + : [] + name: varAutomationAccountName + jobSchedules: [ + { + parameters: { + ClientId: userAssignedManagedIdentity.outputs.clientId + EnvironmentName: varAzureCloudName + ImageOffer: mpImageOffer + ImagePublisher: mpImagePublisher + ImageSku: mpImageSku + Location: deploymentLocation + SubscriptionId: sharedServicesSubId + TemplateName: imageTemplate.outputs.name + TemplateResourceGroupName: varResourceGroupName + TenantId: subscription().tenantId } - } - dependsOn: empty(existingLogAnalyticsWorkspaceResourceId) ? [ + runbookName: 'aib-build-automation' + scheduleName: varImageTemplateName + } + ] + location: deploymentLocation + runbooks: [ + { + name: 'aib-build-automation' + description: 'When this runbook is triggered, last build date is checked on the AIB image template. If a new marketplace image has been released since that date, a new build is initiated. If a build has never been initiated then it will be start one.' + type: 'PowerShell' + // ToDo: Update URL before PR merge + uri: 'https://raw.githubusercontent.com/Azure/avdaccelerator/main/workload/scripts/New-AzureImageBuilderBuild.ps1' + version: '1.0.0.0' + } + ] + schedules: [ + { + name: varImageTemplateName + frequency: buildSchedule == 'OneTime' ? 'OneTime' : 'Day' + interval: buildSchedule == 'OneTime' ? 0 : 1 + starttime: dateTimeAdd(time, 'PT15M') + varTimeZone: varTimeZone + advancedSchedule: {} // required to prevent deployment failure + } + ] + skuName: 'Free' + tags: enableResourceTags ? varCommonResourceTags : {} + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + userAssignedManagedIdentity.outputs.resourceId + ] + } + } + dependsOn: empty(existingLogAnalyticsWorkspaceResourceId) + ? [ workspace - ] : [] + ] + : [] } // Automation accounts. @batchSize(1) -module modules '../../avm/1.0.0/res/automation/automation-account/module/main.bicep' = [for i in range(0, length(varModules)): { +module modules '../../avm/1.1.0/res/automation/automation-account/module/main.bicep' = [ + for i in range(0, length(varModules)): { scope: resourceGroup(sharedServicesSubId, varResourceGroupName) name: 'AA-Module-${i}-${time}' params: { - name: varModules[i].name - location: deploymentLocation - automationAccountName: automationAccount.outputs.name - uri: varModules[i].uri - version: varModules[i].version + name: varModules[i].name + location: deploymentLocation + automationAccountName: automationAccount.outputs.name + uri: varModules[i].uri + version: varModules[i].version } -}] + } +] // Action groups. -module actionGroup '../../avm/1.0.0/res/insights/action-group/main.bicep' = if (enableMonitoringAlerts) { - scope: resourceGroup(sharedServicesSubId, varResourceGroupName) - name: 'Action-Group-${time}' - params: { - location: 'global' - groupShortName: 'aib-email' - name: varActionGroupName - enabled: true - emailReceivers: [ - { - name: alertsDistributionGroup - emailAddress: alertsDistributionGroup - useCommonvarAlertschema: true - } - ] - tags: enableResourceTags ? varCommonResourceTags : {} - } - dependsOn: [ - avdSharedResourcesRg +module actionGroup '../../avm/1.1.0/res/insights/action-group/main.bicep' = if (enableMonitoringAlerts) { + scope: resourceGroup(sharedServicesSubId, varResourceGroupName) + name: 'Action-Group-${time}' + params: { + location: 'global' + groupShortName: 'aib-email' + name: varActionGroupName + enabled: true + emailReceivers: [ + { + name: alertsDistributionGroup + emailAddress: alertsDistributionGroup + useCommonvarAlertschema: true + } ] + tags: enableResourceTags ? varCommonResourceTags : {} + } + dependsOn: [ + avdSharedResourcesRg + ] } // Schedules. -module scheduledQueryRules '../../avm/1.0.0/res/insights/scheduled-query-rule/main.bicep' = [for i in range(0, length(varAlerts)): if (enableMonitoringAlerts) { +module scheduledQueryRules '../../avm/1.1.0/res/insights/scheduled-query-rule/main.bicep' = [ + for i in range(0, length(varAlerts)): if (enableMonitoringAlerts) { scope: resourceGroup(sharedServicesSubId, varResourceGroupName) name: 'Scheduled-Query-Rule-${i}-${time}' params: { - location: deploymentLocation - name: varAlerts[i].name - alertDescription: varAlerts[i].description - enabled: true - kind: 'LogAlert' - autoMitigate: false - skipQueryValidation: false - targetResourceTypes: [] - roleAssignments: [] - scopes: empty(alertsDistributionGroup) ? [] : empty(existingLogAnalyticsWorkspaceResourceId) ? [ - workspace.outputs.resourceId - ] : [ - existingLogAnalyticsWorkspaceResourceId - ] - severity: varAlerts[i].severity - evaluationFrequency: varAlerts[i].evaluationFrequency - windowSize: varAlerts[i].windowSize - actions: !empty(alertsDistributionGroup) ? [ + location: deploymentLocation + name: varAlerts[i].name + alertDescription: varAlerts[i].description + enabled: true + kind: 'LogAlert' + autoMitigate: false + skipQueryValidation: false + targetResourceTypes: [] + roleAssignments: [] + scopes: empty(alertsDistributionGroup) + ? [] + : empty(existingLogAnalyticsWorkspaceResourceId) + ? [ + workspace.outputs.resourceId + ] + : [ + existingLogAnalyticsWorkspaceResourceId + ] + severity: varAlerts[i].severity + evaluationFrequency: varAlerts[i].evaluationFrequency + windowSize: varAlerts[i].windowSize + actions: !empty(alertsDistributionGroup) + ? [ actionGroup.outputs.resourceId - ] : [] - criterias: varAlerts[i].criterias - tags: enableResourceTags ? varCommonResourceTags : {} - } - dependsOn: empty(existingLogAnalyticsWorkspaceResourceId) ? [ - workspace - ] : [] -}] + ] + : [] + criterias: varAlerts[i].criterias + tags: enableResourceTags ? varCommonResourceTags : {} + } + dependsOn: empty(existingLogAnalyticsWorkspaceResourceId) + ? [ + workspace + ] + : [] + } +] From d4e6dc6cbf581c968f89a3bf863513d96295ef94 Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Thu, 10 Apr 2025 09:58:46 -0500 Subject: [PATCH 51/55] updates --- avm/1.1.0/res/compute/gallery/image/main.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/1.1.0/res/compute/gallery/image/main.bicep b/avm/1.1.0/res/compute/gallery/image/main.bicep index ae277e2cf..e5f2cb520 100644 --- a/avm/1.1.0/res/compute/gallery/image/main.bicep +++ b/avm/1.1.0/res/compute/gallery/image/main.bicep @@ -180,7 +180,7 @@ resource image 'Microsoft.Compute/galleries/images@2024-03-03' = { osState: osState osType: osType privacyStatementUri: privacyStatementUri - purchasePlan: purchasePlan ?? null + //purchasePlan: purchasePlan ?? null recommended: { vCPUs: vCPUs, memory: memory } releaseNoteUri: releaseNoteUri } From f0b56cfdd8c87a864ab905756d6b367c74ff353e Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Thu, 10 Apr 2025 10:41:05 -0500 Subject: [PATCH 52/55] updates --- .../scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 b/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 index 834ee0ab8..4fd2f09d1 100644 --- a/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 +++ b/workload/scripts/DSCStorageScripts/1.0.3/Script-DomainJoinStorage.ps1 @@ -125,6 +125,7 @@ if ($IdentityServiceProvider -eq 'ADDS' && $StorageService -eq 'AzureFiles') { Join-AzStorageAccount -ResourceGroupName $StorageAccountRG -StorageAccountName $StorageAccountName -OrganizationalUnitDistinguishedName $OUName -DomainAccountType 'ComputerAccount' -OverwriteExistingADObject #-SamAccountName $SamAccountName Write-Log -Message "Successfully domain joined the storage account $StorageAccountName to custom OU path $OUName" } +} if ($IdentityServiceProvider -eq 'EntraDS' && $StorageService -eq 'AzureFiles') { Write-Log "Domain joining storage account $StorageAccountName in Resource group $StorageAccountRG" From 13df835883b08e02d27c69076454424bd15ec78d Mon Sep 17 00:00:00 2001 From: Dany Contreras Date: Thu, 10 Apr 2025 10:48:36 -0500 Subject: [PATCH 53/55] updates --- .../1.0.3/DSCStorageScripts.zip | Bin 173662 -> 86944 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip b/workload/scripts/DSCStorageScripts/1.0.3/DSCStorageScripts.zip index 9aeab669f52807d6b11c6a67917dd8d0f0d21f1c..8d670855d9cdbf06bfa501b8be4e3b1c76ef7ff6 100644 GIT binary patch delta 4361 zcmZ8lbyU>d)}A30P>G>iV1{~e=&pB2hpwR;0R@Kc@CPEGNF$9PEhQ--AUTwTNI9f* zhzuzq@!@;F_1$~Fv)9>w?Pr~5@3q%@_Sp+VByURy@9C)H6HtMOZp;W3op=ucoUETX zPH&tzE+s5E&YPg!X8S3wDnMss_@*ybryece_v4QF7|M&4oW~|v^CGK;m#R69zFKm_ z>(osX^{-Dx_|hQA@l*>5BXfCZYX7{WWo`y`(&{8f-Z|iEv|zu7_58G1G(nxy_EdKn zc*;wi<+Vu|HneQ5NxeFd=TD=<>ZgpF3Gqg{GH~?frdd!G; zatGtdZOuT(XHrcrxEsr6;ohj;`w$Hb0}VCc9mjk29jt;Sa$aiCNmwtU9_rJ?uK+~Q>@E1lhLR}N6~@LK%)lrBfl zMKKvl3cBb$b%YWV(zvQ?ykifh`Oo&u8IDStYng_McEKMiq$KI8DA@TaJ zd%}6A(aMRpiPjD$nD>t++~ zo)L^RGSQg`%OJN_X7V=Y(FXE1FPpJTze>gS%EI${uX)00p>ArkffmmMAX3XsU{88) zS-CB2woxfnKSoE<(^Qswx6Qe3J?gj!!p0YC`}%J*@OwFzT{0QWVak^ArNtFs%Xd#d zfEjaYUSzA&>gD4+Xd%qmBzw87&IqW>n_y%$UXyIZ$}n}*EuIA)8qf-zUxz4Xd%z4g zk00ulkavNdz2-oiIT^l}c_}`%MhSoNv4K`_pwUG5)SaeS+l-@C-I;J?&l9H@`@#57 zk{N1%_5K;2zG$*${;YA>7YV3}v$c_iQjbI?eGtB|8T;>@`=zqsvMKiuzJ)&|``(4q z42v)pC!jG=$*(T!f7lH%6GYLrFof+u&##ya?@;hr!}9yBX+n>DOFmlKbs+}jYz}Tq zpsd+=3-qEP)nl&>r2Rwh641dZUlLZU)Yq;8n&+xb2)W0dp-1KS7CVY})Pj zKArN8>D9a6i%`>Q;^tR8xLUz)}`2csVvmH zpTgDcduH@T@?@N(v&gs4cb_(S7`O^H8Po8?QdXz#WynuV5=-%K%CB!Fw-k!gSzSeP z1B||Y2e``@PtXwhmvtJ|XWS+D*O6p*T-x8yA5zb>2TJC7*mMVgTr13QC`@3p0p?<+ zvy_+t+sTeGX@ciA`)|@$@x*DxdZ|t@+FA7qmbpQ6*kf&#ND;ddI%5lG^?%7u#KfvnAe-%^V zjLiRuW!suUj?@I`%F?gSeA#(?{P<^vXB^wVpT`612 z(uS`=0Uytv&+FWc5;lxMZOM$Eoz~z3@6AoVPsfEA&v`Db-*-FEXWA2J?6>Os+iLT% zxdzEZI!kx5Yg-Ox;E|SlLOh46koW2~#ydG<|G}xT%-X4s5R=X&1 zpX0(o#aC|sIM1$kIU1m*k`*u^P8_xoSvR!Y;Kaxf9zp8cQ|Cg)>pv}%aW{7bjpp-J z$p;nnMQyUjkkizA^ICYN42O8B8exN#v&I+$AvX4z2mD1G(%@UsS#qD*dl>goOQdOP z@Af0wr+BOaHynNyx5$xYQB6sDX$tKBHUl-5tkYLYbT5-wZ~>!t-`Iwjwm&@%;hvn6 zR&458PYyJ<`LQKI<4}>#7ThO4X!Qd%uSc zad)baE*O`$?gRq#eqH27eR|fAbt%liICKWLMijc8 zofW;PQHp+z0n6*1ROkouj4^HCaFLGVOPh9XL0PbrPugAPHR-MwUuK)Addum|)cj=T zaKH8!-CGxB7u($c3!$Pg3gZLCDxetr1`&S}h`Ws$1;C7co6Fk;`?Q_eh?*EltppK* z9l4CTbItsGtvnC~Y(P9Jv?HVV@taqmlK~TwTO^TLW=g|{-yale9fRrWxD%-VcIGPD z62tlh#K$o|qD&%Qa|!!PO z24xWHluSqcHqnf^wh=8c2*kq%0{wfca#4v+TYm@^1LlTK9A!5DHCL^fn7Pf0Q9XSR zzK+80OJ{z2R6XrYZ~G1TJ?}$oKU&bc^XN-Y{xlG?WYB~F?OmXWljK3~Saq6kS; z-RSK;3^8~r>nsLR9X+#?$&lhul`k8M$`b~~D<4`Xx*Of%dlo>hmo7{yXV#1$U^O8p z90Ty4Kbo`9ahHvUCAx?SRdzc&x{GIys3h;J?7Pqtk+YE55^E#qy6_2eltRxf^aYO* zI&81!VU&=h{*nm$X{#mec>P=zA$P?wXR(o|`jK{NE#(dcJcH8qQTxUG$!5_fz|2gED9E70y4pg})A?yg|yN7*?w>Qu;? z(I}OVrc=*v3;PjmZP&H39y?VqNdtIOO$8{CImhiRt!40|3jQ7vwW+26-=2yZwaQJC zpiq10C3p#~gCfrUVRgPiA7d!E0$EM!iasN@lwJFpvaQBjBN*+C$a~<ZXaS0nRoXDk@_hBoLfrpqM`bgOP7-KP}3qR50}vfeW2RpnYsYlUoUzCm~l zN4OS=@V(EW)iw7T@n6(8EzTa{DWOpq5(Ojp((CCEYV zJV+sfF-JZK?+y{vE{Vfhhhsa-&Vz0V^FHDnrsP`>=!hT~;v(<@h}@F~pO*(rW>}S( z#&_hc|79QBh{+U$m-|kB$z0lQ4)5b2wpT?dsbXx@P%Li>CevQsr!dZ-{jJ`~1etxM zT*`o>u;uQY&MW$)f!^?6S#ig0@H}pxv_#iTrOqE{f0-d!)xPAydUC|x?Qb}kcPRhr z*XV1K&1KJ`+n?eHAW5&z0{1m4j4j^Pz>}UG(|BSCu+qeAa}ya?W$Z`%V&cqdhLOU&C+87^yO*P6eY?Mfj@=oVf?I3?->j?dq)ToEeq^e`SskxM>W zT7@Pmg@4Z5BPts@p0Qs`s^dCMK+GRI#uraUe}{~fxPG>2qBQ{12#}TQ*gzdNJCN=D z=myL68W#hzna@|8jz_D*r=*&@zZ)dG)!mS7?WiclA&HLzi2H-b)3am0W-jxJHPi8* zr^P6Okty7O>Hfnzde+mSu0F_~Rh7xJ_tlgA38f(g0;6yT9v@NePu1F9D#Ud}a}$0* zJMPIXmHh1XVb{XDiuOhFLl2n{@Msx&sq+AGc2;}^dBmLzz3lIL<>8LomyiHst&5zz zOC#+@HmbQcd+Dwbuh!|&HXfsH7dJDG&%maAOWP2&mqT1N{%OfG_?4 delta 25571 zcmY(pQ*@wB8!Vb+VmlMtwmq?J+cw_Vb|&`3#)K2wwrxAv-@n&c>zvcQs;~O0FS_cf zs{AsDtqE8JMVTMq=pfMl?K)-GL1-%dc!@n9RzSj~q3VX{{L1(^vJh(_Fr;IU9AQi)DM75oex6Q4=@(j?64_ zGgm*%-XANgi9SwUxnQA)zqZcCxzVUUh;D0VBnM0J+Lg%e7drjLqTj=ffNNVO9Hg+a zCjSJH0X8V^K>P1>e`uaPY88+XbwVXA%57qj2FcNxStvU8$DKWP zF3?zveMpo1mPK(eo6hB@^>HOvfW;L zQ4NY#v&5%?&k!d)QjaNWWsyF$deD`r)C9?1dtu7T=DQf21jK)=3dqJ92YN%6U z`9O6SRuD2b|BbiY!I#1)SYlFRnI=k(j7UqcFfA6hYbn*b1#zHgL;cobGJ4w92Gk4% z_H=@J#mGB!=z7_KpD^ho*IHq+7@`(PM+gr6fx0!>&=j(#TZ7 zV_Z^`K)5siNhA(A7Z{PC8`P1(fE0+>f2i2UZScDG|02WtxRXHn=wKRSRAT(lh@@>8 z7nEH!3yQ)=5ldPSu0SBk|1O$F526iMPU*M$3dFrp_(gLBynY1H#!|vu2MI!LLtJlN z1u766+N7Xi9~Xyj@+HA-Fzrjt!QU}>67qq~cERZGoJnA%nZ4D!owSCk<`L?73^h+U z4Qk(+Fpu;Ib*x{9d;FLl&1b#b!rO&8?O|k0jWDtgRd#IJ2nV7rG{s|-A<-cCkDtv+ zBB8>jd(B1xD!RJ^S?LGbt3EQwTF8 dX4VJA8eMj7@(Hqj;ym0%2*#kWstXr*~Zw z!}ZqKBv?*crH5+Qs_OC;r4u6~L~CyS{s(Usow!4)Vh6JthfmO}!ZtduB^cX&s@;XO zlDQi{B9it!KiS_S4SFrGiXMnWZ0<&*s4Ey~FlMj-yV+*9-4>ILZdvJ%X#O;!C>IDL z_g%V+xWK`TYp~J8L@LuCnU)zQEIluT?mF|x5h6jU zzefcF>pc4g&hX;EPXZ_Ny1szxh&oG9A3BqClHQ*n*Rrf=wuVrjGlEy)y%~uAbnHq4 zb}K?2Mo|1)uXRdcN3Ewh?h&3?q6us9)HLA*=2lC{Xg1r)@1ffD9pFg53ZV1)$Tz=k z?lgXBnb~)EUXjb%;Pz#p-@`|T-L2i=`eqves}GyGwKH$zR7n_E9Ip3{=NoVNG*jak zVX&MO$rP3oh-p+)duDEbcAX5nO1XI0>GA5dX1rPCl>Bf5Q0J+{4t|En>?>3CwT1dW z55Yk8$hzNbRtk3#fO8xWv1SIDp8C3#oKpP7)oZIRk|M5tgRpV2+dS(2E=GP>_9x{B zIFEb9Ys(bVNS50+up9V1jvh<9W`f_i%Z8U)N{pIXw$O~D)8_A#C!msy&9)Omy8l)h zB`^6KmHV*ko3G@h8eQtQ^b%H3%M8X=lhJW2gr36D2+!*h!3;up&pPcJ%Wgvay}N1G zR5eGqv&lRZ1B5C{XWrZ*ddazj!;_Yyo1>NNM-0B1<7}q zR7h~enfSsdmM;3JY9;M=R(QXr!508O_)o%6xd}=-g$aJA#;fhKd;4A$w49OhHh0y< zv;Bd-_{6D11*H5>mG!G04-d}q_8~(b_vtSH{he0US0oAz%3;rLEefJHNEic{pQ@p^ z4!pRODKT*X-WI|H*(Wz&S}wa&IXNOwFfbfqHW49lyskk`0*^WxY?b9`it?$O=y=?j z$Ns%PZ`&azLqpEuM6M>6?vHIi@{Vu_Gh~Eyz-q4#ul%rEXi1eAr*3*MRcTtunr<7d zJuj^jy_}<>>ojOGYIb>~U4{dY3kMd+WFD|-67TUf?zN9`e0a-7K|LLueYaW>`pO^& zJ7c>e+|$D@L@_36=urF*T)m7jw#bm*9@r4QLipTqvV=nn9)q_mx;O4^;WRs*^84$U zp(5c_*$(Azw1buL7H36g-n4HY?B?%&v*zzb{6`Fb&3<2wt@A%1DV&c`hV|c z^hp+<^k?;5LkY-7giZYQGI>!Ll{Yx_=!Dx;x~cSb(bTjBLu6u$oE?pQWZR=*>oAE6 zR+T)^pO!$l&=p*?onpvf@oOVs>=Gi=uDARNW!N9xE5|M`HOVC}M3o}@ZC7Em%d|q7 zz%94z9E%K;%8m1~sFr}{mNl`h(JVC+fig=cdavHU{N|2*RmU`Dh@KpNmSBT78R?^0 zc4Ukc)-J#8^Npwo^d&Z)Mgl8o+pPIioC68*KRIW@-1&JqTFUl|kXdSuMAmsp_DYIw zGR}g?!y?4E9}a1)Kyq5J0|t}CIIs0Gq3Bc5CDdv84*-^zgwf~Ar6>`VZqeW2wBZ+^g(g zfS3}LN~W_da>O)Yw*2o}X`8bYSY$Md!K0tZT+6Q7lq7wA&c^>ldJWyA3cZ{>S<7R$ zAZ#%4O%Y~Rwc>%B;Z6xT^3{;YU}trK4Qnm+lJWD$5};&-!|R;b>8ei0fd1mLn|EFO zm}_>iv7=doVG%W{CTZL}iQjN#s61}MJ3(6dXg$naKa7)EzAnrmiVpdHp+4{#p2X9e z=L;A7hF4Jr3c8$i27Cw_1jGs-1myqKK&SGc7Rk)Wd?-hl^B-nvPgxe~lK+X? z;3lpcpF{~KPPOo8xk}NLr$6>wQ%N_F%`=`>_+tx_p?I}(5?p)z`EXvc1&PhQfA?f@ z6OZ#+C_)mo03nD!>LtOff%OExC;FA)0xDqeR~S6c6B%L_04v_>(<5rj9p0B@$1Pvl zO=WGvm$N7u^{n)4fhUtx0Jnia68_nT9~41K^l7ie{6?fCZRass62x`K+V*I2xCWX%=eu!*6Gq8kmfkC z$c5M+*`{3$ES6@~%8*md#m~6QR{5cwWuOaA?^VywT*~R0r`7z!>HkTAt6mf+EPL4c zdq72l-iC!)xkm*2t*Nrca2#;BF`q0bGJ)>UyC>r{KiCs zWyDZWF~^`cZu|qva|hm&!60`F>3ID*_kNscyStVz08KD<@b`Fo%!AvpFRju?-ICkq zYW&DdqjphdyRv}eE+_6WPpP?yq6ou$s6VOZUkZ2`Z~eww%chcuf^WL~q4MtBz3Wlv zyP_D(nPTx|-Vx#;i5cOq9JK(HQ-lRiMlL_y=F`to39lSo1GUC&AM5-`efc2K(rb z5}9*@6 z2mG+?`*hSkY+z}I0gs1lWLOq2VxS#I2f`JcKq7vE-5lo-6vyB9kX$eeQj8k!6r(k` z&2;b2jCSWe6^AqUyGmkLS`1^SN51$yX=sMG+$9zaE{Q;t!#z}3lkGa5^r23MO0UI#+|vDs5nZUQ1KEw{F!$AU?;T-gdmg?ai1F@~Z5 zafYZ+@*m@ZW4B=c8XJBvsOZ`h_N@aOAk;~#xiWkfzLtR3m2Xec%~j0R6;G^utjML| z%^77NiROOKks3X`@X1)IV%SFn$Mk`x>0vp06VJg9kKm*D$7SnKCH~b~gU%O>HgDjE z(U&Q&Jy{~?x?1qM0)z0Y{}NR%u`dWRtsFp6aO6TU|d~UP|nJ| z;uyE^Vd-5#g7?2^-G83$m;Z1EX_&SV$Z0;cW~rAON{oB1_@Bq)V1KbYj5UexNeiAl zZ!k`GfRAc24l}i=#MGyldE+Brv{~iaoGoH&r%3o#-1W>|x5GTG=PCW{yUa7MNJ6p> z0eFKh(8VuTw@HYDD#lGzCxwks_bZYD`#D1eyaUp?a-5{5rDEziv|1txP`R{;4RB|c zDL)T<=p&w_7M3M-MBD!C@2155IqLk?(vf(BkdykwRN@+wL0xZtl5s37c>({^KMeD> z)J;~V8ZoE*S;p858^Jf^DUW|XMbhy*?GlD}{8m^HsZ=-KIN4hoe-NDg)Y5Lt2FX*G5TgXee3Az7=5zeE0 zyw9&{;CS8urqLnm8zsXLMc7@9Sg-LCG-wu~9U zRk+-q?+UoFkE)Bn52}@dLL%V8?kSzuTzH52MdmEKG#3N*7AqWY9FoeqI*2_ zjRT- zIvDi-%SHdAtN+2ZUB!_>cA*7(-MzsCSHX6@<#k{v&W?BW_J2pc-MakIr+J0>7hrAf zR((~YUAZLu-0O$GA>FWp{F8|3o1PZQ9zWrmTv1q3=vN>j=2Dvd)KJZm5R|wC7AB{H zC$eJ1H}!X3Ryz&}v}>eth1n?poO&ghdKKFtZS4GdUHb7Y9!4-pMCX}Z&2OStC3A(= zJgBh2#2t$&pKZT8>z-O#EeV`;6{J}a85r`spU2Zm#+@zpin;EqeVumNLZN0o-|UW_ zQJ@?*YlhHS!-${*8wycsKaOE;g-FtN!DtLu7~m7HBf+?#)H?<973R_aPH&>YK!f_u z^syyzDhDmLE3MPjAR&elXd}2tx)@fWpXkEkcZc~Cck+dFCfCgRsNiiDR$abjK7zr1 zrb;jac}$kB-Zcjo&PbO{yBC@YMqZp>I;E%Q*7l=`5`l|eRUt=>M^-<*))&>N3)j$>GH3Q_N$jR z^!~OjN@Y}yqGJD?;^DqS$`<-mr9zyD7xH8)b5Mns*7I+tD$2dwp?+nm)sFOKmccgTP#A8HB3UNtCy<3f7dDm$EVQkl*t%?6c40U45{PDB&!fGW z-Q<(%5{l=Pxp8Ucw>o+)jGmZw4}}LpI>D zJ-&#zsKpKNu2MF${dx^0d*Mo9z0}g>Jv~|$7*$0c6^s0D7(92!|AUXU-iVf*sW3GV zX|=36x~I}?1MW)dM6Tk%AvY22E@mP#vv+<&bRuHh#a3H5`WcKqGQ#_{ZZk@!U0@vB z&Xf*AFQT(U+lTj+rR=3?I)u5SRrCimFvLvKWSt%82J@IPEQ-_(vH5rHKgOr*>5t>) z4I7~>mCDEL!$T6AKY|cPK&M0!F*b%?OVl2yCza8Wk+U7?;&JNjeAfvfVYAj-={D_{ z>*`t5&>qx=1juw-%b*80%=_Lus0yzCyDrYNHhshq{B2pxNv?VS^`!xED>JXU9phv5 zc0vHOl$e@M4sczZX?P!5#s3wPTKRp|*fzAAvV6qU8k!<2^IM4DM(J;+P>YvE&L*N( z>lk?q(xo+-ptBSr4{HKPULn}qJ)vpLA*^z$GscQ&#aNz~ahk3Lq~6+b^mz)Jw&8nh zu3H!-wtINJ2*X+OHZ9u(qh`+{95I~4>47OgkLlPk3p#JS1hMYww(7s9r^IC-Cn~_5 z^#C>&=omiQMbUD{|H2^^2fJXZzT7V-$|}E^DPEn{1Fte1m+V?orco;i&qMh2LwAq)X7inq0WvZ~o2OFCy;}oyQ%B_+?zq#a;a5fqC2>Zj4 zQDNmScd_2On18gLJD>Gdlf1TEUz&>NoJSLV525BO+Xz;puS*Kn`#E*&GBXMwjZ|5% z8=O8ZXs0eUGdFzi%$u6+R5j*D=f^E5H%w8mc`MNv4z9A_+r3(ApZeHrIUm2$^5m|E zQMSfcqq88DRDO=8BZY}`)TsNFg#Zg~`uivNuhVaJvOd|GZ@EP1FBLL16$={)4M^tv zuKMO+_?b1~MT`?$TdS{cO8F+BOe(E9>N}mw?lYb%w!q&YsFOJO9Av0+I6R~_)p0{; z5m)u`(kydw{69J0oOD{1$uzh8;5Mh*?a+qvXc~3sot0>wCpL@9`58A!f6uZk&?S&d zQz<1dtqbZn)6?BLP5F1$N}&AO+M*;(28JhPln}GyW3WiDFV^8A<2C{4AN&1*_A6|q z;O`H7|G7^i&nGKYu^O?5kZ#kIrO@-<9hUrj-MZ3&LSNO))tdAI8-zB z1k6~W{_n#EdehAckt?K7mNCUvsl{*iV5)!a1gg~-1S3x0h~8SohgVomW9WYXfy;b@$4-!)wzN#atf;?g1oG7;~oDk-kl=|Hq3p3 zS&AMD6@safA0JJEwTCu*nW$a9tnh}^m~G{I9KdGv}?jFb=G zBSQh3xe;6=&pEu5v*|DGpc1V(a8a4^Cw%CH282tAtkoAU2?@nbNkaq9KL*)_%IV#C zKcG1LE<||YK~)w2)YlAGSf}IVbGpV?%6kGruG_X>R(?O3$2@TU;{1w{u||dVFwZmH zi*PAmrVca0=cbb^i0Ch?5Z$0)^Z}v9N&417ndlIhQu5}0@;F33T0?O;3a$l!GidJ!3BVtik*kBcDT$}~$~7Tj88Y*q z3ADtUBi@hOz!`(Fwzx#4YJ$4d3xR&)rxDK3h%7W?F`8*3W>RnnK zH?-J^T(vFbWxC=xaH6EwGmrSI76O^?!cRqYC9goCgaVG6^1RcZ#sx0m*|2UH75I4c zOX@c6)W{bgEQa}_Ka&*K+YVA4f0{0BZK!Fs1JXjkm=rfiZg(~Ml|7n?iSeVhMLuhK z8#}Aqr9L%>;Ws3&#pR2x2%$Gzz7OJ&Qh z3gzh|v}C{`qIHz4g6s;=Q6y2blq|wd9DRhhDtiJ;7N`m+^|h4Q1xNwcZ0yF|SLn*j zq~SVfg#)}xsBr@uO@WT)D+FOBtwfV&Sj6#orBM7GR6OBPm*LR&xYQBV{TN`CFGY7z z+N~*tExTADAc6Ps^v-{{6My-2Ixme~_6y@S-$!mww$V!%8M!h!mRkU=W^e2{M4oY6 zvMc~pYm|R_dWwEox}|gTuPE$_c#mB|@UM!x9g~l6W*6$0YH^NOCEQC!|Ko(5%J?SO z#IQ$kukD>H;JwH-DMPdOw&sd0k);}OKQEA-)lW)h5_fvuu- z0YK^;Kbo3kdH?fFr&ZEGrgOzWvs_Z`?YZ{+w54SmdQQlf{aSKT)@gZCZ>BgU#tC5Z z4w;=i@OHCd<;R4U&0FML*V$Lq=mD=b$7gpl;seLDsrE|10;{!CkIq79o8sLCH=^V0saUYT`Jn%gxOit5#j zb8HFhuH?L??-E{pEbkE=0T8i0`~e_|c8UBfypK8X7*aLuK{o>ZRvzk8L^1bgcXnk_ zm?7W&k-P7|B9sRoDF%?m&Jr3@&g!9aRtjiuySO@F4gSftvVmUA+6H}WEgfVChucvX zjHV~#)X`BvV5h6}(uoxu=-+lcd4+iw{anpmrKjj~6PNCnvu&B>Arru&u>dM@U%@7Q zZtsw?`JZzBk$U|?W4<-=onP7!inP;5z7A@|d9!UkfU&0K3OnKY{JFG#U7LO(d`GlP z0h4^Z*T}K7~)Jrv#ejeD=qSYYQ_!K)Q2>QxYlS)~aLr>Em!sdN7ITEgFHdWKF=mHYa*fV{X4=~5 zcia8Efx7=ls$X%w%Trf7LBB%Y%ljvUVzWx4@t6&>y6D+(0cf1a!4sTjW*bprTj2JW{HcF`?RIlNh0`IhNe zA)Vmw9G84)!Ks~P`p#hTxe*?^}FWGZ)U2?!c5B$mSegpZ7_S#5*5KbT~#T* z9PCsLk`3obC`Ul)dc8yGbS@|0t#GEsJbvXZ3*s50wrtGbaebhT_4gn<*TTM9qjWV} z%1Sz`F&1TZ9luUS`$p!okgE>MjFezvs9+B70ChO(hG+TgJ`n71U*aPY|Bd*AP&tU3 zGx{nR6m*v2!$9hkV;`U-zxbAvTG8oSo7xZ?8y{F*n*b746DAW*g3C%erMNp5=}68&QjKYFH%<9vA$Vzm(Bl*Flf1WfB&r4K<4~{ zf6+JnG}xZ*|Fd(9e>a5d9XK#t*VIg+mN!lC$-8tMo%noK`n5}uC-nAsOYxnOTdp$8 z2B3M8ICiP4`?lO%m8I(1<}()hiK{0TNdFOQ1Yr})G7UR7zgnN}2yrS?d5smo@W}uZDw2zXzmp>;#>v>6f2R*&Ef5pUG@H-SbU4YQ(z8CkQK4KD5q`>qstO!9 zfD2pR=<6;-=}B4WbA56mS8h+<{Wqy$ZbJ=QFuz^Wi!lUop@w1j;` z{3E;YW4~SI>U=MdKU3;lL(BUEVq@{J!`FJ;7!!u(@4QdkyNNs;;m~mGx)0RsVXS&* zm*M*-RnIe&E1_4K|F#5fhDY%?By<}64zl^MDBpxMtUaoWcWWQYcCwRXw9 zlkqt&5J=cCc`M009{rKud3yh?xj|BSsizQXeT3;4So~M&tYa}$32r1bA&be&^^0ari&vA0tt zw;~no6gu+It3U1joeb)IfC^D}VF~Kb$lRdX`SJ>;ch!QF7TLz!6W2c#77O{fICYU6 z{PYXiWLp^A+HM9X*XlAiuVDjEhV;HSVCOO-?A17HX?ZLG#<=$bQV>pwZA?wDD$Eque| z(OE5JoSx_U1T1bnKqKVJF%*^Up9zlvkzl7s0f?s*f=6VSiRZfko%3pki6&`<4y{VU zDhFll#}q-o=hwa{>qG8x1(j5Q`KI5GxW#NK7wsoRRKCLfYG${+gvTJ93Q8?n4T9+ZOX*>@C578QE)ki~MzyfB% z1=@$%>gmBp+n8n-uJ{fgVq!1HF%NaF+HK$L)9HcXW1ICkcAsDlUCGVE4>0i+q}<~g zIR+DLf){%HH)!i^ma)O(6P4+}TcOUUk>4l)l8}7;v&xv>v%}&rp&Z&>_}7-& zv2HFXVezo(dG_X(A6{S{L|^Psdvp)Y!(E-?uAb(FfiI{(?>i}2YD~zJb81n2b8Flb z3+{|^a$gs-dnb_xiw~2whgN>7W$(CYt9QJubq+P745gOoe2Zxz_2Rw1b;S;k@gX+d z_25wfZn*~k<*v-IVx%g|rKp~hC0uo(-LqtTu=e4^ZGY<44kCid*J*W>+g5&>p1^;a zrt@gBVo%2o_SoK^Dk5D#x%{Nz3fU0jokrZ&?4X3*CBj=1mqjrjrjS?en`~sJXsg(_Vu;0l@ka*RD;h}mJ!4t$$X@+1hsT!0 zKZVZwaqNKJcRotJFL+dRo_6IKT#g6(F?WxpfoZIqWeClMr6qA=*Mb2`#rNe{I(dSNJ6A!Gs=@E zc5nf!bBvHso9~aKnsxtMT^ZQwCb*kxS1PUG)Z)fVP%0iwu(5hdiR@4Lj?~iGrPC^& zGoQTJ0o~t@=(O_!id*YM;LdyfUm|P>w35=bj;#Or`UPd>uLdLpu6qB zm$J%s?GglV&Y_7;&vH@r^Be`lswqf`TuFRDk>rCd;&;%u&RWL%f!GhepXKke-WXO* zOG*--9NNpwtbUMUb*9R;{8YAvA&hUp0A^qgnSabz{gG=#h4R$+ISQb2l>O)b}qvTnlU`-s=T)~w;MmgUa7E2L#6R(q2TnBhEq_pw&9RX zV+&`z(04;Pn(ZCeG!p5XEMY2j3_7u`rA2pAqrdhQ?fN`ea56u=g?G3tnE$WfA)&RRxM-fuFML)cYqia#4WU6lWC-;n&*Qj2a>QkaO6}7 zrVyR0bhWjEq=|(;nO?XHXo%Toj+}EDZi*Z%YJBkBU{*4RC^KC$9Jd~5 zXYvto+vgQ{teEjyVJAqqax3P7cwCC6M9NIZ_#;;mCqy4>6Js_3rw_iK!kWPRSTq41 z=q}5Pz*lH$rPtBpZcibls%l2G{<445%(_97oTEK}OowfWp{KPj8z)Pk(Ff)gy)9`|6E!BY9dr?=2A3PJ}wh!y|@0lTLE;;$V+-;h;?{;%@Q zwsJj$c>6WS1wFE{xKx1?(e9VQAPbwCALB1N8Y8y$GC`Wq7b%Dks<7j@BH&I$uHdT7 zBh7U;hlt%oKD6+~9ZPVgh!-1s`Hvr!Ja+St^}!cKlQ>R(cXzm|*r-LkgSHE?wUK7S zN)op?o8p456Z=UmueQ1;@AQ4oqA#5F$1@3N5_B2*n!XL`wC|_^oORva zxPw%SeKjA+M@jg#Ig9or>Ir`-mJ#&PYDWe&^vaB8@Ar!4Cdu!zs>+ zQL*vgXT+O)ZriP0N~NK$Hb_Y9gI@*N2RVb|H(|ige^s|9@2;p^e6r?v|Kv5m{fI5; z_KaiiJ6Qm&bFxkKpFgG%-r50ko|`<=l2?TM0W+C{JSR<_F7gphk>haud`Z@8_R){H zKw5@A&o0WGgDA+dqwNlmJvLe|1&wND0*h~+$}XhjPh-Cim!}T1Z9k}v3-hsnVQjPH z)J~w@q$FQAQcYmmnIsP8h({5NbbX51Zq783nHSG_h24DP!HSSeXu+GY^QXUca`f`j zzcB;PbbGfLnxc$;_~x7nF9{kf@V{)xg#~}4DC4={nG{@!M>sBdV9=D2sed9o!cmH5 z_2Q0FXgETrfYDQZ*%zPCkkCy{6sbZhR?hJ_9o$1C}=9IcqErWjt^(hEDG4g#Wh9~;8{S$Ajk?!7>6 z9JJXvBsDXKeDA>}hbNv6j7JhsdcObNVskq`Gk=i;YO8bh`J;181Wp8#Z&A#$nRtpM zM0_UOMMn_X^ANfFsIC}OqT`S!gy>1U-r{zwF_`b!v*CAxmVE|X)ubi%mDgQ3>N2L+ zbPf=MZ(7v&Pz~~QSHoAf$wzNaj|}{x$b-ZmQJ?OcpI78E-xd=OnW-Ygi-bljjV^Dc zXlZNa@EF|UVkGUbJoFO9Ja~m-RfCFQGb)O)i*-ITgDM0ULrQVHH)xqZfja0-7JPr` zgh~S~o9;NY94M}0U& zn)#U@n?lkj&D>q~PCG?lWD2BXRWw6;Ciz&ih_0zRgKw1r|e{&Fc}G5)lHe~bAc;%j-|+j1(BIm+AoL#HsM^1;@>BUAy@ zO~Xh&`muuj$fKdzi7K!eNF225CfP+>HeVj9;!L28H|>uU%wLuZNlyzWk=fcn#j5BF zM6nJ)%!H=~`ZlMT%O-%|dizDrBnhadMscD|bBz$Lg84b8I667K_khcXbs7;vw<~3* zfq>mqtM@OEyj&zoZ{KNcCQ;`N*W=dZEvA#~MRMG&^6$tN5b3eSiCvSPJtsHFmm!pz z;6wPspFEylc3i-jCh=P$4{ELHO!2X1Xw39en~?9vR2^ME7Kyd~_^^oHda9cDM}WWbAc zvQE15qM%k7IwH#(y*`UtnvcbjI?OT)DPM_eG`}UgXu%8RM#?d}JXJ~g80G*c^o3s- zPneu#a#F4r55z<4tba70Dn#sP;3RKn=L6OGFK$2WM@?!5pg5OpyR+iPEv?f_-WTq! zus?R++6ElpVwKpd{{%&E&s_Wz_>@LW$Z{^lW~A={xf5=}KFO9E=6}2M<-reR$Xonq z7%rYo8;-H9V_iyNGaY1unoJ7HX?Ke(gzLQJROiP4l{JHgP91~IAzhmZa2)C%Y2PIx4^N>Ym8R$gi!gV>Nk5E zoCqW@7L(!)JyL0_%N&D73S4t12nONz#na_D{vOF$G@nOqB>Y^p+;3Mfx7|_80&Nb4 ziz3kw24ahir%g<_dT1&%9l_E)$O2$oHt?C7hO8tE z$nK-W4a0;K*rOUCquJdWWsw(gJo3_J0`*b<2K<|0d#WzJwsbWFG*!uq!pQj%a=#e6 zR(1YFJ-2%#VF%8mGb-49s96908Vi}mbSVt!DY<&SZFoQuVY0NZOnO0s7Q?kh|LKv)@yWb(+zu*#6*F?iSGyLw!rfyazj5 z+c;?!!HKKEg-~j-w8Zy@(C3|5J|o&){gN2^E@>&b>d>)#Sbt9)At^yjj1F5awWspJ+3vLWQ(Ad?M&Iey+tbw`Po4 znCc?z?|@wPv`)gDKETPJ=b z4qpG(V;DV+>(R}-*Xt9`RYe)5R5_MQlC&!&XrkjjVM?2lUYh?*+3OKRu=OnB&@ipc z+@%q%I6jV=c`M;fCedsxoS)7^DXt<`%SI`zIg@3!7Tg#iO9=R7`1)_J26)Uy_XzQa zO!uo(LcI1G0Y3*L8xM|zzkwMQlw>s9A*KLE;$B5C2%>>)_-349lK&aa)a zhM<^Rt1Gp6F)KtPMnaJ*#AVA6B>Ck#)Y4k@kF^60 z*k)b{?nX2)dY%)slg6dagPOJY2v5U0^qE7PyfmRKmGURHEk`+qJGmm{75#Foy+Dj zdY5qQ6lXiOeyG-SP6uDzrvSx9x4#1lB8~!Pd_Y2Hxv1}e_x)!hHd0y-+Qnni{KBSo zW!%!E@<8Onfmtg%Af5GyU5APk{^`Ek@2j)!{*Y8K^X~MHneL_a-U8}sEf)8gySBc;xj2yy0fG1@!uEU!e8 zA$#-XQ_^?a!4DrX_8K#)TFK2{m`JY;QFL3u&wv_wM}Q6)hz;+NX}^*t$_wmG`S<42 zO6~K9$AwLYo-OHDN{3GfD@tVmC6l%KK_8sk^-rO4JEt#Sr?R#_U2qPS9Oisj4_=stP zBFJiiJ}3X~@qG?L702-cFIIj2jDR?Y>Y>T&8PjlifEQ6WbJ)w z6d^RQYO4d;>-qmG{Hn+xuw2H}|B{I@FzWHD9^$BHxwYf?czrq{{a5665o!sC;4VHM zQ8<-O1}gC~QmG&%1F)L{&c_G|oZl|S5-qgEq3$eeVmwD}aepx;CU?s1>1MbUvvk(~ zQGT;<)A&?(g=K#<@E|;SqSlO9E0-C&*>+hG{JrM9d=KqALrJg=RYhrq9oT)Y@>-oz z4g8^7|JFyPKk8mDe!rQT2`(tAr(h#{epz=x1wNAN_C2zOu90^_?Oun1tGNw&i30gw z+0W7^*zXzWUQ#X34;oE4+N|^1f?oQlHHcs2Uo}O`EI7CscX(c74OA#%%Lr#+nm55x zQ$g{ZY1t?e&*tmrKm`*voc>^~Y-#qSD?|EGq0)7cM7ST%S^hPNF7b7u#tz%x2|Obq z0l5FNibs#ZG;&VM+g`{CDlXC)=c{r3{J3+gNRLMtf@S0y%L-XBq=^U%^n%?&kpyF@ zToW90xS|;yqCEl zw=65%F279$OkH3ig-?R41eTrXc1GUhPV-XUr#c9S2x$;ix9reEQ1B&;CWI0goa- zn*NLR!q5d1G87>)WK-g%f5pFK2qNy+y+E3{;w26jpUR)SNZxk6+LyL?5s-5ao=a23VlGm(ON<|1S`}zLMq4w(uZwe zt19d@5&%I2QW!4ETY90XZn^&g^0_#ILy_rlT=b{%N*wnFRlo4JnW{ zjBo5?4~hZ|`^6f4)+rPw+KBgPLmh5PbRrz|2`z)u6ZH3W10Pr=xHE9(R z0(gZ2y(1-`3iAjY?V31G=E8l^XKwCsGTXn3RDxM8|NbUh)v=D3K1^2V6k0Nl#uv=M zlQ@T=^5c@vTHEi1F)%{eXuO?Lsbb!`qUk^4zM%1VR8ar;bu6_lgGM;DdA zKA>C-Z6+&RaK-zlSW9y+Vflvd{$WvLrS~6y#Bq*8e9xb~$!*C%S2pR6HBMU22fs#F0AC2E#8*(nA|xBa7JCz z*H3|pN!)_bi1!;KP*g8goT+rROr|(lwy@vCVeB8+u}7D zR}W0Y{ntky%tsBip-1r>-;)KhOg@_;!L=5V^@h071^j}mT*^W*CWDVP1N3Rw#b0W; zHu&uis_Z^Vrm<(Q!+&lX?cq<^4EN}iWXy&Pi~p(Z1vZO9>{-sUPbBA*k|N62jYv>$ z+ptQ%&$u7_iNF&l(nTX_Ed8uKwDc+|5&Fw#hO;{2YPO3pl^|WLnQ?LyE(!0Tu-DLn z^^J{9W2)?HahtCc;J4su0Gik2%x;l~NWnTkDuiuno_PXKKPm{uom%~C={5o=4~}*L z5e%YdAkZI1pD|=n+MtB?$v@svjdwY)x5bk`efG;O#Gn6^;2B5_OFhR`VYp)Rd_~qh z_|~(H3CXT174E-5hH5${-D@+_{$#Gd+eFRB%8`;Okr_gBjV|kjskC5&F~B3W4!w7I zvNpu-+`^Kyzc5~ixpjT{Cy+#L?B@*&d=nf3Hol49*x!PTP?bSzyn@=eoSTEP3Lmv< zxaI|TENU44r>=Vp4m9W%1RUFTCZ1Rm+qTV#ZNG6caV9n=wr$(CGqIiQe08gK@7>z1 z{&TvjPgnmw-TfR$mM|oOFR$Cv(#pIxAHabtR~g~%iR=u$IREYTx}IIiW^=DB#QU>L zLLYq#W)c3e;r7`*fQoLR4^=i1snxDi(5kQft=gnH+tVARwR7L7q?Eab+^%H(0;z5+ zm;@QXb`i_D%@dqniY{_)+%}`Uj0rP2>M?!BP5uj$K2~0KOexum-A